From 262da018e2b25c3d972a7a994691def8d6ecce2f Mon Sep 17 00:00:00 2001 From: David Viejo Date: Tue, 4 Aug 2026 16:53:40 +0200 Subject: [PATCH 1/9] feat(cloud): add secure managed telemetry client --- Cargo.lock | 29 ++ Cargo.toml | 2 + crates/temps-cloud-client/Cargo.toml | 24 + crates/temps-cloud-client/src/flusher.rs | 145 ++++++ crates/temps-cloud-client/src/lib.rs | 345 ++++++++++++++ crates/temps-cloud-client/src/link.rs | 428 +++++++++++++++++ crates/temps-cloud-client/src/spool.rs | 247 ++++++++++ crates/temps-cloud-client/src/state.rs | 317 +++++++++++++ crates/temps-cloud-client/src/status.rs | 203 ++++++++ .../tests/client_behaviour_test.rs | 221 +++++++++ .../tests/link_lifecycle_test.rs | 441 ++++++++++++++++++ crates/temps-cloud-protocol/Cargo.toml | 15 + crates/temps-cloud-protocol/src/lib.rs | 168 +++++++ crates/temps-cloud-protocol/src/messages.rs | 269 +++++++++++ 14 files changed, 2854 insertions(+) create mode 100644 crates/temps-cloud-client/Cargo.toml create mode 100644 crates/temps-cloud-client/src/flusher.rs create mode 100644 crates/temps-cloud-client/src/lib.rs create mode 100644 crates/temps-cloud-client/src/link.rs create mode 100644 crates/temps-cloud-client/src/spool.rs create mode 100644 crates/temps-cloud-client/src/state.rs create mode 100644 crates/temps-cloud-client/src/status.rs create mode 100644 crates/temps-cloud-client/tests/client_behaviour_test.rs create mode 100644 crates/temps-cloud-client/tests/link_lifecycle_test.rs create mode 100644 crates/temps-cloud-protocol/Cargo.toml create mode 100644 crates/temps-cloud-protocol/src/lib.rs create mode 100644 crates/temps-cloud-protocol/src/messages.rs diff --git a/Cargo.lock b/Cargo.lock index a9b989f87..4c50f0a15 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10695,6 +10695,35 @@ dependencies = [ "x509-parser", ] +[[package]] +name = "temps-cloud-client" +version = "0.1.0-beta.55" +dependencies = [ + "axum", + "chrono", + "reqwest 0.12.28", + "serde", + "serde_json", + "tempfile", + "temps-cloud-protocol", + "thiserror 2.0.19", + "tokio", + "tracing", + "url", + "uuid", +] + +[[package]] +name = "temps-cloud-protocol" +version = "0.1.0-beta.55" +dependencies = [ + "chrono", + "serde", + "serde_json", + "thiserror 2.0.19", + "uuid", +] + [[package]] name = "temps-config" version = "0.1.0-beta.55" diff --git a/Cargo.toml b/Cargo.toml index b969954c1..94fbfe2ae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,8 @@ members = [ "crates/temps-vm-agent", # Library crates "crates/temps-core", + "crates/temps-cloud-protocol", + "crates/temps-cloud-client", "crates/temps-ai", "crates/temps-ai-chat", "crates/temps-entities", diff --git a/crates/temps-cloud-client/Cargo.toml b/crates/temps-cloud-client/Cargo.toml new file mode 100644 index 000000000..82facbf18 --- /dev/null +++ b/crates/temps-cloud-client/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "temps-cloud-client" +version.workspace = true +edition.workspace = true +license.workspace = true +description = "Optional client that links a self-hosted Temps instance to a managed backend." + +[dependencies] +temps-cloud-protocol = { path = "../temps-cloud-protocol" } + +chrono.workspace = true +reqwest.workspace = true +serde.workspace = true +serde_json.workspace = true +tempfile = "3" +thiserror.workspace = true +tokio.workspace = true +tracing.workspace = true +url.workspace = true +uuid = { workspace = true, features = ["serde"] } + +[dev-dependencies] +axum.workspace = true +tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } diff --git a/crates/temps-cloud-client/src/flusher.rs b/crates/temps-cloud-client/src/flusher.rs new file mode 100644 index 000000000..a09e7b57d --- /dev/null +++ b/crates/temps-cloud-client/src/flusher.rs @@ -0,0 +1,145 @@ +//! The background task that drains the spool. +//! +//! Runs beside the instance's own work, so it is written to be a bad citizen of +//! nothing: bounded interval, exponential backoff on failure, and it never +//! holds a lock across a network call. + +use std::sync::Arc; +use std::time::Duration; + +use crate::link::{CloudLink, FlushOutcome}; + +/// Interval between flushes when everything is healthy. +pub const BASE_INTERVAL: Duration = Duration::from_secs(15); + +/// Ceiling for backoff. A backend that has been down for an hour should be +/// polled every few minutes, not every fifteen seconds — but it must still be +/// polled, or recovery would need a restart to notice. +pub const MAX_INTERVAL: Duration = Duration::from_secs(300); + +/// Next interval after an outcome. +/// +/// Separated from the loop so the policy is testable without waiting on real +/// time — a sleeping test is a slow test and a flaky one. +pub fn next_interval(current: Duration, outcome: &FlushOutcome) -> Duration { + match outcome { + // Progress, or nothing to do: return to the base rate immediately. + // Backing off after a success would leave a recovered backend receiving + // telemetry minutes late for no reason. + FlushOutcome::Shipped { .. } | FlushOutcome::Idle => BASE_INTERVAL, + + // Not linked: there is nothing to poll for. Slow all the way down, but + // keep ticking so linking later is noticed without a restart. + FlushOutcome::NotLinked => MAX_INTERVAL, + + // Transient failure: back off, capped. + FlushOutcome::Retained { .. } => (current * 2).min(MAX_INTERVAL), + + // Permanent refusal. Backing off does not help — only the operator can + // fix it — so poll at the base rate to pick up their fix promptly. + FlushOutcome::Blocked { .. } => BASE_INTERVAL, + } +} + +/// Run until cancelled. Spawn this once at instance startup. +pub async fn run(link: Arc, mut cancel: tokio::sync::watch::Receiver) { + let mut interval = BASE_INTERVAL; + + loop { + tokio::select! { + _ = tokio::time::sleep(interval) => {} + _ = cancel.changed() => { + if *cancel.borrow() { + // One last attempt on the way out, bounded: a clean + // shutdown should not lose a spool we could have delivered, + // but it also must not hang the process. + let _ = tokio::time::timeout(Duration::from_secs(5), link.flush()).await; + tracing::info!("cloud mirror stopped"); + return; + } + } + } + + let outcome = link.flush().await; + interval = next_interval(interval, &outcome); + + match &outcome { + FlushOutcome::Shipped { spans } => { + tracing::debug!(spans, "mirrored telemetry"); + } + FlushOutcome::Retained { spans, reason } => { + tracing::warn!( + spans, + reason, + retry_in_secs = interval.as_secs(), + "buffering" + ); + } + FlushOutcome::Blocked { spans, reason } => { + tracing::error!(spans, reason, "telemetry shipment needs operator action"); + } + FlushOutcome::Idle | FlushOutcome::NotLinked => {} + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn a_transient_failure_backs_off_and_is_capped() { + let mut d = BASE_INTERVAL; + let retained = FlushOutcome::Retained { + spans: 1, + reason: "unreachable".into(), + }; + + d = next_interval(d, &retained); + assert_eq!(d, BASE_INTERVAL * 2); + + for _ in 0..20 { + d = next_interval(d, &retained); + } + assert_eq!(d, MAX_INTERVAL, "backoff must be bounded"); + } + + #[test] + fn success_returns_to_the_base_rate_immediately() { + // Staying backed off after recovery would deliver telemetry minutes + // late for no reason. + assert_eq!( + next_interval(MAX_INTERVAL, &FlushOutcome::Shipped { spans: 10 }), + BASE_INTERVAL + ); + assert_eq!( + next_interval(MAX_INTERVAL, &FlushOutcome::Idle), + BASE_INTERVAL + ); + } + + #[test] + fn a_permanent_refusal_does_not_back_off() { + // Only the operator can fix it, so poll at the base rate to pick up + // their fix promptly rather than making them wait out a backoff. + assert_eq!( + next_interval( + MAX_INTERVAL, + &FlushOutcome::Blocked { + spans: 1, + reason: "re-enroll".into() + } + ), + BASE_INTERVAL + ); + } + + #[test] + fn an_unlinked_instance_still_ticks() { + // Slowly — but it must tick, or linking an account would need a restart + // before anything shipped. + let d = next_interval(BASE_INTERVAL, &FlushOutcome::NotLinked); + assert_eq!(d, MAX_INTERVAL); + assert!(d < Duration::from_secs(3600), "must still poll"); + } +} diff --git a/crates/temps-cloud-client/src/lib.rs b/crates/temps-cloud-client/src/lib.rs new file mode 100644 index 000000000..0edbf766e --- /dev/null +++ b/crates/temps-cloud-client/src/lib.rs @@ -0,0 +1,345 @@ +//! Optional client linking a self-hosted Temps instance to a managed backend. +//! +//! # The rule this crate exists to keep +//! +//! **Local is primary. The managed backend is a mirror.** Nothing here may +//! block, slow, or fail the instance's own work. If the backend is down, +//! unreachable, unpaid or misconfigured, the instance keeps deploying, keeps +//! serving and keeps storing telemetry locally — it simply buffers what it +//! would have mirrored, and says so. +//! +//! Every operation therefore either succeeds, or degrades to a *reported* +//! state. There is no path where the instance is worse off than if it had +//! never connected. +//! +//! # What leaves the machine +//! +//! Only what is in [`temps_cloud_protocol`]: telemetry batches, heartbeats and +//! enrollment. No source, no environment variables, no secrets. An operator can +//! read the protocol crate and know exactly what is sent. + +#![forbid(unsafe_code)] + +pub mod flusher; +pub mod link; +pub mod spool; +pub mod state; +pub mod status; + +pub use link::{CloudLink, FlushOutcome}; +pub use state::EnrollmentState; +pub use status::{LinkStatus, MirrorHealth}; + +use std::time::Duration; + +use temps_cloud_protocol::{EnrollRequest, EnrollResponse, IngestAck, SpanRecord, TelemetryBatch}; +use thiserror::Error; +use uuid::Uuid; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct BackendUrl(url::Url); + +impl BackendUrl { + /// Parse a production managed-backend origin. + /// + /// The value comes from trusted host configuration, never an HTTP request. + /// HTTPS is mandatory and credentials, query strings and fragments are + /// rejected so bearer-token requests cannot be redirected or disguised. + pub fn production(value: &str) -> Result { + Self::parse(value, false) + } + + /// Explicit local-development escape hatch. Only loopback HTTP(S) origins + /// are accepted; this must never become a general insecure-HTTP toggle. + pub fn loopback_development(value: &str) -> Result { + Self::parse(value, true) + } + + fn parse(value: &str, allow_loopback_http: bool) -> Result { + let parsed = url::Url::parse(value).map_err(|e| CloudError::InvalidBackendUrl { + reason: e.to_string(), + })?; + + if !parsed.username().is_empty() + || parsed.password().is_some() + || parsed.query().is_some() + || parsed.fragment().is_some() + { + return Err(CloudError::InvalidBackendUrl { + reason: "credentials, query strings and fragments are not allowed".into(), + }); + } + if parsed.path() != "/" && !parsed.path().is_empty() { + return Err(CloudError::InvalidBackendUrl { + reason: "the backend URL must be an origin without a path".into(), + }); + } + + let loopback = parsed + .host_str() + .is_some_and(|host| host.eq_ignore_ascii_case("localhost")) + || matches!(parsed.host(), Some(url::Host::Ipv4(ip)) if ip.is_loopback()) + || matches!(parsed.host(), Some(url::Host::Ipv6(ip)) if ip.is_loopback()); + + match parsed.scheme() { + "https" => {} + "http" if allow_loopback_http && loopback => {} + "http" => { + return Err(CloudError::InvalidBackendUrl { + reason: "HTTP is allowed only for an explicit loopback development backend" + .into(), + }) + } + other => { + return Err(CloudError::InvalidBackendUrl { + reason: format!("unsupported scheme {other:?}; HTTPS is required"), + }) + } + } + + Ok(Self(parsed)) + } + + fn endpoint(&self, path: &str) -> url::Url { + let mut endpoint = self.0.clone(); + endpoint.set_path(path); + endpoint + } + + pub fn as_str(&self) -> &str { + self.0.as_str() + } +} + +/// How long any single call to the backend may take. +/// +/// Deliberately short. This runs alongside the instance's own work, and a slow +/// backend must never become the instance's latency. +const REQUEST_TIMEOUT: Duration = Duration::from_secs(10); + +#[derive(Debug, Error)] +pub enum CloudError { + #[error("Invalid managed backend URL: {reason}")] + InvalidBackendUrl { reason: String }, + + #[error("Failed to configure the managed-backend HTTP client: {reason}")] + ClientConfiguration { reason: String }, + + #[error("Not linked to an account. Paste an enrollment code to connect one.")] + NotEnrolled, + + #[error("Enrollment was refused: {detail}")] + EnrollmentRefused { detail: String }, + + #[error("Credential rejected by the backend — re-enroll this instance")] + CredentialRejected, + + /// Transient. The caller keeps the batch spooled and tries again. + #[error("Managed backend unreachable ({reason}); {spooled_bytes} bytes buffered locally")] + Unreachable { reason: String, spooled_bytes: u64 }, + + #[error("Backend rejected the payload: {detail}")] + Rejected { detail: String }, + + #[error("Backend acknowledgement did not match submission {submission_id}: {detail}")] + InvalidAcknowledgement { submission_id: Uuid, detail: String }, +} + +impl CloudError { + /// Whether retrying the same payload later could succeed. + /// + /// Drives the spool: retryable failures keep data, permanent ones must not + /// buffer forever behind a problem no amount of waiting will fix. + pub fn is_retryable(&self) -> bool { + matches!( + self, + CloudError::Unreachable { .. } + | CloudError::CredentialRejected + | CloudError::InvalidAcknowledgement { .. } + ) + } +} + +pub struct CloudClient { + http: reqwest::Client, + backend: BackendUrl, +} + +impl CloudClient { + pub fn new(backend: BackendUrl) -> Result { + let http = reqwest::Client::builder() + .timeout(REQUEST_TIMEOUT) + .redirect(reqwest::redirect::Policy::none()) + .build() + .map_err(|e| CloudError::ClientConfiguration { + reason: e.to_string(), + })?; + Ok(Self { http, backend }) + } + + /// Exchange an operator-pasted code for a long-lived instance token. + pub async fn enroll( + &self, + code: &str, + instance_id: Uuid, + agent_version: &str, + ) -> Result { + let res = self + .http + .post(self.backend.endpoint("/v1/enroll")) + .json(&EnrollRequest { + enrollment_code: code.trim().to_uppercase(), + instance_id, + agent_version: agent_version.to_string(), + }) + .send() + .await + .map_err(|e| CloudError::Unreachable { + reason: e.to_string(), + spooled_bytes: 0, + })?; + + if res.status().is_success() { + return res + .json::() + .await + .map_err(|e| CloudError::EnrollmentRefused { + detail: format!("unreadable response: {e}"), + }); + } + + // Surface the backend's own wording — "this code has expired" is far + // more useful to a lone operator than "enrollment failed". + let detail = res + .json::() + .await + .ok() + .and_then(|v| v["detail"].as_str().map(String::from)) + .unwrap_or_else(|| "no detail provided".into()); + Err(CloudError::EnrollmentRefused { detail }) + } + + /// Mirror a batch of spans. Never called on a request path. + pub async fn ship( + &self, + token: &str, + submission_id: Uuid, + spans: Vec, + ) -> Result { + let span_count = spans.len(); + let res = self + .http + .post(self.backend.endpoint("/v1/telemetry")) + .bearer_auth(token) + .json(&TelemetryBatch { + submission_id, + spans, + }) + .send() + .await + .map_err(|e| CloudError::Unreachable { + reason: e.to_string(), + spooled_bytes: 0, + })?; + + let status = res.status(); + if status.is_success() { + let ack = + res.json::() + .await + .map_err(|e| CloudError::InvalidAcknowledgement { + submission_id, + detail: format!("unreadable ack: {e}"), + })?; + if ack.submission_id != submission_id { + return Err(CloudError::InvalidAcknowledgement { + submission_id, + detail: format!("response named submission {}", ack.submission_id), + }); + } + if ack.processed_spans != span_count { + return Err(CloudError::InvalidAcknowledgement { + submission_id, + detail: format!("processed {} of {span_count} spans", ack.processed_spans), + }); + } + return Ok(ack); + } + + match status.as_u16() { + 401 | 403 => Err(CloudError::CredentialRejected), + // 5xx and 429 are the backend's problem, not the payload's: keep it. + 429 | 500..=599 => Err(CloudError::Unreachable { + reason: format!("backend returned {status}"), + spooled_bytes: 0, + }), + _ => { + let detail = res + .json::() + .await + .ok() + .and_then(|v| v["detail"].as_str().map(String::from)) + .unwrap_or_else(|| format!("backend returned {status}")); + Err(CloudError::Rejected { detail }) + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn only_transient_failures_are_retryable() { + assert!(CloudError::Unreachable { + reason: "timeout".into(), + spooled_bytes: 0 + } + .is_retryable()); + + // These must NOT buffer forever: no amount of waiting fixes a revoked + // credential or a payload the backend refuses. + assert!(CloudError::CredentialRejected.is_retryable()); + assert!(!CloudError::NotEnrolled.is_retryable()); + assert!(!CloudError::Rejected { + detail: "bad".into() + } + .is_retryable()); + } + + #[test] + fn production_backends_require_a_clean_https_origin() { + assert!(BackendUrl::production("https://cloud.test").is_ok()); + for invalid in [ + "http://cloud.test", + "https://user@cloud.test", + "https://cloud.test/path", + "https://cloud.test?query=1", + "https://cloud.test#fragment", + ] { + assert!( + BackendUrl::production(invalid).is_err(), + "accepted {invalid}" + ); + } + } + + #[test] + fn development_http_is_restricted_to_loopback() { + assert!(BackendUrl::loopback_development("http://127.0.0.1:1234").is_ok()); + assert!(BackendUrl::loopback_development("http://localhost:1234").is_ok()); + assert!(BackendUrl::loopback_development("http://192.168.1.2:1234").is_err()); + } + + #[test] + fn errors_tell_the_operator_what_to_do() { + // These strings are the entire support channel for a self-hosted user. + assert!(CloudError::NotEnrolled + .to_string() + .contains("enrollment code")); + assert!(CloudError::CredentialRejected + .to_string() + .contains("re-enroll")); + } +} diff --git a/crates/temps-cloud-client/src/link.rs b/crates/temps-cloud-client/src/link.rs new file mode 100644 index 000000000..8c388f47c --- /dev/null +++ b/crates/temps-cloud-client/src/link.rs @@ -0,0 +1,428 @@ +//! The object a running instance holds. +//! +//! Owns the link state, the spool and the HTTP client, and exposes the two +//! operations the rest of the instance needs: [`CloudLink::record`], which must +//! never block or fail, and [`CloudLink::flush`], which a background task calls +//! on an interval. +//! +//! # Why `record` cannot fail +//! +//! It is called from wherever the instance already produces telemetry. If it +//! could return an error, every call site would need a decision about what to +//! do — and one of them would eventually decide to propagate it, which would +//! make an outage in *our* backend into an incident in the operator's +//! application. So it takes `&self`, returns `()`, and the worst it can do is +//! silently... no: the worst it can do is *count a drop the operator can see*. + +use std::path::PathBuf; +use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; +use std::sync::{Mutex, RwLock}; + +use temps_cloud_protocol::SpanRecord; +use uuid::Uuid; + +use crate::spool::Spool; +use crate::state::EnrollmentState; +use crate::status::{LinkStatus, MirrorHealth}; +use crate::{BackendUrl, CloudClient, CloudError}; + +/// Spans per shipment. Small enough that one failure loses little progress. +const BATCH_SIZE: usize = 500; + +/// What a flush attempt did. Returned so a caller can log or schedule backoff. +#[derive(Debug, Clone, PartialEq)] +pub enum FlushOutcome { + /// Nothing buffered. + Idle, + /// Not linked, so there is nothing to mirror to. + NotLinked, + Shipped { + spans: usize, + }, + /// Kept for a later attempt. + Retained { + spans: usize, + reason: String, + }, + /// Shipment needs operator action, but the batch remains retained. + Blocked { + spans: usize, + reason: String, + }, +} + +#[derive(Clone)] +struct PendingSubmission { + submission_id: Uuid, + spans: Vec, +} + +pub struct CloudLink { + state: RwLock>, + spool: Mutex, + /// The active submission stays here until a matching full acknowledgement + /// arrives, preserving its id across retries. + pending: Mutex>, + health: RwLock, + state_path: PathBuf, + agent_version: String, + /// Set when the backend refuses our token. Distinct from mirror health: + /// this one needs the operator, not time. + credential_rejected: AtomicBool, + generation: AtomicU64, + flush_lock: tokio::sync::Mutex<()>, + allow_loopback_development: bool, +} + +impl CloudLink { + /// Load from disk. An unlinked or absent state is a normal outcome, not an + /// error — most instances never connect anything. + pub fn load(data_dir: PathBuf, agent_version: impl Into) -> Self { + Self::load_inner(data_dir, agent_version, false) + } + + /// Local-test constructor. Production callers must use [`CloudLink::load`]. + pub fn load_for_loopback_development( + data_dir: PathBuf, + agent_version: impl Into, + ) -> Self { + Self::load_inner(data_dir, agent_version, true) + } + + fn load_inner( + data_dir: PathBuf, + agent_version: impl Into, + allow_loopback_development: bool, + ) -> Self { + // Credentials live in their own directory; state hardening must never + // chmod an operator's shared TEMPS_DATA_DIR. + let state_path = data_dir.join("cloud-link").join("state.json"); + let state = EnrollmentState::load(&state_path).unwrap_or_else(|e| { + // Corruption is reported, not silently reset: overwriting would + // destroy a token the operator may still be able to recover. + tracing::error!(error = %e, "link state unreadable; treating as unlinked"); + None + }); + + Self { + state: RwLock::new(state), + spool: Mutex::new(Spool::with_default_capacity()), + pending: Mutex::new(None), + health: RwLock::new(MirrorHealth::Healthy), + state_path, + agent_version: agent_version.into(), + credential_rejected: AtomicBool::new(false), + generation: AtomicU64::new(0), + flush_lock: tokio::sync::Mutex::new(()), + allow_loopback_development, + } + } + + fn parse_backend(&self, value: &str) -> Result { + if self.allow_loopback_development { + BackendUrl::loopback_development(value) + } else { + BackendUrl::production(value) + } + } + + pub fn status(&self) -> LinkStatus { + match &*self.state.read().unwrap_or_else(|p| p.into_inner()) { + None => LinkStatus::NotConfigured, + Some(s) if s.is_linked() => { + let base_url = s.base_url.clone(); + // A token that still exists but is no longer accepted is its + // own state: the operator must re-enroll, and no amount of + // waiting will fix it. Reporting it as plain `Linked` would + // leave them watching a spool that never drains. + if self.credential_rejected.load(Ordering::SeqCst) { + LinkStatus::CredentialRejected { base_url } + } else { + LinkStatus::Linked { base_url } + } + } + Some(s) => LinkStatus::AwaitingEnrollment { + base_url: s.base_url.clone(), + }, + } + } + + pub fn health(&self) -> MirrorHealth { + self.health + .read() + .unwrap_or_else(|p| p.into_inner()) + .clone() + } + + pub fn instance_id(&self) -> Option { + self.state + .read() + .unwrap_or_else(|p| p.into_inner()) + .as_ref() + .map(|s| s.instance_id) + } + + /// Point this instance at a backend without linking it yet. + pub fn configure(&self, backend: BackendUrl) -> Result<(), crate::state::StateError> { + let mut guard = self.state.write().unwrap_or_else(|p| p.into_inner()); + let next_url = backend.as_str().to_string(); + let mut changed_origin = false; + let next = match guard.as_ref() { + Some(existing) => { + let mut existing = existing.clone(); + if existing.base_url != next_url { + changed_origin = true; + // Credentials are origin-bound. Keeping a token while + // changing its destination would exfiltrate it on flush. + // Buffered telemetry is origin-bound for the same reason. + existing.unlink(); + } + existing.base_url = next_url; + existing + } + None => EnrollmentState::new(next_url), + }; + next.save(&self.state_path)?; + if changed_origin { + self.spool + .lock() + .unwrap_or_else(|p| p.into_inner()) + .take(usize::MAX); + self.pending + .lock() + .unwrap_or_else(|p| p.into_inner()) + .take(); + self.credential_rejected.store(false, Ordering::SeqCst); + *self.health.write().unwrap_or_else(|p| p.into_inner()) = MirrorHealth::Healthy; + } + *guard = Some(next); + self.generation.fetch_add(1, Ordering::SeqCst); + Ok(()) + } + + /// Redeem an operator-pasted code and persist the resulting credential. + pub async fn enroll(&self, code: &str) -> Result<(), CloudError> { + let (base_url, instance_id, generation) = { + let guard = self.state.read().unwrap_or_else(|p| p.into_inner()); + let s = guard.as_ref().ok_or(CloudError::NotEnrolled)?; + ( + s.base_url.clone(), + s.instance_id, + self.generation.load(Ordering::SeqCst), + ) + }; + + let backend = self.parse_backend(&base_url)?; + let res = CloudClient::new(backend)? + .enroll(code, instance_id, &self.agent_version) + .await?; + + let mut guard = self.state.write().unwrap_or_else(|p| p.into_inner()); + let current = guard + .as_ref() + .ok_or_else(|| CloudError::EnrollmentRefused { + detail: "link state changed while enrollment was in progress; try again".into(), + })?; + if self.generation.load(Ordering::SeqCst) != generation + || current.base_url != base_url + || current.instance_id != instance_id + { + return Err(CloudError::EnrollmentRefused { + detail: "link state changed while enrollment was in progress; try again".into(), + }); + } + let mut next = current.clone(); + next.token = Some(res.instance_token); + next.tenant_id = Some(res.tenant_id); + // Clone → save → swap: a failed disk write cannot leave a credential + // alive only in memory. + next.save(&self.state_path) + .map_err(|e| CloudError::EnrollmentRefused { + detail: format!("enrolled, but the credential could not be saved: {e}"), + })?; + *guard = Some(next); + self.generation.fetch_add(1, Ordering::SeqCst); + self.credential_rejected.store(false, Ordering::SeqCst); + *self.health.write().unwrap_or_else(|p| p.into_inner()) = MirrorHealth::Healthy; + Ok(()) + } + + /// Forget the credential. Keeps the instance identity so re-linking later + /// reattaches to the same record. + pub fn disconnect(&self) -> Result<(), crate::state::StateError> { + let mut guard = self.state.write().unwrap_or_else(|p| p.into_inner()); + if let Some(s) = guard.as_mut() { + let mut next = s.clone(); + next.unlink(); + next.save(&self.state_path)?; + *s = next; + } + self.spool + .lock() + .unwrap_or_else(|p| p.into_inner()) + .take(usize::MAX); + self.pending + .lock() + .unwrap_or_else(|p| p.into_inner()) + .take(); + self.credential_rejected.store(false, Ordering::SeqCst); + self.generation.fetch_add(1, Ordering::SeqCst); + *self.health.write().unwrap_or_else(|p| p.into_inner()) = MirrorHealth::Healthy; + Ok(()) + } + + /// Offer spans to the mirror. Never blocks on IO, never fails. + /// + /// When the instance is not linked this is a no-op: buffering for a backend + /// that does not exist would burn memory to no purpose. Telemetry is still + /// stored locally by the instance itself — that path is untouched. + pub fn record(&self, spans: Vec) { + let state = self.state.read().unwrap_or_else(|p| p.into_inner()); + if !state.as_ref().is_some_and(|s| s.is_linked()) { + return; + } + let mut spool = self.spool.lock().unwrap_or_else(|p| p.into_inner()); + spool.push(spans); + + if spool.dropped() > 0 { + *self.health.write().unwrap_or_else(|p| p.into_inner()) = MirrorHealth::Dropping { + spooled: spool.len(), + dropped: spool.dropped(), + }; + } + drop(state); + } + + pub fn spooled(&self) -> usize { + let queued = self.spool.lock().unwrap_or_else(|p| p.into_inner()).len(); + let pending = self + .pending + .lock() + .unwrap_or_else(|p| p.into_inner()) + .as_ref() + .map_or(0, |batch| batch.spans.len()); + queued + pending + } + + /// Ship one batch. Called on an interval by a background task. + pub async fn flush(&self) -> FlushOutcome { + let _flush = self.flush_lock.lock().await; + let (base_url, token, generation) = { + let guard = self.state.read().unwrap_or_else(|p| p.into_inner()); + match guard.as_ref() { + Some(s) if s.is_linked() => ( + s.base_url.clone(), + s.token.clone().unwrap_or_default(), + self.generation.load(Ordering::SeqCst), + ), + _ => return FlushOutcome::NotLinked, + } + }; + + let pending = { + let mut pending = self.pending.lock().unwrap_or_else(|p| p.into_inner()); + if pending.is_none() { + let spans = self + .spool + .lock() + .unwrap_or_else(|p| p.into_inner()) + .take(BATCH_SIZE); + if !spans.is_empty() { + *pending = Some(PendingSubmission { + submission_id: Uuid::new_v4(), + spans, + }); + } + } + pending.clone() + }; + let Some(pending) = pending else { + *self.health.write().unwrap_or_else(|p| p.into_inner()) = MirrorHealth::Healthy; + return FlushOutcome::Idle; + }; + let count = pending.spans.len(); + let backend = match self.parse_backend(&base_url) { + Ok(backend) => backend, + Err(e) => { + return FlushOutcome::Blocked { + spans: count, + reason: e.to_string(), + } + } + }; + + let client = match CloudClient::new(backend) { + Ok(client) => client, + Err(e) => { + return FlushOutcome::Blocked { + spans: count, + reason: e.to_string(), + } + } + }; + + let result = client + .ship(&token, pending.submission_id, pending.spans.clone()) + .await; + if self.generation.load(Ordering::SeqCst) != generation { + return FlushOutcome::Blocked { + spans: count, + reason: "link state changed while this shipment was in progress".into(), + }; + } + + match result { + Ok(ack) => { + let mut current = self.pending.lock().unwrap_or_else(|p| p.into_inner()); + if current + .as_ref() + .is_some_and(|value| value.submission_id == pending.submission_id) + { + current.take(); + } + self.credential_rejected.store(false, Ordering::SeqCst); + *self.health.write().unwrap_or_else(|p| p.into_inner()) = match ack.warning { + Some(detail) => MirrorHealth::Degraded { detail }, + None => MirrorHealth::Healthy, + }; + FlushOutcome::Shipped { spans: count } + } + + Err(e) if e.is_retryable() => { + if matches!(e, CloudError::CredentialRejected) { + self.credential_rejected.store(true, Ordering::SeqCst); + } + let spool = self.spool.lock().unwrap_or_else(|p| p.into_inner()); + let spooled = spool.len() + count; + let dropped = spool.dropped(); + + *self.health.write().unwrap_or_else(|p| p.into_inner()) = if dropped > 0 { + MirrorHealth::Dropping { spooled, dropped } + } else { + MirrorHealth::Buffering { + spooled, + reason: e.to_string(), + } + }; + FlushOutcome::Retained { + spans: count, + reason: e.to_string(), + } + } + + Err(e) => { + // Never infer that a 4xx or version-skew response makes customer + // telemetry disposable. Keep the bounded pending batch and make + // the operator-visible state explicit. + *self.health.write().unwrap_or_else(|p| p.into_inner()) = MirrorHealth::Buffering { + spooled: self.spooled(), + reason: e.to_string(), + }; + FlushOutcome::Blocked { + spans: count, + reason: e.to_string(), + } + } + } + } +} diff --git a/crates/temps-cloud-client/src/spool.rs b/crates/temps-cloud-client/src/spool.rs new file mode 100644 index 000000000..50f46f7e5 --- /dev/null +++ b/crates/temps-cloud-client/src/spool.rs @@ -0,0 +1,247 @@ +//! Bounded in-memory buffer for telemetry the backend could not accept yet. +//! +//! # Why bounded, and why it drops the *oldest* +//! +//! An unbounded buffer is a memory leak with a delay: a backend outage would +//! eventually OOM the instance, turning our problem into the operator's outage. +//! So the spool has a hard cap. +//! +//! When full it discards the **oldest** spans, because during an incident the +//! newest telemetry is the useful telemetry. Dropping is always counted and +//! always reported — a gap the operator cannot see is worse than no data at all. + +use temps_cloud_protocol::SpanRecord; + +/// Default cap. Roughly a few MB of spans — enough to ride out a short outage, +/// small enough to be irrelevant on a 4 GB box. +pub const DEFAULT_CAPACITY: usize = 10_000; +pub const DEFAULT_CAPACITY_BYTES: usize = 8 * 1024 * 1024; + +#[derive(Debug)] +struct BufferedSpan { + span: SpanRecord, + bytes: usize, +} + +#[derive(Debug)] +pub struct Spool { + buffer: std::collections::VecDeque, + capacity: usize, + capacity_bytes: usize, + buffered_bytes: usize, + dropped: u64, +} + +impl Spool { + pub fn new(capacity: usize) -> Self { + Self::with_limits(capacity, usize::MAX) + } + + pub fn with_limits(capacity: usize, capacity_bytes: usize) -> Self { + Self { + buffer: std::collections::VecDeque::new(), + capacity: capacity.max(1), + capacity_bytes: capacity_bytes.max(1), + buffered_bytes: 0, + dropped: 0, + } + } + + pub fn with_default_capacity() -> Self { + Self::with_limits(DEFAULT_CAPACITY, DEFAULT_CAPACITY_BYTES) + } + + pub fn len(&self) -> usize { + self.buffer.len() + } + + pub fn is_empty(&self) -> bool { + self.buffer.is_empty() + } + + /// Spans discarded because the spool was full. Never resets — it is a + /// lifetime counter the operator can watch. + pub fn dropped(&self) -> u64 { + self.dropped + } + + /// Add spans, discarding the oldest if that would exceed the cap. + pub fn push(&mut self, spans: impl IntoIterator) { + for span in spans { + let bytes = estimated_bytes(&span); + if bytes > self.capacity_bytes { + self.dropped += 1; + continue; + } + while self.buffer.len() == self.capacity + || self.buffered_bytes.saturating_add(bytes) > self.capacity_bytes + { + if let Some(removed) = self.buffer.pop_front() { + self.buffered_bytes = self.buffered_bytes.saturating_sub(removed.bytes); + self.dropped += 1; + } else { + break; + } + } + self.buffered_bytes = self.buffered_bytes.saturating_add(bytes); + self.buffer.push_back(BufferedSpan { span, bytes }); + } + } + + /// Take up to `max` spans for a shipping attempt. + /// + /// They are removed from the spool, so a caller that fails to ship MUST + /// return them with [`Spool::requeue`]. That is deliberate: it makes losing + /// data require an explicit mistake rather than a forgotten branch. + pub fn take(&mut self, max: usize) -> Vec { + let n = max.min(self.buffer.len()); + self.buffer + .drain(..n) + .map(|buffered| { + self.buffered_bytes = self.buffered_bytes.saturating_sub(buffered.bytes); + buffered.span + }) + .collect() + } + + /// Put spans back at the front after a failed attempt, preserving order. + pub fn requeue(&mut self, spans: Vec) { + for s in spans.into_iter().rev() { + let bytes = estimated_bytes(&s); + if bytes > self.capacity_bytes { + self.dropped += 1; + continue; + } + while self.buffer.len() == self.capacity + || self.buffered_bytes.saturating_add(bytes) > self.capacity_bytes + { + // Still full: the newest already-buffered span wins over a + // returned older one. + if let Some(removed) = self.buffer.pop_back() { + self.buffered_bytes = self.buffered_bytes.saturating_sub(removed.bytes); + self.dropped += 1; + } else { + break; + } + } + self.buffered_bytes = self.buffered_bytes.saturating_add(bytes); + self.buffer.push_front(BufferedSpan { span: s, bytes }); + } + } +} + +/// Cheap upper-bound input sizing without serializing on the telemetry path. +fn estimated_bytes(span: &SpanRecord) -> usize { + let attributes = span.attributes.iter().fold(0usize, |total, (key, value)| { + total.saturating_add(key.len()).saturating_add(value.len()) + }); + span.trace_id + .len() + .saturating_add(span.span_id.len()) + .saturating_add(span.name.len()) + .saturating_add(attributes) + .saturating_add(std::mem::size_of::() + std::mem::size_of::() + 64) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn span(i: i64) -> SpanRecord { + SpanRecord { + trace_id: format!("t{i}"), + span_id: format!("s{i}"), + name: "GET /".into(), + ts_millis: i, + duration_ms: 1.0, + attributes: Default::default(), + } + } + + fn spans(range: std::ops::Range) -> Vec { + range.map(span).collect() + } + + #[test] + fn spans_come_back_in_the_order_they_went_in() { + let mut s = Spool::new(10); + s.push(spans(0..3)); + let taken = s.take(10); + assert_eq!( + taken.iter().map(|x| x.ts_millis).collect::>(), + vec![0, 1, 2] + ); + assert!(s.is_empty()); + } + + #[test] + fn a_full_spool_discards_the_oldest_and_counts_it() { + // During an incident the newest telemetry is the useful telemetry. + let mut s = Spool::new(3); + s.push(spans(0..5)); + + assert_eq!(s.len(), 3); + assert_eq!(s.dropped(), 2); + assert_eq!( + s.take(3).iter().map(|x| x.ts_millis).collect::>(), + vec![2, 3, 4], + "the newest spans should survive" + ); + } + + #[test] + fn taking_a_partial_batch_leaves_the_rest() { + let mut s = Spool::new(10); + s.push(spans(0..5)); + assert_eq!(s.take(2).len(), 2); + assert_eq!(s.len(), 3); + } + + #[test] + fn requeued_spans_keep_their_place_at_the_front() { + // A failed shipment must not reorder telemetry. + let mut s = Spool::new(10); + s.push(spans(0..4)); + let attempt = s.take(2); + s.requeue(attempt); + + assert_eq!( + s.take(4).iter().map(|x| x.ts_millis).collect::>(), + vec![0, 1, 2, 3] + ); + } + + #[test] + fn the_spool_never_grows_past_its_cap_however_it_is_used() { + let mut s = Spool::new(4); + for _ in 0..10 { + s.push(spans(0..3)); + let t = s.take(2); + s.requeue(t); + assert!(s.len() <= 4, "spool exceeded its cap: {}", s.len()); + } + } + + #[test] + fn a_zero_capacity_spool_is_clamped_rather_than_dividing_by_zero() { + let mut s = Spool::new(0); + s.push(spans(0..3)); + assert_eq!(s.len(), 1); + } + + #[test] + fn taking_from_an_empty_spool_is_not_an_error() { + assert!(Spool::new(10).take(5).is_empty()); + } + + #[test] + fn serialized_content_cannot_bypass_the_memory_bound() { + let mut s = Spool::with_limits(10_000, 256); + let mut oversized = span(1); + oversized.name = "x".repeat(10_000); + s.push([oversized]); + + assert!(s.is_empty()); + assert_eq!(s.dropped(), 1); + } +} diff --git a/crates/temps-cloud-client/src/state.rs b/crates/temps-cloud-client/src/state.rs new file mode 100644 index 000000000..a369c80d1 --- /dev/null +++ b/crates/temps-cloud-client/src/state.rs @@ -0,0 +1,317 @@ +//! Persisted link state: which account this instance is connected to, and the +//! credential it uses. +//! +//! Written atomically (temp file + rename) so a crash mid-write cannot leave a +//! half-parsed file that makes a working instance look unenrolled. + +use std::io::Write; +use std::path::Path; + +use serde::{Deserialize, Serialize}; +use thiserror::Error; +use uuid::Uuid; + +#[derive(Debug, Error)] +pub enum StateError { + #[error("Failed to read link state at {path}: {reason}")] + Read { path: String, reason: String }, + + #[error("Failed to write link state at {path}: {reason}")] + Write { path: String, reason: String }, + + #[error("Link state at {path} is corrupt: {reason}")] + Corrupt { path: String, reason: String }, +} + +#[derive(Clone, PartialEq, Serialize, Deserialize)] +pub struct EnrollmentState { + /// Minted once, on first run, and kept forever. Stable across + /// re-enrollment so the backend recognises a returning instance rather + /// than accumulating duplicates. + pub instance_id: Uuid, + + /// Base URL of the managed backend. + pub base_url: String, + + /// Bearer token. `None` means "known backend, not linked" — a different + /// state from having no file at all, and worth distinguishing in the UI. + pub token: Option, + + pub tenant_id: Option, +} + +impl std::fmt::Debug for EnrollmentState { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("EnrollmentState") + .field("instance_id", &self.instance_id) + .field("base_url", &self.base_url) + .field("token", &self.token.as_ref().map(|_| "[REDACTED]")) + .field("tenant_id", &self.tenant_id) + .finish() + } +} + +impl EnrollmentState { + /// A brand-new, unlinked instance. + pub fn new(base_url: impl Into) -> Self { + Self { + instance_id: Uuid::new_v4(), + base_url: base_url.into(), + token: None, + tenant_id: None, + } + } + + pub fn is_linked(&self) -> bool { + self.token.is_some() + } + + /// Load, or `Ok(None)` when this instance has never been linked. + /// + /// A missing file is a normal state, not an error — most instances never + /// connect anything, and treating that as a failure would fill their logs. + pub fn load(path: &Path) -> Result, StateError> { + #[cfg(unix)] + if path.exists() { + use std::os::unix::fs::PermissionsExt; + + let read_err = |reason: String| StateError::Read { + path: path.display().to_string(), + reason, + }; + let dir = path + .parent() + .filter(|parent| !parent.as_os_str().is_empty()) + .unwrap_or_else(|| Path::new(".")); + std::fs::set_permissions(dir, std::fs::Permissions::from_mode(0o700)) + .map_err(|e| read_err(format!("protect credential directory: {e}")))?; + std::fs::set_permissions(path, std::fs::Permissions::from_mode(0o600)) + .map_err(|e| read_err(format!("protect credential file: {e}")))?; + } + + let raw = match std::fs::read_to_string(path) { + Ok(r) => r, + Err(e) if e.kind() == std::io::ErrorKind::NotFound => return Ok(None), + Err(e) => { + return Err(StateError::Read { + path: path.display().to_string(), + reason: e.to_string(), + }) + } + }; + + serde_json::from_str(&raw) + .map(Some) + .map_err(|e| StateError::Corrupt { + path: path.display().to_string(), + reason: e.to_string(), + }) + } + + /// Persist atomically. + pub fn save(&self, path: &Path) -> Result<(), StateError> { + let write_err = |reason: String| StateError::Write { + path: path.display().to_string(), + reason, + }; + + let dir = path + .parent() + .filter(|parent| !parent.as_os_str().is_empty()) + .unwrap_or_else(|| Path::new(".")); + std::fs::create_dir_all(dir).map_err(|e| write_err(e.to_string()))?; + + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + std::fs::set_permissions(dir, std::fs::Permissions::from_mode(0o700)) + .map_err(|e| write_err(e.to_string()))?; + } + + let json = serde_json::to_string_pretty(self).map_err(|e| write_err(e.to_string()))?; + + // A unique O_EXCL temporary file prevents a predictable `.tmp` symlink + // from redirecting the credential write. Same directory keeps the final + // persist atomic on Unix. + let mut tmp = tempfile::NamedTempFile::new_in(dir) + .map_err(|e| write_err(format!("create secure temporary file: {e}")))?; + tmp.write_all(json.as_bytes()) + .map_err(|e| write_err(format!("write secure temporary file: {e}")))?; + tmp.as_file() + .sync_all() + .map_err(|e| write_err(format!("sync secure temporary file: {e}")))?; + + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + tmp.as_file() + .set_permissions(std::fs::Permissions::from_mode(0o600)) + .map_err(|e| write_err(format!("protect secure temporary file: {e}")))?; + } + + tmp.persist(path) + .map_err(|e| write_err(format!("atomically replace link state: {}", e.error)))?; + + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + std::fs::set_permissions(path, std::fs::Permissions::from_mode(0o600)) + .map_err(|e| write_err(format!("protect link state: {e}")))?; + } + + Ok(()) + } + + /// Forget the credential but keep the identity. + /// + /// Disconnecting must not mint a new `instance_id`: re-linking later should + /// reattach to the same instance record rather than orphaning its history. + pub fn unlink(&mut self) { + self.token = None; + self.tenant_id = None; + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::path::PathBuf; + + fn temp() -> (tempfile::TempDir, PathBuf) { + let d = tempfile::tempdir().unwrap(); + let p = d.path().join("nested").join("link.json"); + (d, p) + } + + #[test] + fn a_never_linked_instance_loads_as_none_not_an_error() { + let (_d, p) = temp(); + assert!(matches!(EnrollmentState::load(&p), Ok(None))); + } + + #[test] + fn state_round_trips_through_disk() { + let (_d, p) = temp(); + let mut s = EnrollmentState::new("https://cloud.test"); + s.token = Some("inst_abc".into()); + s.tenant_id = Some(Uuid::new_v4()); + + s.save(&p).unwrap(); + assert_eq!(EnrollmentState::load(&p).unwrap(), Some(s)); + } + + #[test] + fn saving_creates_missing_parent_directories() { + let (_d, p) = temp(); + EnrollmentState::new("https://cloud.test").save(&p).unwrap(); + assert!(p.exists()); + } + + #[test] + fn a_corrupt_file_is_reported_with_its_path_not_silently_ignored() { + let (_d, p) = temp(); + std::fs::create_dir_all(p.parent().unwrap()).unwrap(); + std::fs::write(&p, "{not json").unwrap(); + + match EnrollmentState::load(&p) { + Err(StateError::Corrupt { path, .. }) => { + assert!(path.contains("link.json"), "error must name the file"); + } + other => panic!("corruption must not be swallowed, got {other:?}"), + } + } + + #[test] + fn unlinking_keeps_the_instance_identity() { + let mut s = EnrollmentState::new("https://cloud.test"); + let id = s.instance_id; + s.token = Some("inst_abc".into()); + s.tenant_id = Some(Uuid::new_v4()); + + s.unlink(); + + assert!(!s.is_linked()); + assert!(s.tenant_id.is_none()); + assert_eq!(s.instance_id, id, "re-linking must reattach, not orphan"); + } + + #[test] + fn saving_twice_leaves_no_temp_file_behind() { + let (_d, p) = temp(); + let s = EnrollmentState::new("https://cloud.test"); + s.save(&p).unwrap(); + s.save(&p).unwrap(); + assert!( + !p.with_extension("tmp").exists(), + "temp file was left behind" + ); + } + + #[cfg(unix)] + #[test] + fn persisted_credentials_are_private_to_the_owner() { + use std::os::unix::fs::PermissionsExt; + + let (_d, p) = temp(); + let mut s = EnrollmentState::new("https://cloud.test"); + s.token = Some("inst_secret".into()); + s.save(&p).unwrap(); + + assert_eq!( + std::fs::metadata(&p).unwrap().permissions().mode() & 0o777, + 0o600 + ); + assert_eq!( + std::fs::metadata(p.parent().unwrap()) + .unwrap() + .permissions() + .mode() + & 0o777, + 0o700 + ); + } + + #[cfg(unix)] + #[test] + fn loading_repairs_permissions_from_a_legacy_installation() { + use std::os::unix::fs::PermissionsExt; + + let (_d, p) = temp(); + let mut s = EnrollmentState::new("https://cloud.test"); + s.token = Some("inst_secret".into()); + s.save(&p).unwrap(); + std::fs::set_permissions(&p, std::fs::Permissions::from_mode(0o644)).unwrap(); + std::fs::set_permissions(p.parent().unwrap(), std::fs::Permissions::from_mode(0o755)) + .unwrap(); + + assert!(EnrollmentState::load(&p).unwrap().is_some()); + assert_eq!( + std::fs::metadata(&p).unwrap().permissions().mode() & 0o777, + 0o600 + ); + assert_eq!( + std::fs::metadata(p.parent().unwrap()) + .unwrap() + .permissions() + .mode() + & 0o777, + 0o700 + ); + } + + #[test] + fn debug_output_redacts_the_bearer_token() { + let mut s = EnrollmentState::new("https://cloud.test"); + s.token = Some("inst_secret".into()); + assert!(!format!("{s:?}").contains("inst_secret")); + } + + #[test] + fn a_known_backend_without_a_token_is_not_linked() { + // Distinct from "no file": the operator configured a backend and has + // not finished connecting, which the UI should say plainly. + let s = EnrollmentState::new("https://cloud.test"); + assert!(!s.is_linked()); + assert!(s.token.is_none()); + } +} diff --git a/crates/temps-cloud-client/src/status.rs b/crates/temps-cloud-client/src/status.rs new file mode 100644 index 000000000..01d4fe86b --- /dev/null +++ b/crates/temps-cloud-client/src/status.rs @@ -0,0 +1,203 @@ +//! The link state the console and CLI show the operator. +//! +//! A self-hosted operator debugs alone. Every state here is either "fine" or a +//! sentence naming what is wrong and what to do about it — never a spinner, +//! never a silent absence, and never a bare boolean the UI has to interpret. + +use temps_cloud_protocol::Unavailable; + +/// Whether this instance is linked to a managed account. +#[derive(Debug, Clone, PartialEq)] +pub enum LinkStatus { + /// No backend configured. The UI should offer to connect one rather than + /// hiding the feature — an unconfigured capability must onboard, not vanish. + NotConfigured, + /// Backend known, not yet linked. + AwaitingEnrollment { + base_url: String, + }, + Linked { + base_url: String, + }, + /// Linked, but the credential was refused. Actionable, not fatal. + CredentialRejected { + base_url: String, + }, +} + +impl LinkStatus { + /// One line, written for a human with no support channel. + pub fn message(&self) -> String { + match self { + LinkStatus::NotConfigured => { + "Not connected to a managed backend. Telemetry is stored locally only.".into() + } + LinkStatus::AwaitingEnrollment { base_url } => format!( + "Backend {base_url} is configured but this instance is not linked. \ + Paste an enrollment code to connect it." + ), + LinkStatus::Linked { base_url } => format!("Connected to {base_url}."), + LinkStatus::CredentialRejected { base_url } => format!( + "{base_url} rejected this instance's credential. Re-enroll to reconnect. \ + Telemetry is still being stored locally." + ), + } + } + + /// Whether the operator must do something. Drives whether the UI nags. + pub fn needs_attention(&self) -> bool { + matches!( + self, + LinkStatus::AwaitingEnrollment { .. } | LinkStatus::CredentialRejected { .. } + ) + } +} + +/// How the mirror is doing, independent of whether the link is valid. +#[derive(Debug, Clone, PartialEq)] +pub enum MirrorHealth { + /// Everything shipped. + Healthy, + /// Buffering in memory while the local Temps store remains authoritative. + Buffering { spooled: usize, reason: String }, + /// The spool overflowed and telemetry was discarded. This is the one state + /// that must never be quiet. + Dropping { spooled: usize, dropped: u64 }, + /// Accepted, but the backend is degrading us (e.g. over quota). + Degraded { detail: Unavailable }, +} + +impl MirrorHealth { + pub fn message(&self) -> String { + match self { + MirrorHealth::Healthy => "All telemetry mirrored.".into(), + MirrorHealth::Buffering { spooled, reason } => format!( + "{spooled} spans awaiting mirror delivery — {reason}. Source telemetry remains \ + in local Temps storage." + ), + MirrorHealth::Dropping { spooled, dropped } => format!( + "Local buffer is full: {dropped} spans discarded, {spooled} still queued. \ + The backend has been unreachable long enough to overflow the buffer." + ), + MirrorHealth::Degraded { detail } => match detail { + Unavailable::QuotaExhausted { + used_bytes, + limit_bytes, + resets_at, + } => format!( + "Ingest allowance used ({used_bytes} of {limit_bytes} bytes). \ + Sampling until {resets_at}; raise the cap or upgrade to keep full fidelity." + ), + Unavailable::NotEntitled { required_plan } => { + format!("This capability requires the {required_plan} plan.") + } + Unavailable::NotEnrolled => "This instance is not linked to an account.".into(), + Unavailable::Degraded { + retry_after_secs, + detail, + } => format!( + "Backend degraded ({detail}); retrying in {retry_after_secs}s. \ + Telemetry is buffered locally in the meantime." + ), + _ => "The managed backend is unavailable; telemetry is buffered locally.".into(), + }, + } + } + + /// True when telemetry has actually been lost, as opposed to delayed. + pub fn is_losing_data(&self) -> bool { + matches!(self, MirrorHealth::Dropping { .. }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn an_unconfigured_instance_is_told_what_it_is_missing_not_shown_nothing() { + let m = LinkStatus::NotConfigured.message(); + assert!( + m.contains("locally"), + "must say where telemetry is going: {m}" + ); + assert!(!LinkStatus::NotConfigured.needs_attention()); + } + + #[test] + fn half_finished_setup_asks_the_operator_to_finish_it() { + let s = LinkStatus::AwaitingEnrollment { + base_url: "https://cloud.test".into(), + }; + assert!(s.needs_attention()); + assert!(s.message().contains("enrollment code")); + } + + #[test] + fn a_rejected_credential_is_actionable_and_says_local_storage_is_unaffected() { + let s = LinkStatus::CredentialRejected { + base_url: "https://cloud.test".into(), + }; + assert!(s.needs_attention()); + let m = s.message(); + assert!(m.contains("Re-enroll"), "must say what to do: {m}"); + assert!(m.contains("locally"), "must reassure about local data: {m}"); + } + + #[test] + fn buffering_is_clearly_distinguished_from_losing_data() { + let buffering = MirrorHealth::Buffering { + spooled: 120, + reason: "backend unreachable".into(), + }; + assert!(!buffering.is_losing_data()); + assert!(buffering + .message() + .contains("Source telemetry remains in local Temps storage")); + + let dropping = MirrorHealth::Dropping { + spooled: 10_000, + dropped: 523, + }; + assert!(dropping.is_losing_data()); + assert!(dropping.message().contains("523"), "must state how many"); + } + + #[test] + fn quota_degradation_names_the_numbers_and_the_remedy() { + let m = MirrorHealth::Degraded { + detail: Unavailable::QuotaExhausted { + used_bytes: 11_000_000_000, + limit_bytes: 10_737_418_240, + resets_at: chrono::Utc::now(), + }, + } + .message(); + assert!(m.contains("11000000000"), "must show real usage: {m}"); + assert!(m.contains("upgrade"), "must offer a remedy: {m}"); + } + + #[test] + fn every_state_produces_a_non_empty_message() { + // No state may render as a blank or a spinner. + let states: Vec String>> = vec![ + Box::new(|| LinkStatus::NotConfigured.message()), + Box::new(|| { + LinkStatus::Linked { + base_url: "u".into(), + } + .message() + }), + Box::new(|| MirrorHealth::Healthy.message()), + Box::new(|| { + MirrorHealth::Degraded { + detail: Unavailable::NotEnrolled, + } + .message() + }), + ]; + for f in states { + assert!(!f().trim().is_empty()); + } + } +} diff --git a/crates/temps-cloud-client/tests/client_behaviour_test.rs b/crates/temps-cloud-client/tests/client_behaviour_test.rs new file mode 100644 index 000000000..99f536424 --- /dev/null +++ b/crates/temps-cloud-client/tests/client_behaviour_test.rs @@ -0,0 +1,221 @@ +//! The client against a live HTTP backend. +//! +//! A stub server stands in for the managed backend so this suite can assert the +//! behaviour that matters to a self-hosted operator — what happens when the +//! backend is slow, wrong, unauthorised or simply gone — without depending on +//! the backend implementation. +//! +//! The governing property under test: **a failing backend never costs the +//! instance data or uptime.** It either succeeds, or it degrades to a state the +//! operator can see. + +use std::net::SocketAddr; + +use axum::{routing::post, Json, Router}; +use temps_cloud_client::spool::Spool; +use temps_cloud_client::{BackendUrl, CloudClient, CloudError}; +use temps_cloud_protocol::{SpanRecord, TelemetryBatch}; +use uuid::Uuid; + +/// Start a stub backend and return its base URL. +async fn serve(app: Router) -> String { + let listener = tokio::net::TcpListener::bind::("127.0.0.1:0".parse().unwrap()) + .await + .unwrap(); + let addr = listener.local_addr().unwrap(); + tokio::spawn(async move { + let _ = axum::serve(listener, app).await; + }); + format!("http://{addr}") +} + +fn client(url: &str) -> CloudClient { + CloudClient::new(BackendUrl::loopback_development(url).unwrap()).unwrap() +} + +fn spans(n: usize) -> Vec { + (0..n) + .map(|i| SpanRecord { + trace_id: "t".into(), + span_id: format!("s{i}"), + name: "GET /".into(), + ts_millis: i as i64, + duration_ms: 1.0, + attributes: Default::default(), + }) + .collect() +} + +#[tokio::test] +async fn enrolling_with_a_good_code_yields_a_token() { + let tenant = Uuid::new_v4(); + let url = serve(Router::new().route( + "/v1/enroll", + post(move || async move { + Json(serde_json::json!({ + "tenant_id": tenant, + "instance_token": "inst_abc123" + })) + }), + )) + .await; + + let got = client(&url) + .enroll("abcd-2345", Uuid::new_v4(), "0.1.0") + .await + .expect("enrollment should succeed"); + + assert_eq!(got.instance_token, "inst_abc123"); + assert_eq!(got.tenant_id, tenant); + // The stub omitted `capabilities` entirely, as an older backend would. + // Defaulting to empty — rather than failing to parse — is what keeps a new + // instance working against an older backend. + assert!(got.capabilities.is_empty()); +} + +#[tokio::test] +async fn a_refused_code_surfaces_the_backends_own_wording() { + // "this code has expired" is far more useful to a lone operator than + // "enrollment failed", so the backend's detail must reach them intact. + let url = serve(Router::new().route( + "/v1/enroll", + post(|| async { + ( + axum::http::StatusCode::BAD_REQUEST, + Json(serde_json::json!({"detail": "this code has expired — generate a new one"})), + ) + }), + )) + .await; + + match client(&url) + .enroll("dead-beef", Uuid::new_v4(), "0.1.0") + .await + { + Err(CloudError::EnrollmentRefused { detail }) => { + assert!(detail.contains("expired"), "lost the reason: {detail}"); + } + other => panic!("expected a refusal, got {other:?}"), + } +} + +#[tokio::test] +async fn shipping_returns_the_acknowledgement() { + let url = serve(Router::new().route( + "/v1/telemetry", + post(|Json(batch): Json| async move { + Json(serde_json::json!({ + "submission_id": batch.submission_id, + "processed_spans": batch.spans.len(), + "stored_spans": batch.spans.len(), + "metered_bytes": 512 + })) + }), + )) + .await; + + let submission_id = Uuid::new_v4(); + let ack = client(&url) + .ship("inst_abc", submission_id, spans(3)) + .await + .expect("ship should succeed"); + + assert_eq!(ack.submission_id, submission_id); + assert_eq!(ack.processed_spans, 3); + assert_eq!(ack.stored_spans, 3); + assert_eq!(ack.metered_bytes, 512); + assert!(ack.warning.is_none()); +} + +#[tokio::test] +async fn a_rejected_credential_is_repairable_and_keeps_the_submission() { + let url = serve(Router::new().route( + "/v1/telemetry", + post(|| async { axum::http::StatusCode::UNAUTHORIZED }), + )) + .await; + + let err = client(&url) + .ship("stale-token", Uuid::new_v4(), spans(1)) + .await + .unwrap_err(); + + assert!(matches!(err, CloudError::CredentialRejected)); + assert!( + err.is_retryable(), + "re-enrollment can repair a rejected credential, so the submission must survive" + ); +} + +#[tokio::test] +async fn a_backend_error_is_retryable_so_the_batch_is_kept() { + let url = serve(Router::new().route( + "/v1/telemetry", + post(|| async { axum::http::StatusCode::SERVICE_UNAVAILABLE }), + )) + .await; + + let err = client(&url) + .ship("inst_abc", Uuid::new_v4(), spans(2)) + .await + .unwrap_err(); + + assert!(err.is_retryable(), "5xx is our problem, not the payload's"); +} + +#[tokio::test] +async fn rate_limiting_is_treated_as_transient() { + let url = serve(Router::new().route( + "/v1/telemetry", + post(|| async { axum::http::StatusCode::TOO_MANY_REQUESTS }), + )) + .await; + + assert!(client(&url) + .ship("inst_abc", Uuid::new_v4(), spans(1)) + .await + .unwrap_err() + .is_retryable()); +} + +#[tokio::test] +async fn an_absent_backend_degrades_without_losing_the_batch() { + // Nothing is listening. This is the everyday case — a backend outage, a + // firewall, a laptop offline — and it must cost the operator nothing. + let client = client("http://127.0.0.1:1"); + let mut spool = Spool::new(100); + let batch = spans(5); + + spool.push(batch.clone()); + let attempt = spool.take(5); + + let err = client + .ship("inst_abc", Uuid::new_v4(), attempt.clone()) + .await + .unwrap_err(); + + assert!(err.is_retryable()); + spool.requeue(attempt); + + assert_eq!(spool.len(), 5, "the batch must survive a failed shipment"); + assert_eq!(spool.dropped(), 0, "nothing should have been discarded"); +} + +#[tokio::test] +async fn a_malformed_acknowledgement_is_reported_rather_than_panicking() { + let url = serve(Router::new().route( + "/v1/telemetry", + post(|| async { Json(serde_json::json!({"unexpected": true})) }), + )) + .await; + + match client(&url) + .ship("inst_abc", Uuid::new_v4(), spans(1)) + .await + { + Err(CloudError::InvalidAcknowledgement { detail, .. }) => { + assert!(detail.contains("ack")) + } + other => panic!("expected a rejection, got {other:?}"), + } +} diff --git a/crates/temps-cloud-client/tests/link_lifecycle_test.rs b/crates/temps-cloud-client/tests/link_lifecycle_test.rs new file mode 100644 index 000000000..bcd315e17 --- /dev/null +++ b/crates/temps-cloud-client/tests/link_lifecycle_test.rs @@ -0,0 +1,441 @@ +//! The link as an instance actually uses it, against a live stub backend. +//! +//! The property under test throughout: **an instance is never worse off for +//! having connected.** A backend that is absent, broken, or refusing must cost +//! the operator no data and no uptime — only a visible, explained degradation. + +use std::net::SocketAddr; +use std::sync::atomic::{AtomicU16, AtomicU64, AtomicUsize, Ordering}; +use std::sync::{Arc, Mutex}; + +use axum::{extract::State, routing::post, Json, Router}; +use temps_cloud_client::link::{CloudLink, FlushOutcome}; +use temps_cloud_client::status::{LinkStatus, MirrorHealth}; +use temps_cloud_client::BackendUrl; +use temps_cloud_protocol::{SpanRecord, TelemetryBatch}; +use uuid::Uuid; + +#[derive(Clone, Default)] +struct Stub { + /// Status the telemetry endpoint returns. Mutable so a test can take the + /// backend down and bring it back. + status: Arc, + received: Arc, + submissions: Arc>>, + enroll_delay_ms: Arc, +} + +async fn serve(stub: Stub) -> String { + let app = Router::new() + .route( + "/v1/enroll", + post(|State(s): State| async move { + let delay = s.enroll_delay_ms.load(Ordering::SeqCst); + if delay > 0 { + tokio::time::sleep(std::time::Duration::from_millis(delay)).await; + } + Json(serde_json::json!({ + "tenant_id": Uuid::new_v4(), + "instance_token": "inst_live" + })) + }), + ) + .route( + "/v1/telemetry", + post( + |State(s): State, Json(batch): Json| async move { + s.submissions + .lock() + .unwrap_or_else(|p| p.into_inner()) + .push(batch.submission_id); + let code = s.status.load(Ordering::SeqCst); + if code != 200 { + return ( + axum::http::StatusCode::from_u16(code).unwrap(), + Json(serde_json::json!({"detail": "stub failure"})), + ); + } + let n = batch.spans.len(); + s.received.fetch_add(n, Ordering::SeqCst); + ( + axum::http::StatusCode::OK, + Json(serde_json::json!({ + "submission_id": batch.submission_id, + "processed_spans": n, + "stored_spans": n, + "metered_bytes": 1 + })), + ) + }, + ), + ) + .with_state(stub); + + let listener = tokio::net::TcpListener::bind::("127.0.0.1:0".parse().unwrap()) + .await + .unwrap(); + let addr = listener.local_addr().unwrap(); + tokio::spawn(async move { + let _ = axum::serve(listener, app).await; + }); + format!("http://{addr}") +} + +fn spans(n: usize) -> Vec { + (0..n) + .map(|i| SpanRecord { + trace_id: "t".into(), + span_id: format!("s{i}"), + name: "GET /".into(), + ts_millis: i as i64, + duration_ms: 1.0, + attributes: Default::default(), + }) + .collect() +} + +fn link(dir: &tempfile::TempDir) -> CloudLink { + CloudLink::load_for_loopback_development(dir.path().to_path_buf(), "0.1.0-test") +} + +fn backend(url: &str) -> BackendUrl { + BackendUrl::loopback_development(url).unwrap() +} + +#[tokio::test] +async fn a_fresh_instance_is_unconfigured_and_says_so() { + let d = tempfile::tempdir().unwrap(); + let l = link(&d); + + assert_eq!(l.status(), LinkStatus::NotConfigured); + assert!( + !l.status().needs_attention(), + "an unlinked instance is not a problem" + ); + assert!(l.status().message().contains("locally")); +} + +#[tokio::test] +async fn telemetry_is_not_buffered_before_the_instance_is_linked() { + // Buffering for a backend that does not exist would burn memory for + // nothing. Local storage is unaffected either way. + let d = tempfile::tempdir().unwrap(); + let l = link(&d); + + l.record(spans(100)); + + assert_eq!(l.spooled(), 0); + assert_eq!(l.flush().await, FlushOutcome::NotLinked); +} + +#[tokio::test] +async fn the_full_lifecycle_configure_enroll_record_flush() { + let d = tempfile::tempdir().unwrap(); + let stub = Stub { + status: Arc::new(AtomicU16::new(200)), + ..Default::default() + }; + let url = serve(stub.clone()).await; + + let l = link(&d); + l.configure(backend(&url)).unwrap(); + assert!( + l.status().needs_attention(), + "a configured-but-unlinked instance should ask the operator to finish" + ); + + l.enroll("abcd-2345").await.expect("enroll"); + assert!(matches!(l.status(), LinkStatus::Linked { .. })); + + l.record(spans(3)); + assert_eq!(l.flush().await, FlushOutcome::Shipped { spans: 3 }); + + assert_eq!(stub.received.load(Ordering::SeqCst), 3); + assert_eq!(l.spooled(), 0); + assert_eq!(l.health(), MirrorHealth::Healthy); +} + +#[tokio::test] +async fn concurrent_flushes_ship_each_submission_once() { + let d = tempfile::tempdir().unwrap(); + let stub = Stub { + status: Arc::new(AtomicU16::new(200)), + ..Default::default() + }; + let url = serve(stub.clone()).await; + let link = Arc::new(link(&d)); + link.configure(backend(&url)).unwrap(); + link.enroll("abcd-2345").await.unwrap(); + link.record(spans(3)); + + let first = tokio::spawn({ + let link = link.clone(); + async move { link.flush().await } + }); + let second = tokio::spawn({ + let link = link.clone(); + async move { link.flush().await } + }); + let outcomes = [first.await.unwrap(), second.await.unwrap()]; + + assert!(outcomes.contains(&FlushOutcome::Shipped { spans: 3 })); + assert!(outcomes.contains(&FlushOutcome::Idle)); + assert_eq!(stub.received.load(Ordering::SeqCst), 3); + assert_eq!( + stub.submissions + .lock() + .unwrap_or_else(|p| p.into_inner()) + .len(), + 1 + ); +} + +#[tokio::test] +async fn an_enrollment_response_cannot_cross_an_origin_change() { + let d = tempfile::tempdir().unwrap(); + let first = serve(Stub { + status: Arc::new(AtomicU16::new(200)), + enroll_delay_ms: Arc::new(AtomicU64::new(100)), + ..Default::default() + }) + .await; + let second = serve(Stub { + status: Arc::new(AtomicU16::new(200)), + ..Default::default() + }) + .await; + let link = Arc::new(link(&d)); + link.configure(backend(&first)).unwrap(); + + let enrollment = tokio::spawn({ + let link = link.clone(); + async move { link.enroll("abcd-2345").await } + }); + tokio::time::sleep(std::time::Duration::from_millis(25)).await; + link.configure(backend(&second)).unwrap(); + + let error = enrollment.await.unwrap().unwrap_err().to_string(); + assert!(error.contains("state changed"), "unexpected error: {error}"); + assert!(matches!( + link.status(), + LinkStatus::AwaitingEnrollment { .. } + )); +} + +#[tokio::test] +async fn an_outage_buffers_and_a_recovery_drains_without_loss() { + // The everyday failure, start to finish. + let d = tempfile::tempdir().unwrap(); + let stub = Stub { + status: Arc::new(AtomicU16::new(200)), + ..Default::default() + }; + let url = serve(stub.clone()).await; + + let l = link(&d); + l.configure(backend(&url)).unwrap(); + l.enroll("abcd-2345").await.unwrap(); + + // Backend goes down. + stub.status.store(503, Ordering::SeqCst); + l.record(spans(4)); + + let outcome = l.flush().await; + assert!(matches!(outcome, FlushOutcome::Retained { spans: 4, .. })); + assert_eq!(l.spooled(), 4, "nothing may be lost to a transient failure"); + + match l.health() { + MirrorHealth::Buffering { spooled, .. } => assert_eq!(spooled, 4), + other => panic!("expected Buffering, got {other:?}"), + } + assert!(!l.health().is_losing_data()); + assert!(l + .health() + .message() + .contains("Source telemetry remains in local Temps storage")); + + // Backend recovers. + stub.status.store(200, Ordering::SeqCst); + assert_eq!(l.flush().await, FlushOutcome::Shipped { spans: 4 }); + assert_eq!(stub.received.load(Ordering::SeqCst), 4); + let submissions = stub.submissions.lock().unwrap_or_else(|p| p.into_inner()); + assert_eq!(submissions.len(), 2); + assert_eq!(submissions[0], submissions[1], "retry changed its id"); + assert_eq!(l.health(), MirrorHealth::Healthy); +} + +#[tokio::test] +async fn changing_backend_origin_revokes_the_existing_credential() { + let d = tempfile::tempdir().unwrap(); + let first = serve(Stub { + status: Arc::new(AtomicU16::new(200)), + ..Default::default() + }) + .await; + let second = serve(Stub { + status: Arc::new(AtomicU16::new(200)), + ..Default::default() + }) + .await; + + let l = link(&d); + l.configure(backend(&first)).unwrap(); + l.enroll("abcd-2345").await.unwrap(); + assert!(matches!(l.status(), LinkStatus::Linked { .. })); + l.record(spans(2)); + assert_eq!(l.spooled(), 2); + + l.configure(backend(&second)).unwrap(); + + assert!(matches!(l.status(), LinkStatus::AwaitingEnrollment { .. })); + assert_eq!( + l.spooled(), + 0, + "telemetry buffered for one origin must not cross to another" + ); + l.record(spans(1)); + assert_eq!(l.flush().await, FlushOutcome::NotLinked); +} + +#[tokio::test] +async fn a_rejected_credential_retains_the_batch_for_reenrollment() { + let d = tempfile::tempdir().unwrap(); + let stub = Stub { + status: Arc::new(AtomicU16::new(401)), + ..Default::default() + }; + let url = serve(stub.clone()).await; + + let l = link(&d); + l.configure(backend(&url)).unwrap(); + l.enroll("abcd-2345").await.unwrap(); + l.record(spans(2)); + + match l.flush().await { + FlushOutcome::Retained { spans: 2, reason } => { + assert!( + reason.contains("re-enroll"), + "must tell the operator what to do: {reason}" + ); + } + other => panic!("expected Retained, got {other:?}"), + } + + assert_eq!(l.spooled(), 2, "re-enrollment can repair the credential"); +} + +#[tokio::test] +async fn the_credential_survives_a_restart() { + let d = tempfile::tempdir().unwrap(); + let url = serve(Stub { + status: Arc::new(AtomicU16::new(200)), + ..Default::default() + }) + .await; + + let id = { + let l = link(&d); + l.configure(backend(&url)).unwrap(); + l.enroll("abcd-2345").await.unwrap(); + l.instance_id().unwrap() + }; + + // Simulated restart: a new CloudLink over the same directory. + let reloaded = link(&d); + assert!(matches!(reloaded.status(), LinkStatus::Linked { .. })); + assert_eq!( + reloaded.instance_id().unwrap(), + id, + "instance identity must be stable across restarts" + ); +} + +#[tokio::test] +async fn disconnecting_clears_the_credential_but_keeps_the_identity() { + let d = tempfile::tempdir().unwrap(); + let url = serve(Stub { + status: Arc::new(AtomicU16::new(200)), + ..Default::default() + }) + .await; + + let l = link(&d); + l.configure(backend(&url)).unwrap(); + l.enroll("abcd-2345").await.unwrap(); + let id = l.instance_id().unwrap(); + l.record(spans(5)); + + l.disconnect().unwrap(); + + assert!(matches!(l.status(), LinkStatus::AwaitingEnrollment { .. })); + assert_eq!( + l.spooled(), + 0, + "buffered data for a severed link is pointless" + ); + assert_eq!(l.instance_id().unwrap(), id, "re-linking must reattach"); +} + +#[tokio::test] +async fn a_corrupt_state_file_leaves_the_instance_working_and_unlinked() { + // One damaged file must never stop an instance from starting. + let d = tempfile::tempdir().unwrap(); + let state_dir = d.path().join("cloud-link"); + std::fs::create_dir_all(&state_dir).unwrap(); + std::fs::write(state_dir.join("state.json"), "{ truncated").unwrap(); + + let l = link(&d); + assert_eq!(l.status(), LinkStatus::NotConfigured); + l.record(spans(10)); // must not panic + assert_eq!(l.flush().await, FlushOutcome::NotLinked); +} + +#[tokio::test] +async fn flushing_an_empty_spool_is_idle_not_an_error() { + let d = tempfile::tempdir().unwrap(); + let url = serve(Stub { + status: Arc::new(AtomicU16::new(200)), + ..Default::default() + }) + .await; + + let l = link(&d); + l.configure(backend(&url)).unwrap(); + l.enroll("abcd-2345").await.unwrap(); + + assert_eq!(l.flush().await, FlushOutcome::Idle); + assert_eq!(l.health(), MirrorHealth::Healthy); +} + +#[tokio::test] +async fn a_refused_credential_becomes_a_visible_state_the_operator_must_act_on() { + // Without this the operator watches a spool that never drains and is told + // only "Linked" — the one state where waiting cannot help. + let d = tempfile::tempdir().unwrap(); + let stub = Stub { + status: Arc::new(AtomicU16::new(200)), + ..Default::default() + }; + let url = serve(stub.clone()).await; + + let l = link(&d); + l.configure(backend(&url)).unwrap(); + l.enroll("abcd-2345").await.unwrap(); + assert!(matches!(l.status(), LinkStatus::Linked { .. })); + + stub.status.store(401, Ordering::SeqCst); + l.record(spans(1)); + l.flush().await; + + match l.status() { + LinkStatus::CredentialRejected { .. } => {} + other => panic!("expected CredentialRejected, got {other:?}"), + } + assert!(l.status().needs_attention()); + assert!(l.status().message().contains("Re-enroll")); + + // Recovering clears it. + stub.status.store(200, Ordering::SeqCst); + l.enroll("abcd-2345").await.unwrap(); + assert!(matches!(l.status(), LinkStatus::Linked { .. })); +} diff --git a/crates/temps-cloud-protocol/Cargo.toml b/crates/temps-cloud-protocol/Cargo.toml new file mode 100644 index 000000000..2c74c665b --- /dev/null +++ b/crates/temps-cloud-protocol/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "temps-cloud-protocol" +version.workspace = true +edition.workspace = true +license.workspace = true +description = "Wire protocol between a self-hosted Temps instance and an optional managed backend." + +[dependencies] +serde.workspace = true +serde_json.workspace = true +chrono.workspace = true +# `serde` is not in the workspace uuid feature set, but every identifier on this +# wire protocol is a Uuid, so it is enabled here rather than widened globally. +uuid = { workspace = true, features = ["serde"] } +thiserror.workspace = true diff --git a/crates/temps-cloud-protocol/src/lib.rs b/crates/temps-cloud-protocol/src/lib.rs new file mode 100644 index 000000000..3d11308f7 --- /dev/null +++ b/crates/temps-cloud-protocol/src/lib.rs @@ -0,0 +1,168 @@ +//! Wire protocol between a self-hosted Temps instance and an optional managed +//! backend. +//! +//! This crate is deliberately public and dependency-light. An operator running +//! a self-hosted instance must be able to read exactly what their instance +//! would send before deciding to connect anything. +//! +//! # Design constraints +//! +//! A released binary cannot be recalled, and instances are never force-upgraded. +//! Old versions will be talking to the backend for years. Two rules follow: +//! +//! 1. **Negotiate, never assume.** Every connection opens with [`Hello`], +//! which carries the protocol version and a capability set. Neither side +//! may use a capability the other did not advertise. +//! 2. **Additive changes only.** New fields are optional with defaults; new +//! message kinds are ignored by peers that do not know them. Removing or +//! repurposing a field requires a new [`PROTOCOL_VERSION`]. +//! +//! # Boundaries +//! +//! This channel is a *control* plane: config, heartbeat, health, enrollment. +//! It never carries end-user application traffic, and the managed backend is +//! never in the request path of a deployed app. If the backend is unreachable, +//! the instance continues on its cached configuration. + +#![forbid(unsafe_code)] + +pub mod messages; + +pub use messages::{ + BackupCompleted, BackupTarget, BackupTargetRequest, EnrollRequest, EnrollResponse, Envelope, + Heartbeat, IngestAck, SpanRecord, TelemetryBatch, +}; + +use serde::{Deserialize, Serialize}; + +/// Bumped only for a breaking change. Additive changes must not bump it. +pub const PROTOCOL_VERSION: u16 = 1; + +/// A capability one side is willing to use. Absent = unsupported; the peer +/// must fall back rather than error. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +#[non_exhaustive] +pub enum Capability { + /// Instance may ship telemetry to the managed backend for longer retention + /// than local storage provides. Local storage is unaffected either way. + TelemetryShipping, + /// Instance may have backups orchestrated centrally. Backup bytes always + /// travel instance -> object storage directly, never through the backend. + BackupOrchestration, + /// Instance accepts managed DNS records and certificate material for a + /// subdomain issued by the backend. + ManagedSubdomain, +} + +/// First frame on every connection, sent by both sides. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Hello { + pub protocol_version: u16, + /// Human-readable build identifier, for support and skew diagnostics. + pub agent_version: String, + /// What this side is willing to do. The effective set is the intersection. + pub capabilities: Vec, +} + +impl Hello { + /// Capabilities usable on this connection: the intersection of both sides. + /// + /// Returns an error only for an incompatible major protocol version -- + /// a capability the peer lacks is a normal, non-fatal outcome. + pub fn negotiate(&self, peer: &Hello) -> Result, ProtocolError> { + if peer.protocol_version != PROTOCOL_VERSION { + return Err(ProtocolError::VersionMismatch { + ours: PROTOCOL_VERSION, + theirs: peer.protocol_version, + }); + } + Ok(self + .capabilities + .iter() + .copied() + .filter(|c| peer.capabilities.contains(c)) + .collect()) + } +} + +/// Why a managed feature is unavailable, so the instance can say something +/// specific instead of failing silently or showing a generic error. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(tag = "reason", rename_all = "snake_case")] +#[non_exhaustive] +pub enum Unavailable { + /// No account is connected. The instance should offer to connect one. + NotEnrolled, + /// Enrolled, but the plan does not include this capability. + NotEntitled { required_plan: String }, + /// Included, but the period allowance is exhausted. + QuotaExhausted { + used_bytes: u64, + limit_bytes: u64, + resets_at: chrono::DateTime, + }, + /// Backend reachable but degraded. The instance keeps buffering locally. + Degraded { + retry_after_secs: u32, + detail: String, + }, +} + +#[derive(Debug, thiserror::Error)] +pub enum ProtocolError { + #[error("protocol version mismatch: ours {ours}, peer {theirs}")] + VersionMismatch { ours: u16, theirs: u16 }, +} + +#[cfg(test)] +mod tests { + use super::*; + + fn hello(caps: &[Capability]) -> Hello { + Hello { + protocol_version: PROTOCOL_VERSION, + agent_version: "test".into(), + capabilities: caps.to_vec(), + } + } + + #[test] + fn negotiate_yields_the_intersection() { + let ours = hello(&[ + Capability::TelemetryShipping, + Capability::BackupOrchestration, + ]); + let theirs = hello(&[Capability::TelemetryShipping, Capability::ManagedSubdomain]); + assert_eq!( + ours.negotiate(&theirs).unwrap(), + vec![Capability::TelemetryShipping] + ); + } + + #[test] + fn a_capability_the_peer_lacks_is_not_an_error() { + let ours = hello(&[Capability::TelemetryShipping]); + let theirs = hello(&[]); + assert!(ours.negotiate(&theirs).unwrap().is_empty()); + } + + #[test] + fn version_mismatch_is_fatal() { + let ours = hello(&[]); + let mut theirs = hello(&[]); + theirs.protocol_version = PROTOCOL_VERSION + 1; + assert!(matches!( + ours.negotiate(&theirs), + Err(ProtocolError::VersionMismatch { .. }) + )); + } + + #[test] + fn unknown_message_kinds_do_not_break_deserialisation() { + // Additive-change guarantee: a peer sending a variant we do not know + // must not take down the connection. + let json = r#"{"reason":"not_enrolled"}"#; + assert!(serde_json::from_str::(json).is_ok()); + } +} diff --git a/crates/temps-cloud-protocol/src/messages.rs b/crates/temps-cloud-protocol/src/messages.rs new file mode 100644 index 000000000..3c4dfaec3 --- /dev/null +++ b/crates/temps-cloud-protocol/src/messages.rs @@ -0,0 +1,269 @@ +//! Messages exchanged over the management channel and the ingest endpoint. +//! +//! # Forward compatibility +//! +//! Every envelope carries a `kind` string rather than an externally-tagged +//! enum, so a peer that receives a kind it does not know can log and drop the +//! frame instead of failing to deserialise the connection. That property is +//! load-bearing: a v1 instance will still be talking to the backend years after +//! v3 ships, and a single unknown frame must never take the channel down. + +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +/// A framed message on the management channel. +/// +/// `payload` stays as raw JSON until `kind` has been matched, so unknown kinds +/// cost nothing to skip. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Envelope { + pub kind: String, + pub payload: serde_json::Value, +} + +impl Envelope { + pub fn new(kind: &str, payload: &T) -> Result { + Ok(Self { + kind: kind.to_string(), + payload: serde_json::to_value(payload)?, + }) + } + + /// Decode the payload, or `None` when this is not the expected kind. + /// + /// Returning `None` rather than an error for a kind mismatch is what lets + /// a receive loop skip unknown frames without special-casing each one. + pub fn decode Deserialize<'de>>(&self, kind: &str) -> Option { + if self.kind != kind { + return None; + } + serde_json::from_value(self.payload.clone()).ok() + } +} + +// --------------------------------------------------------------------------- +// Enrollment +// --------------------------------------------------------------------------- + +/// Sent once, over HTTPS, to exchange an operator-pasted enrollment code for +/// long-lived instance credentials. +#[derive(Clone, Serialize, Deserialize)] +pub struct EnrollRequest { + /// Short-lived code the operator copied from the cloud console. + pub enrollment_code: String, + /// Stable identifier the instance generates once and persists. + pub instance_id: Uuid, + /// Reported for support and skew diagnostics only — never trusted for + /// authorization decisions. + pub agent_version: String, +} + +impl std::fmt::Debug for EnrollRequest { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("EnrollRequest") + .field("enrollment_code", &"[REDACTED]") + .field("instance_id", &self.instance_id) + .field("agent_version", &self.agent_version) + .finish() + } +} + +#[derive(Clone, Serialize, Deserialize)] +pub struct EnrollResponse { + pub tenant_id: Uuid, + /// Bearer token for the management channel and the ingest endpoint. + /// Scoped to this instance and this tenant, nothing else. + pub instance_token: String, + /// What the tenant's current plan permits. May shrink on downgrade. + /// + /// Defaults to empty when absent, per the additive-changes rule: a backend + /// predating this field must still be understood, and an instance that + /// cannot tell what it is allowed to do should assume nothing rather than + /// everything. + #[serde(default)] + pub capabilities: Vec, +} + +impl std::fmt::Debug for EnrollResponse { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("EnrollResponse") + .field("tenant_id", &self.tenant_id) + .field("instance_token", &"[REDACTED]") + .field("capabilities", &self.capabilities) + .finish() + } +} + +// --------------------------------------------------------------------------- +// Telemetry +// --------------------------------------------------------------------------- + +/// One span as shipped by an instance. +/// +/// Deliberately flat and self-describing: the cloud must be able to accept a +/// batch from an instance several versions behind without a translation table. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct SpanRecord { + pub trace_id: String, + pub span_id: String, + pub name: String, + /// Milliseconds since the Unix epoch. Used for querying and retention. + /// + /// NEVER used for billing: the cloud meters on its own receive time, so a + /// wrong clock on an instance cannot move money. + pub ts_millis: i64, + pub duration_ms: f64, + #[serde(default)] + pub attributes: std::collections::BTreeMap, +} + +/// A batch posted to the ingest endpoint. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TelemetryBatch { + /// Generated by the instance before the first attempt and reused for every + /// retry of these exact bytes. The backend binds it to the authenticated + /// instance and payload digest before treating a retry as idempotent. + pub submission_id: Uuid, + pub spans: Vec, +} + +/// Ingest outcome. A client clears a submission only when the id matches and +/// `processed_spans` covers the entire attempted batch. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct IngestAck { + pub submission_id: Uuid, + /// Records fully handled by the gateway and safe to remove client-side. + pub processed_spans: usize, + /// Records retained after quota sampling. May be lower than `processed`. + pub stored_spans: usize, + /// Bytes the cloud will bill for — echoed back so the operator can + /// reconcile their own figure against the invoice. + pub metered_bytes: u64, + /// Present when the batch was accepted but the tenant is degraded, e.g. + /// over quota and now sampling. The instance must surface this, not hide it. + #[serde(skip_serializing_if = "Option::is_none")] + pub warning: Option, +} + +// --------------------------------------------------------------------------- +// Backups +// --------------------------------------------------------------------------- + +/// Instance asks where to put a backup. +/// +/// The cloud replies with a presigned destination; backup bytes then travel +/// instance -> object storage **directly**. They never transit the control +/// plane, which is what keeps our bandwidth cost at zero and stops us becoming +/// a throughput bottleneck. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BackupTargetRequest { + pub instance_id: Uuid, + /// What is being backed up, e.g. a service or database name. + pub source: String, + pub estimated_bytes: u64, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BackupTarget { + pub backup_id: Uuid, + /// Presigned PUT destination, scoped to this object key alone. + pub upload_url: String, + pub object_key: String, + pub expires_at_millis: i64, +} + +/// Instance reports the upload finished. Until this arrives the object is not +/// a backup: a partial multipart upload must never be counted as one. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BackupCompleted { + pub backup_id: Uuid, + pub bytes: u64, + /// SHA-256 of the uploaded object, so restore can detect corruption before + /// the customer discovers it during an actual disaster. + pub checksum_sha256: String, +} + +// --------------------------------------------------------------------------- +// Liveness +// --------------------------------------------------------------------------- + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Heartbeat { + pub instance_id: Uuid, + /// Reported so the cloud can keep a DNS A record current for instances + /// with dynamic addresses. + #[serde(skip_serializing_if = "Option::is_none")] + pub public_ip: Option, + /// Local spool depth. A growing value is the signal that the instance is + /// buffering because we are failing it. + pub pending_spool_bytes: u64, +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn envelope_round_trips() { + let hb = Heartbeat { + instance_id: Uuid::nil(), + public_ip: None, + pending_spool_bytes: 42, + }; + let env = Envelope::new("heartbeat", &hb).unwrap(); + let back: Heartbeat = env.decode("heartbeat").unwrap(); + assert_eq!(back.pending_spool_bytes, 42); + } + + #[test] + fn unknown_kind_decodes_to_none_rather_than_erroring() { + // The forward-compatibility guarantee: a v1 peer receiving a v3 frame + // must be able to skip it and keep the channel open. + let env = Envelope::new("some_future_kind", &serde_json::json!({"x": 1})).unwrap(); + assert!(env.decode::("heartbeat").is_none()); + } + + #[test] + fn span_attributes_default_when_absent() { + // Older instances predate `attributes`; their batches must still parse. + let json = r#"{ + "trace_id":"t","span_id":"s","name":"GET /", + "ts_millis":1700000000000,"duration_ms":1.5 + }"#; + let span: SpanRecord = serde_json::from_str(json).unwrap(); + assert!(span.attributes.is_empty()); + } + + #[test] + fn ingest_ack_omits_warning_when_healthy() { + let ack = IngestAck { + submission_id: Uuid::new_v4(), + processed_spans: 3, + stored_spans: 3, + metered_bytes: 100, + warning: None, + }; + let s = serde_json::to_string(&ack).unwrap(); + assert!( + !s.contains("warning"), + "healthy ack should not carry a warning key: {s}" + ); + } + + #[test] + fn enrollment_debug_output_redacts_credentials() { + let request = EnrollRequest { + enrollment_code: "secret-code".into(), + instance_id: Uuid::new_v4(), + agent_version: "test".into(), + }; + let response = EnrollResponse { + tenant_id: Uuid::new_v4(), + instance_token: "inst_secret".into(), + capabilities: vec![], + }; + + assert!(!format!("{request:?}").contains("secret-code")); + assert!(!format!("{response:?}").contains("inst_secret")); + } +} From 3271c3fc9900d10fb51b8ac53596752fd70a966c Mon Sep 17 00:00:00 2001 From: David Viejo Date: Wed, 5 Aug 2026 13:58:29 +0200 Subject: [PATCH 2/9] feat(cloud): add managed cloud link lifecycle and console settings Adds the temps-cloud crate (plugin, handler, service), extends the cloud client's link lifecycle and status, exposes a Cloud settings page in the console, and grows the CLI's cloud commands. Committed as-is from the worktree so main can be merged in with a real three-way merge rather than a stash replay. --- CHANGELOG.md | 1 + Cargo.lock | 24 ++ Cargo.toml | 1 + apps/temps-cli/openapi.json | 2 +- apps/temps-cli/src/api/index.ts | 4 +- apps/temps-cli/src/api/sdk.gen.ts | 30 +- apps/temps-cli/src/api/types.gen.ts | 100 ++++++ apps/temps-cli/src/commands/cloud/index.ts | 74 +++- apps/temps-cli/src/commands/env-sync/index.ts | 11 +- .../src/commands/environments/index.ts | 11 +- .../src/commands/notifications/index.ts | 4 +- .../temps-cli/src/commands/providers/index.ts | 6 +- crates/temps-cli/Cargo.toml | 1 + .../temps-cli/src/commands/serve/console.rs | 20 +- crates/temps-cloud-client/src/lib.rs | 35 ++ crates/temps-cloud-client/src/link.rs | 118 +++++- crates/temps-cloud-client/src/state.rs | 3 + crates/temps-cloud-client/src/status.rs | 7 +- .../tests/link_lifecycle_test.rs | 82 ++++- crates/temps-cloud/Cargo.toml | 25 ++ crates/temps-cloud/src/handler.rs | 173 +++++++++ crates/temps-cloud/src/lib.rs | 11 + crates/temps-cloud/src/plugin.rs | 86 +++++ crates/temps-cloud/src/service.rs | 233 ++++++++++++ crates/temps-core/src/app_settings.rs | 21 ++ crates/temps-otel/Cargo.toml | 3 + crates/temps-otel/src/plugin.rs | 15 +- .../temps-otel/src/services/otel_service.rs | 102 ++++++ web/e2e/authenticated/ai-cloud-entry.spec.ts | 94 +++++ .../authenticated/cloud-onboarding.spec.ts | 97 +++++ web/src/App.tsx | 8 +- .../api/client/@tanstack/react-query.gen.ts | 62 +++- web/src/api/client/index.ts | 4 +- web/src/api/client/sdk.gen.ts | 30 +- web/src/api/client/types.gen.ts | 100 ++++++ web/src/components/ai/AiAssistantButton.tsx | 20 +- web/src/components/ai/AiAssistantDock.tsx | 13 +- web/src/components/ai/AiAssistantGate.tsx | 151 ++++++++ web/src/components/dashboard/Sidebar.tsx | 1 + web/src/pages/settings/CloudSettingsPage.tsx | 335 ++++++++++++++++++ 40 files changed, 2037 insertions(+), 81 deletions(-) create mode 100644 crates/temps-cloud/Cargo.toml create mode 100644 crates/temps-cloud/src/handler.rs create mode 100644 crates/temps-cloud/src/lib.rs create mode 100644 crates/temps-cloud/src/plugin.rs create mode 100644 crates/temps-cloud/src/service.rs create mode 100644 web/e2e/authenticated/ai-cloud-entry.spec.ts create mode 100644 web/e2e/authenticated/cloud-onboarding.spec.ts create mode 100644 web/src/components/ai/AiAssistantGate.tsx create mode 100644 web/src/pages/settings/CloudSettingsPage.tsx diff --git a/CHANGELOG.md b/CHANGELOG.md index 26e763824..2cc852809 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **Credential reveal boundaries:** Mask environment variables, container configuration, external-service parameters, notification providers, MCP servers, and legacy agent tool credentials by default; plaintext now requires an explicit, audited, non-cacheable reveal request ### Added +- **Temps Cloud:** Connect a self-hosted instance to the optional managed control plane in two steps from Settings, mirror OpenTelemetry spans without putting the managed service on the ingest path, and surface connection, buffering, and credential health through the console and CLI. - **providers:** Reset all accumulated `pg_stat_statements` statistics from the Query Performance page through a write-protected, audited API with explicit destructive-action confirmation. - **providers:** `pg_stat_statements`-based slow-query monitoring for user-provisioned Postgres services — a dedicated "Query Performance" page (sortable, paginated, with a per-query detail view) alongside a `GET /external-services/{id}/pg-stat-statements/slow-queries` endpoint and a `temps services slow-queries --id ` CLI command ([#460](https://github.com/gotempsh/temps/pull/460)) - **providers:** self-service "Enable & Restart" action to load `pg_stat_statements` on standalone Postgres services that predate this feature — clustered/HA services are rejected with a clear error instead, since a blind single-container restart bypasses controlled failover ([#460](https://github.com/gotempsh/temps/pull/460)) diff --git a/Cargo.lock b/Cargo.lock index 4c50f0a15..897e2d649 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10636,6 +10636,7 @@ dependencies = [ "temps-auth", "temps-backup", "temps-blob", + "temps-cloud", "temps-config", "temps-core", "temps-database", @@ -10695,6 +10696,26 @@ dependencies = [ "x509-parser", ] +[[package]] +name = "temps-cloud" +version = "0.1.0-beta.55" +dependencies = [ + "anyhow", + "axum", + "serde", + "serde_json", + "tempfile", + "temps-auth", + "temps-cloud-client", + "temps-config", + "temps-core", + "thiserror 2.0.19", + "tokio", + "tracing", + "utoipa", + "uuid", +] + [[package]] name = "temps-cloud-client" version = "0.1.0-beta.55" @@ -12018,8 +12039,11 @@ dependencies = [ "serde", "serde_json", "sha2 0.11.0", + "tempfile", "temps-ai", "temps-auth", + "temps-cloud-client", + "temps-cloud-protocol", "temps-config", "temps-core", "temps-database", diff --git a/Cargo.toml b/Cargo.toml index 94fbfe2ae..7cb6e581f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ members = [ "crates/temps-core", "crates/temps-cloud-protocol", "crates/temps-cloud-client", + "crates/temps-cloud", "crates/temps-ai", "crates/temps-ai-chat", "crates/temps-entities", diff --git a/apps/temps-cli/openapi.json b/apps/temps-cli/openapi.json index 713698cf4..73dd1a602 100644 --- a/apps/temps-cli/openapi.json +++ b/apps/temps-cli/openapi.json @@ -1 +1 @@ -{"openapi":"3.1.0","info":{"title":"Temps","description":"An API for managing projects, deployments, and infrastructure resources","contact":{"name":"Temps Support","url":"https://temps.sh"},"version":"1.0.0"},"servers":[{"url":"/api","description":"Base path for all API endpoints"}],"paths":{"/.well-known/temps.json":{"get":{"tags":["Platform"],"summary":"Get platform information","operationId":"get_platform_info","responses":{"200":{"description":"Successfully retrieved platform information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlatformInfo"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/0/organizations/{org_slug}/chunk-upload/":{"get":{"tags":["sentry-compat"],"summary":"Chunk upload options (stub for sentry-cli compatibility).","description":"sentry-cli checks this endpoint to determine if chunk-based upload is supported.\nWe return a response indicating that chunk upload is NOT supported, which forces\nsentry-cli to fall back to the standard file-by-file upload.","operationId":"chunk_upload_options","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Chunk upload options","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryChunkUploadResponse"}}}}}}},"/0/organizations/{org_slug}/releases/":{"post":{"tags":["sentry-compat"],"summary":"Create a release (stub for sentry-cli compatibility).","description":"sentry-cli calls this before uploading files. Since Temps implicitly creates\nreleases when source maps are uploaded, this is a no-op that returns the\nexpected response format.","operationId":"create_release","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored in single-tenant mode)","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryCreateReleaseRequest"}}},"required":true},"responses":{"201":{"description":"Release created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryReleaseResponse"}}}},"401":{"description":"Unauthorized"}}}},"/0/projects/{org_slug}/{project_slug}/releases/":{"post":{"tags":["sentry-compat"],"summary":"Create a release for a specific project (stub for sentry-cli compatibility).","description":"sentry-cli calls this endpoint (instead of /organizations/.../releases/) when\nboth SENTRY_ORG and SENTRY_PROJECT env vars are set. Behaves identically to\nthe organizations endpoint but validates the project slug.","operationId":"create_project_release","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored in single-tenant mode)","required":true,"schema":{"type":"string"}},{"name":"project_slug","in":"path","description":"Project slug or numeric ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryCreateReleaseRequest"}}},"required":true},"responses":{"201":{"description":"Release created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryReleaseResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"}}}},"/0/projects/{org_slug}/{project_slug}/releases/{version}/":{"put":{"tags":["sentry-compat"],"summary":"Finalize a release (stub for sentry-cli compatibility).","description":"sentry-cli calls `releases finalize` after uploading source maps. This sets\nthe dateReleased on the release. Since Temps stores source maps independently\nof releases, this is a no-op that returns the expected response.","operationId":"finalize_project_release","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored)","required":true,"schema":{"type":"string"}},{"name":"project_slug","in":"path","description":"Project slug or numeric ID","required":true,"schema":{"type":"string"}},{"name":"version","in":"path","description":"Release version to finalize","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Release finalized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryReleaseResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"}}}},"/0/projects/{org_slug}/{project_slug}/releases/{version}/files/":{"get":{"tags":["sentry-compat"],"summary":"List files for a release.","description":"Returns all source maps stored for a specific release in sentry-cli compatible format.","operationId":"list_release_files","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored)","required":true,"schema":{"type":"string"}},{"name":"project_slug","in":"path","description":"Project slug or numeric ID","required":true,"schema":{"type":"string"}},{"name":"version","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of release files","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SentryReleaseFileResponse"}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"}}},"post":{"tags":["sentry-compat"],"summary":"Upload a source map file for a release.","description":"Accepts the same multipart format as the Sentry release files API.\nThe `name` field should be the URL path of the file (e.g., `~/dist/bundle.js.map`).\n\nThe route has a 50 MiB body limit applied at the router level (Fix #4).\nA per-field size check provides an additional defense-in-depth layer.","operationId":"upload_release_file","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored)","required":true,"schema":{"type":"string"}},{"name":"project_slug","in":"path","description":"Project slug or numeric ID","required":true,"schema":{"type":"string"}},{"name":"version","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"File uploaded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryReleaseFileResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"},"413":{"description":"Source map file exceeds the 50 MiB per-field limit"}}}},"/_temps/event":{"post":{"tags":["Metrics"],"summary":"Record analytics event","operationId":"record_event_metrics","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventMetricsPayload"}}},"required":true},"responses":{"204":{"description":"Event recorded successfully"},"400":{"description":"Bad request"},"500":{"description":"Internal server error"}}}},"/_temps/session-replay/events":{"post":{"tags":["Analytics"],"summary":"Add events to existing session replay","operationId":"add_session_replay_events","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionReplayEventsRequest"}}},"required":true},"responses":{"200":{"description":"Events added successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddEventsResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/_temps/session-replay/init":{"post":{"tags":["Analytics"],"summary":"Initialize session replay with metadata","operationId":"init_session_replay","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionReplayInitRequest"}}},"required":true},"responses":{"201":{"description":"Session initialized successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionReplayInitResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/_temps/speed":{"post":{"tags":["Performance"],"summary":"Record performance metrics from client","operationId":"record_speed_metrics","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpeedMetricsPayload"}}},"required":true},"responses":{"204":{"description":"Metrics recorded successfully"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Host not found in route table","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/_temps/speed/update":{"post":{"tags":["Performance"],"summary":"Update late performance metrics","operationId":"update_speed_metrics","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSpeedMetricsPayload"}}},"required":true},"responses":{"204":{"description":"Metrics updated successfully"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Host not found or metrics not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/admin/gate-settings":{"get":{"tags":["AdminGate"],"operationId":"get_admin_gate","responses":{"200":{"description":"Current admin gate config","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminGateResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["AdminGate"],"operationId":"patch_admin_gate","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAdminGateRequest"}}},"required":true},"responses":{"200":{"description":"Updated admin gate config","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminGateResponse"}}}},"400":{"description":"Invalid IP/CIDR/host"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"409":{"description":"Env-overridden or would lock out caller"}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers":{"get":{"tags":["Authentication"],"operationId":"list_oidc_providers","responses":{"200":{"description":"OIDC providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OidcProviderResponse"}}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Authentication"],"operationId":"create_oidc_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOidcProviderRequest"}}},"required":true},"responses":{"201":{"description":"OIDC provider created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcProviderResponse"}}}},"409":{"description":"Another OIDC provider already uses that name"}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers/{provider_id}":{"delete":{"tags":["Authentication"],"operationId":"delete_oidc_provider","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"OIDC provider deleted"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Authentication"],"operationId":"update_oidc_provider","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOidcProviderRequest"}}},"required":true},"responses":{"200":{"description":"OIDC provider updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcProviderResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers/{provider_id}/role-mappings":{"get":{"tags":["Authentication"],"operationId":"list_oidc_role_mappings","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"OIDC role mappings","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OidcRoleMappingResponse"}}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Authentication"],"operationId":"create_oidc_role_mapping","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOidcRoleMappingRequest"}}},"required":true},"responses":{"201":{"description":"Role mapping created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcRoleMappingResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers/{provider_id}/test":{"post":{"tags":["Authentication"],"operationId":"test_oidc_provider","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcTestConnectionResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers/{provider_id}/users":{"get":{"tags":["Authentication"],"operationId":"list_oidc_provider_users","parameters":[{"name":"provider_id","in":"path","description":"OIDC provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Users authenticated via this OIDC provider","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OidcProviderUserResponse"}}}}},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/role-mappings/{mapping_id}":{"delete":{"tags":["Authentication"],"operationId":"delete_oidc_role_mapping","parameters":[{"name":"mapping_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Role mapping deleted"}},"security":[{"bearer_auth":[]}]}},"/agents/webhook/{webhook_id}":{"post":{"tags":["Agents"],"summary":"Public webhook endpoint. Authenticated via `X-Webhook-Token` header.","description":"`POST /api/agents/webhook/{webhook_id}`\nHeader: `X-Webhook-Token: `\n\nThe `webhook_id` in the URL is a short non-secret identifier (safe to log).\nThe actual credential is the secret token in the header.\n\nAccepts any JSON body, which is passed as `user_context` to the agent run.","operationId":"webhook_trigger","parameters":[{"name":"webhook_id","in":"path","description":"Webhook ID (non-secret)","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookTriggerRequest"}}},"required":true},"responses":{"202":{"description":"Agent run created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookTriggerResponse"}}}},"401":{"description":"Missing or invalid X-Webhook-Token header"},"404":{"description":"Invalid webhook ID"},"422":{"description":"Agent disabled"}}}},"/ai/conversations":{"get":{"tags":["AI Chat"],"summary":"List every active conversation across all projects, most-recently-active\nfirst, annotated with project name/slug. Powers the unified \"all chats\"\nswitcher in the AI assistant dock.","operationId":"list_all_conversations","responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GlobalConversationResponse"}}}}},"401":{"description":""},"403":{"description":""}},"security":[{"bearer_auth":[]}]}},"/ai/pricing":{"get":{"tags":["AI Gateway Pricing"],"operationId":"get_pricing","responses":{"200":{"description":"Model pricing information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PricingResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/providers":{"get":{"tags":["AI Gateway Admin"],"operationId":"list_provider_keys","responses":{"200":{"description":"List of provider keys","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderKeyResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["AI Gateway Admin"],"operationId":"create_provider_key","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProviderKeyRequest"}}},"required":true},"responses":{"201":{"description":"Provider key created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderKeyResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/providers/test":{"post":{"tags":["AI Gateway Admin"],"operationId":"test_provider_key_inline","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestProviderKeyRequest"}}},"required":true},"responses":{"200":{"description":"Test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestProviderKeyResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/providers/{id}":{"delete":{"tags":["AI Gateway Admin"],"operationId":"delete_provider_key","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Provider key deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["AI Gateway Admin"],"operationId":"update_provider_key","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProviderKeyRequest"}}},"required":true},"responses":{"200":{"description":"Provider key updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderKeyResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/providers/{id}/test":{"post":{"tags":["AI Gateway Admin"],"operationId":"test_provider_key_by_id","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestProviderKeyResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Provider key not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/by-provider":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_by_provider","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Usage broken down by provider","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderUsage"}}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/conversations":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_conversations","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max results (defaults to 50, max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"user_id","in":"query","description":"Filter by user ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"tags","in":"query","description":"Filter by tags (comma-separated)","required":false,"schema":{"type":"string"}},{"name":"model","in":"query","description":"Filter by model name","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Conversation summaries","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ConversationSummary"}}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/conversations/{conversation_id}":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_conversation_detail","parameters":[{"name":"conversation_id","in":"path","description":"Conversation ID","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max results (defaults to 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Invocations within a conversation","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UsageLogEntry"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/recent":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_recent","parameters":[{"name":"limit","in":"query","description":"Page size (defaults to 20, max 50)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Number of results to skip for pagination (defaults to 0)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"provider","in":"query","description":"Filter by provider name","required":false,"schema":{"type":"string"}},{"name":"model","in":"query","description":"Filter by model name","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Filter by HTTP status code (exact match)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"cost_gte","in":"query","description":"Cost greater-than-or-equal, in microcents","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"cost_gt","in":"query","description":"Cost strictly greater-than, in microcents","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"cost_lte","in":"query","description":"Cost less-than-or-equal, in microcents","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"cost_lt","in":"query","description":"Cost strictly less-than, in microcents","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tokens_gte","in":"query","description":"Total tokens greater-than-or-equal","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tokens_gt","in":"query","description":"Total tokens strictly greater-than","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tokens_lte","in":"query","description":"Total tokens less-than-or-equal","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tokens_lt","in":"query","description":"Total tokens strictly less-than","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Page of recent usage log entries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageLogPage"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/summary":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_summary","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Usage summary for the time range","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageSummary"}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/timeseries":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_timeseries","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}},{"name":"bucket","in":"query","description":"Bucket size: hour, day, week (defaults to day)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Time-series usage data","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TimeseriesBucket"}}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/top-models":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_top_models","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max results (defaults to 10)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Top models by request count","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ModelUsage"}}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/v1/chat/completions":{"post":{"tags":["AI Gateway"],"operationId":"chat_completions","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatCompletionRequest"}}},"required":true},"responses":{"200":{"description":"Chat completion response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatCompletionResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"404":{"description":"Model not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/v1/embeddings":{"post":{"tags":["AI Gateway"],"operationId":"embeddings","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmbeddingRequest"}}},"required":true},"responses":{"200":{"description":"Embedding response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmbeddingResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"404":{"description":"Model not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/v1/models":{"get":{"tags":["AI Gateway"],"operationId":"list_models","responses":{"200":{"description":"List of available models","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/analytics/active-visitors":{"get":{"tags":["Analytics"],"summary":"Get detailed active visitors","operationId":"get_analytics_active_visitors","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Deployment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"window_minutes","in":"query","description":"Time window in minutes for active visitors (default: 5)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved active visitors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActiveVisitorsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/event-detail":{"get":{"tags":["Analytics"],"summary":"Get detailed analytics for a specific event","operationId":"get_event_detail","parameters":[{"name":"event_name","in":"query","description":"Event name to get details for","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"bucket_interval","in":"query","description":"Bucket interval: hour, day, week, month (default: auto)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved event details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventDetailResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/event-entries":{"get":{"tags":["Analytics"],"summary":"Get paginated list of raw occurrences of a specific event, including custom JSON properties","operationId":"get_event_entries","parameters":[{"name":"event_name","in":"query","description":"Event name to list occurrences for","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (1-based, default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Successfully retrieved event entries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventEntriesResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/event-visitors":{"get":{"tags":["Analytics"],"summary":"Get paginated list of visitors who triggered a specific event","operationId":"get_event_visitors","parameters":[{"name":"event_name","in":"query","description":"Event name to list visitors for","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (1-based, default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Successfully retrieved event visitors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventVisitorsResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/events":{"get":{"tags":["Analytics"],"operationId":"get_analytics_events_count","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Maximum number of results to return","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"custom_events_only","in":"query","description":"Only return custom events, excluding system events like page_view, page_leave, heartbeat (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"breakdown","in":"query","description":"Breakdown by geography: 'country', 'region', or 'city' (optional)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved event counts","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventCount"}}}}},"400":{"description":"Invalid date format, missing required parameters, or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/general-stats":{"get":{"tags":["Analytics"],"summary":"Get general statistics across all projects for a time frame","operationId":"get_general_stats","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_ids","in":"query","description":"Optional: Filter by specific project IDs (comma-separated)","required":false,"schema":{"type":"array","items":{"type":"integer","format":"int32"}}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"include_project_breakdown","in":"query","description":"Whether to include per-project breakdown (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Successfully retrieved general statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeneralStatsResponse"}}}},"400":{"description":"Invalid date format or parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/has-events":{"get":{"tags":["Analytics"],"operationId":"check_analytics_has_events","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Analytics events existence check","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HasAnalyticsEventsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/live-visitors":{"get":{"tags":["Analytics"],"summary":"Get list of currently live visitors from visitor table","operationId":"get_live_visitors_list","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"window_minutes","in":"query","description":"Time window in minutes for live visitors (default: 5)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved live visitors list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LiveVisitorsListResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-flow":{"get":{"tags":["Analytics"],"summary":"Get page flow analytics: entry pages, exit pages, drop-off points, and page transitions","operationId":"get_page_flow","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max entry/exit pages to return (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"transitions_limit","in":"query","description":"Max page transitions to return (default: 50, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"min_views_for_dropoff","in":"query","description":"Minimum views for drop-off analysis (default: 5)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved page flow analytics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PageFlowResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-hourly-sessions":{"get":{"tags":["Analytics"],"operationId":"get_page_hourly_sessions","parameters":[{"name":"page_path","in":"query","description":"The page path to get sessions for","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","description":"Start time in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"bucket_interval","in":"query","description":"Bucket interval: 'hour', 'day', 'week', or 'month' (default: auto-determined based on range)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved page sessions with time buckets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PageHourlySessionsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-path-detail":{"get":{"tags":["Analytics"],"summary":"Get detailed analytics for a specific page path\nReturns visitors, page views, activity over time, geographic distribution, and referrers","operationId":"get_page_path_detail","parameters":[{"name":"page_path","in":"query","description":"The page path to get details for (URL-encoded)","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"bucket_interval","in":"query","description":"Bucket interval for time series: 'hour', 'day', 'week', 'month' (default: auto based on date range)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved page path detail analytics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PagePathDetailResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-path-visitors":{"get":{"tags":["Analytics"],"summary":"Get individual visitor sessions for a specific page path","operationId":"get_page_path_visitors","parameters":[{"name":"page_path","in":"query","description":"The page path to get visitors for (URL-encoded)","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (1-based, default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Successfully retrieved page path visitors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PagePathVisitorsResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-paths":{"get":{"tags":["Analytics"],"operationId":"get_page_paths","parameters":[{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS (optional)","required":false,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS (optional)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Maximum number of page paths to return (default: 100, max: 1000)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved page paths","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PagePathsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-paths-sparklines":{"get":{"tags":["Analytics"],"operationId":"get_page_paths_sparklines","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","description":"Start time in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"page_paths","in":"query","description":"Comma-separated list of page paths","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sparkline data for all requested page paths","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PagePathsSparklineResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/recent-activity":{"get":{"tags":["Analytics"],"summary":"Get recent activity events for real-time activity feed","operationId":"get_recent_activity","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"since_id","in":"query","description":"Return events with ID greater than this (cursor-based polling)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"limit","in":"query","description":"Max events to return (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved recent activity events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecentActivityResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/sessions/{session_id}":{"get":{"tags":["Analytics"],"summary":"Get detailed information about a specific session including events and request logs","operationId":"get_session_details","parameters":[{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved session details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionDetails"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Session not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/sessions/{session_id}/events":{"get":{"tags":["Analytics"],"operationId":"get_analytics_session_events","parameters":[{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":false,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Number of results to return (default: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Number of results to skip (default: 0)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved session events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionEventsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Session not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/sessions/{session_id}/logs":{"get":{"tags":["Analytics"],"operationId":"get_session_logs","parameters":[{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":false,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Number of results to return (default: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Number of results to skip (default: 0)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved session logs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionLogsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Session not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitor-facets":{"get":{"tags":["Analytics"],"summary":"Get filter dropdown contents for the visitors page. Returns the top\nvalues per dimension with distinct visitor counts so the UI can render\n\"Country — 1,234 visitors\" rows. Each dimension is computed against the\nsegment minus its own filter, so a selected value never collapses its\nown dropdown.","operationId":"get_visitor_facets","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"include_crawlers","in":"query","description":"Include crawlers (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"has_activity_only","in":"query","description":"Hide ghost visitors (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"per_facet_limit","in":"query","description":"Top N values per dimension (default: 50, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"filter_country","in":"query","description":"Geolocation country","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Geolocation region","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Geolocation city","required":false,"schema":{"type":"string"}},{"name":"filter_channel","in":"query","description":"First-touch channel","required":false,"schema":{"type":"string"}},{"name":"filter_referrer","in":"query","description":"First-touch referrer hostname (use 'Direct' for null)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Top values per dimension","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorFacets"}}}},"400":{"description":"Invalid date format or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors":{"get":{"tags":["Analytics"],"summary":"Get list of visitors with summary information","operationId":"get_visitors","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"include_crawlers","in":"query","description":"Include crawlers (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Maximum number of visitors to return (default: 50)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Number of visitors to skip (default: 0)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"has_activity_only","in":"query","description":"Filter to only include visitors with recorded activity (events/sessions). When true, excludes ghost visitors (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"filter_country","in":"query","description":"Geolocation country","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Geolocation region","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Geolocation city","required":false,"schema":{"type":"string"}},{"name":"filter_channel","in":"query","description":"First-touch channel","required":false,"schema":{"type":"string"}},{"name":"filter_referrer","in":"query","description":"First-touch referrer hostname (use 'Direct' for null)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved visitors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorsResponse"}}}},"400":{"description":"Invalid date format, missing required parameters, or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/guid/{visitor_id}":{"get":{"tags":["Analytics"],"summary":"Get visitor by GUID with geolocation data","operationId":"get_visitor_by_guid","parameters":[{"name":"visitor_id","in":"path","description":"Visitor GUID (supports enc_ prefix for encrypted IDs)","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor with geolocation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorWithGeolocation"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/id/{id}":{"get":{"tags":["Analytics"],"summary":"Get visitor by numeric ID with geolocation data","operationId":"get_visitor_by_id","parameters":[{"name":"id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor with geolocation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorWithGeolocation"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}":{"get":{"tags":["Analytics"],"summary":"Get detailed information about a specific visitor by numeric ID","operationId":"get_visitor_details","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorDetails"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/enrich":{"put":{"tags":["Analytics"],"operationId":"enrich_visitor","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID - can be numeric ID, GUID, or encrypted GUID (enc_xxx)","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnrichVisitorRequest"}}},"required":true},"responses":{"200":{"description":"Successfully enriched visitor data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnrichVisitorResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/info":{"get":{"tags":["Analytics"],"summary":"Get visitor record from database","operationId":"get_visitor_info","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor info","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorRecord"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/journey":{"get":{"tags":["Analytics"],"summary":"Get the complete visitor journey: all events across all sessions, grouped by session","operationId":"get_visitor_journey","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"limit_sessions","in":"query","description":"Maximum number of sessions to return (default: 50)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor journey","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorJourneyResponse"}}}},"400":{"description":"Invalid parameters"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/sessions":{"get":{"tags":["Analytics"],"summary":"Get all sessions for a specific visitor by numeric ID","operationId":"get_analytics_visitor_sessions","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Maximum number of sessions to return (default: 100)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor sessions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorSessionsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/stats":{"get":{"tags":["Analytics"],"summary":"Get visitor statistics","operationId":"get_visitor_stats","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorStats"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys":{"get":{"tags":["API Keys"],"operationId":"list_api_keys","parameters":[{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default: 20)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"API keys retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["API Keys"],"operationId":"create_api_key","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyRequest"}}},"required":true},"responses":{"201":{"description":"API key created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"409":{"description":"Conflict - API key name already exists"},"428":{"description":"Recent MFA verification required"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/permissions":{"get":{"tags":["API Keys"],"operationId":"get_api_key_permissions","responses":{"200":{"description":"Available permissions and roles retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AvailablePermissions"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/{id}":{"get":{"tags":["API Keys"],"operationId":"get_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"API key retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["API Keys"],"operationId":"update_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateApiKeyRequest"}}},"required":true},"responses":{"200":{"description":"API key updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"409":{"description":"Conflict - API key name already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["API Keys"],"operationId":"delete_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"API key deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/{id}/activate":{"post":{"tags":["API Keys"],"operationId":"activate_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"API key activated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/{id}/deactivate":{"post":{"tags":["API Keys"],"operationId":"deactivate_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"API key deactivated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/{id}/rotate":{"post":{"tags":["API Keys"],"operationId":"rotate_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"API key rotated successfully; the response contains the new plaintext secret, shown only once","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"428":{"description":"Recent MFA verification required"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/auth/cli/device/approve":{"post":{"tags":["Authentication"],"operationId":"cli_device_approve","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceApproveRequest"}}},"required":true},"responses":{"200":{"description":"Session approved; CLI can now claim the API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceApproveResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Browser session required"},"404":{"description":"Unknown user_code"},"409":{"description":"Already resolved"},"410":{"description":"Session expired"},"428":{"description":"Recent MFA verification required"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/auth/cli/device/deny":{"post":{"tags":["Authentication"],"operationId":"cli_device_deny","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceApproveRequest"}}},"required":true},"responses":{"200":{"description":"Session denied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceApproveResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Unknown user_code"},"409":{"description":"Already resolved"},"410":{"description":"Session expired"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/auth/cli/device/lookup":{"get":{"tags":["Authentication"],"operationId":"cli_device_lookup","parameters":[{"name":"user_code","in":"query","description":"`user_code` as displayed in the CLI / pasted into the URL.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Device session metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceLookupResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Unknown user_code"},"410":{"description":"Device session expired"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/auth/cli/device/poll":{"post":{"tags":["Authentication"],"operationId":"cli_device_poll","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDevicePollRequest"}}},"required":true},"responses":{"200":{"description":"Poll result; check `status` field","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDevicePollResponse"}}}},"404":{"description":"Unknown device_code"},"500":{"description":"Internal server error"}}}},"/auth/cli/device/start":{"post":{"tags":["Authentication"],"operationId":"cli_device_start","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceStartRequest"}}},"required":true},"responses":{"200":{"description":"Device session created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceStartResponse"}}}},"500":{"description":"Internal server error"}}}},"/auth/cli/logout":{"post":{"tags":["Authentication"],"operationId":"cli_logout","responses":{"204":{"description":"API key revoked"},"401":{"description":"Not authenticated"},"403":{"description":"Endpoint requires API key authentication"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/auth/email-status":{"get":{"tags":["Authentication"],"operationId":"email_status","responses":{"200":{"description":"Email configuration status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailStatusResponse"}}}},"500":{"description":"Internal server error"}}}},"/auth/login":{"post":{"tags":["Authentication"],"operationId":"login","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginRequest"}}},"required":true},"responses":{"200":{"description":"Login successful, session cookie set","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"401":{"description":"Invalid credentials, or the account's role requires MFA enrollment that has not been completed"},"500":{"description":"Internal server error"}}}},"/auth/oidc/callback":{"get":{"tags":["Authentication"],"operationId":"oidc_callback","parameters":[{"name":"code","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"state","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"error","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"error_description","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"302":{"description":"Redirect to app with session cookie or login error"}}}},"/auth/oidc/login/{slug}":{"get":{"tags":["Authentication"],"operationId":"start_oidc_login_by_slug","parameters":[{"name":"slug","in":"path","description":"OIDC provider slug (from /email-status or /auth/oidc/providers)","required":true,"schema":{"type":"string"}},{"name":"return_to","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"302":{"description":"Redirect to IdP authorize URL"},"404":{"description":"Provider not found"},"503":{"description":"OIDC provider unreachable"}}}},"/auth/oidc/providers":{"get":{"tags":["Authentication"],"operationId":"list_public_providers","responses":{"200":{"description":"Enabled OIDC providers for login page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcProvidersListResponse"}}}}}}},"/auth/password-reset/request":{"post":{"tags":["Authentication"],"operationId":"request_password_reset","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailRequest"}}},"required":true},"responses":{"200":{"description":"Reset email sent if account exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"503":{"description":"Email service not configured"}}}},"/auth/password-reset/verify":{"post":{"tags":["Authentication"],"operationId":"reset_password","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPasswordRequest"}}},"required":true},"responses":{"200":{"description":"Password reset successful","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"400":{"description":"Invalid or expired token"},"500":{"description":"Internal server error"}}}},"/auth/step-up":{"post":{"tags":["Authentication"],"operationId":"verify_step_up","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyStepUpRequest"}}},"required":true},"responses":{"200":{"description":"Session elevated for sensitive actions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StepUpResponse"}}}},"400":{"description":"Verification code is empty"},"401":{"description":"Invalid code or expired session"},"403":{"description":"Browser session required"},"428":{"description":"MFA setup required"},"429":{"description":"Too many verification attempts"},"500":{"description":"Verification infrastructure failed"}},"security":[{"session_token":[]}]}},"/auth/verify-email":{"get":{"tags":["Authentication"],"operationId":"verify_email","parameters":[{"name":"token","in":"query","description":"Email verification token","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Email verified successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"400":{"description":"Invalid or expired token"},"500":{"description":"Internal server error"}}}},"/auth/verify-mfa":{"post":{"tags":["Authentication"],"operationId":"verify_mfa_challenge","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaVerificationRequest"}}},"required":true},"responses":{"204":{"description":"MFA verification successful"},"400":{"description":"Invalid request"},"401":{"description":"Invalid MFA code"},"500":{"description":"Internal server error"}}}},"/backups/alerts":{"get":{"tags":["Backups"],"summary":"List open backup alerts.","description":"Returns all alerts that have not yet been resolved, ordered by `opened_at`\ndescending (newest first). The UI renders these as a banner above the\nBackups page content. Alerts are auto-opened by the watcher and\nauto-resolved when the triggering condition clears.\n\n**Schedule overdue** — the backup scheduler did not enqueue a job within\nthe expected window (1 hour past `next_run`). Usually means the scheduler\ntask is dead or wedged.\n\n**Job stalled** — a `backup_jobs` row has been in `state='pending'` for\nmore than 1 hour. The runner never claimed the job. Usually means the\nrunner task is dead or the runner concurrency cap is too low.","operationId":"list_backup_alerts","responses":{"200":{"description":"List of open backup alerts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupAlertListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/cleanup":{"post":{"tags":["Backups"],"summary":"Preview or run retention using each selected schedule's configured retention days.","operationId":"cleanup_expired_backups","parameters":[{"name":"dry_run","in":"query","description":"Return the backups selected by retention without deleting anything.","required":false,"schema":{"type":"boolean"}},{"name":"schedule_id","in":"query","description":"Limit cleanup to one backup schedule.","required":false,"schema":{"type":["integer","null"],"format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CleanupExpiredBackupsRequest"}}},"required":true},"responses":{"200":{"description":"Retention cleanup completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RetentionCleanupReport"}}}},"400":{"description":"Missing or invalid preview candidate list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule or backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"409":{"description":"Cleanup preview is stale","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Cleanup could not be started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/external-services/{id}/run":{"post":{"tags":["Backups"],"summary":"Run a backup for an external service manually.","description":"Enqueues the backup for asynchronous execution via the `BackupRunner`\n(ADR-014). Returns `202 Accepted` immediately: pending parent and child\nrows are inserted, and a `backup_jobs` row is enqueued for the resolved\nengine. Poll `GET /backups/{id}` to observe `pending → running → completed`.","operationId":"run_external_service_backup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunExternalServiceBackupRequest"}}},"required":true},"responses":{"202":{"description":"Backup enqueued for async execution","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceBackupResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"External service or S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/external-services/{service_id}/backups":{"get":{"tags":["Backups"],"summary":"List all backups for a specific external service (DB-only, no S3 scan).","description":"Returns a paginated list of backups that belong to this service.\nCompletes in <100 ms regardless of S3 endpoint latency because it\nnever touches S3.","operationId":"list_external_service_backups","parameters":[{"name":"service_id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based). Defaults to 1.","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"page_size","in":"query","description":"Items per page. Defaults to 20, max 100.","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Paginated list of backups for this service","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceBackupListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/external-services/{service_id}/schedules":{"get":{"tags":["Backups"],"summary":"List the schedules that target a specific external service. Useful for\nthe service detail page (\"which schedules back this DB up?\").","operationId":"list_service_schedules","parameters":[{"name":"service_id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Schedules backing up this service","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Service not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources":{"get":{"tags":["Backups"],"summary":"List all S3 sources","operationId":"list_s3_sources","responses":{"200":{"description":"List of S3 sources","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/S3SourceResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Backups"],"summary":"Create a new S3 source","operationId":"create_s3_source","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateS3SourceRequest"}}},"required":true},"responses":{"201":{"description":"S3 source created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3SourceResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/test":{"post":{"tags":["Backups"],"summary":"Test S3 connectivity against a prospective source configuration (before creating it).\nThe credentials are NOT persisted. Useful for validating the form in the UI.","operationId":"test_s3_connection_preview","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateS3SourceRequest"}}},"required":true},"responses":{"200":{"description":"Connection test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3ConnectionTestResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}":{"get":{"tags":["Backups"],"summary":"Get an S3 source by ID","operationId":"get_s3_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"S3 source details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3SourceResponse"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Backups"],"summary":"Delete an S3 source","operationId":"delete_s3_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"S3 source deleted"},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Backups"],"summary":"Update an S3 source","operationId":"update_s3_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateS3SourceRequest"}}},"required":true},"responses":{"200":{"description":"S3 source updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3SourceResponse"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}/backups":{"get":{"tags":["Backups"],"summary":"List all backups in an S3 source","operationId":"list_source_backups","parameters":[{"name":"include_s3_scan","in":"query","description":"When `true`, scan the S3 bucket for backups not tracked in the\nlocal database (useful after disaster-recovery from another Temps\ninstance). Defaults to `false` — the fast DB-only path.","required":false,"schema":{"type":"boolean"}},{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of all backups in the source","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceBackupIndexResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"S3 source not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}/run":{"post":{"tags":["Backups"],"summary":"Run a backup immediately for an S3 source.","description":"Enqueues the backup for asynchronous execution via the `BackupRunner`\n(ADR-014). Returns `202 Accepted` immediately: a `backups` row is inserted\nwith `state='pending'` and a `backup_jobs` row is enqueued for the\n`ControlPlaneEngine`. Poll `GET /backups/{id}` to observe\n`pending → running → completed`.","operationId":"run_backup_for_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunBackupRequest"}}},"required":true},"responses":{"202":{"description":"Backup enqueued for async execution","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}/set-default":{"post":{"tags":["Backups"],"summary":"Mark an S3 source as the default. All new backups/schedules/services that do not\nexplicitly reference a source will use the default. Returns the updated source.","operationId":"set_default_s3_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"S3 source marked as default","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3SourceResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}/test":{"post":{"tags":["Backups"],"summary":"Test connectivity to an existing S3 source using its stored credentials.","operationId":"test_s3_source_connection","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3ConnectionTestResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedule-runs/{id}/cancel":{"post":{"tags":["Backups"],"summary":"Cancel every non-terminal child backup belonging to a schedule run.","description":"Loops over `state IN ('pending','running')` children and flips each via\nthe same path as the per-backup cancel endpoint. The parent\n`schedule_runs.finished_at` is stamped automatically once no live\nchildren remain. Idempotent: cancelling a run with no live children is\na 200 with `cancelled = 0`.","operationId":"cancel_schedule_run","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Cancel processed (idempotent)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelBackupResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule run not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedule-runs/{id}/jobs":{"get":{"tags":["Backups"],"summary":"List the individual backup jobs for a single scheduler run.","description":"Returns each child `backups` row joined with its external service name and\nthe most-recent `backup_jobs` engine key. Used by the schedule detail\naccordion to show per-job detail on row expand.\n\n`page_size` defaults to 50 and is capped at 200.","operationId":"list_schedule_run_jobs","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Jobs for this scheduler run","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ScheduleRunJobEntry"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules":{"get":{"tags":["Backups"],"summary":"List all backup schedules","operationId":"list_backup_schedules","responses":{"200":{"description":"List of backup schedules","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Backups"],"summary":"Create a new backup schedule","operationId":"create_backup_schedule","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBackupScheduleRequest"}}},"required":true},"responses":{"201":{"description":"Backup schedule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}":{"get":{"tags":["Backups"],"summary":"Get a backup schedule by ID","operationId":"get_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Backup schedule details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"404":{"description":"Backup schedule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Backups"],"summary":"Delete a backup schedule","operationId":"delete_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Backup schedule deleted"},"404":{"description":"Backup schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Backups"],"summary":"Update a backup schedule (partial update).","description":"All request fields are optional; only fields that are present in the\nJSON body are updated. Absent fields leave the corresponding column\nunchanged. If `schedule_expression` is changed, `next_run` is\nrecomputed automatically.","operationId":"update_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBackupScheduleRequest"}}},"required":true},"responses":{"200":{"description":"Schedule updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/backups":{"get":{"tags":["Backups"],"summary":"List backups for a schedule","operationId":"list_backups_for_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of backups for the schedule","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BackupResponse"}}}}},"404":{"description":"Backup schedule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/disable":{"patch":{"tags":["Backups"],"summary":"Disable a backup schedule","operationId":"disable_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Backup schedule disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"404":{"description":"Backup schedule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/enable":{"patch":{"tags":["Backups"],"summary":"Enable a backup schedule","operationId":"enable_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Backup schedule enabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"404":{"description":"Backup schedule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/run":{"post":{"tags":["Backups"],"summary":"Immediately fan-out a run for the given schedule (Run Now).","description":"Creates one `schedule_runs` row, one control-plane backup job, and one\nbackup job per supported external service — all in a single transaction.\nReturns `202 Accepted` with a [`ScheduleRunResponse`] containing the new\n`schedule_run_id` and the list of enqueued jobs. Returns `409 Conflict` if\na run for this schedule is already in flight or if the schedule is disabled.","operationId":"run_schedule_now","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Fan-out run enqueued for async execution","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduleRunResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"409":{"description":"Run already in flight or schedule disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/runs":{"get":{"tags":["Backups"],"summary":"Paginated run history for a backup schedule (one row per scheduler tick).","description":"Returns one [`ScheduleRunSummary`] per scheduler tick, with child backup\ncounts aggregated in a single SQL round-trip. Legacy `backups` rows (pre-\nfan-out) are surfaced as synthetic single-job runs so history does not\ndisappear. Ordered by `started_at DESC` (newest first).\n\nUse `GET /backups/schedule-runs/{run_id}/jobs` to drill into a single run.","operationId":"list_schedule_runs","parameters":[{"name":"page","in":"query","description":"Page number (1-based, defaults to 1, clamped to 1 if < 1).","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"page_size","in":"query","description":"Items per page (defaults to 20, clamped to 100 if > 100).","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Paginated run history for the schedule","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduleRunSummaryList"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/services":{"get":{"tags":["Backups"],"summary":"List the external services attached to a backup schedule.","operationId":"list_schedule_services","parameters":[{"name":"id","in":"path","description":"Schedule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Services attached to this schedule","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ExternalServiceSummary"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Backups"],"summary":"Attach one or more external services to a backup schedule. Idempotent —\nservices that are already attached are silently skipped (`ON CONFLICT\nDO NOTHING`). Returns the count of newly inserted rows + the total\nmembership after the operation.","operationId":"attach_schedule_services","parameters":[{"name":"id","in":"path","description":"Schedule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachScheduleServicesRequest"}}},"required":true},"responses":{"200":{"description":"Services attached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachScheduleServicesResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/services/{service_id}":{"delete":{"tags":["Backups"],"summary":"Detach a single external service from a backup schedule. Idempotent —\nreturns `204` whether or not a row was actually removed.","operationId":"detach_schedule_service","parameters":[{"name":"id","in":"path","description":"Schedule ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"service_id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Service detached (or was not attached)"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/{id}":{"get":{"tags":["Backups"],"summary":"Get a backup by ID","operationId":"get_backup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Backup details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Backups"],"summary":"Permanently delete one terminal backup from object storage and the database.","operationId":"delete_backup","parameters":[{"name":"id","in":"path","description":"Backup UUID","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Backup deleted"},"400":{"description":"Backup artifact cannot be safely attributed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"409":{"description":"Backup is running, referenced, or lacks safe artifact identity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Object storage or database error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/{id}/cancel":{"post":{"tags":["Backups"],"summary":"Cancel a single in-flight backup.","description":"Flips the parent `backups` row + its latest `backup_jobs` row to\n`failed` with reason `\"cancelled by user \"`. The in-process\n`CancellationToken` is observed on the next heartbeat tick (≤5s), so the\nengine exits cleanly and rollback reaps the sidecar. Idempotent: cancelling\nan already-terminal backup is a 200 with `cancelled = 0`.","operationId":"cancel_backup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Cancel processed (idempotent)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelBackupResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/{id}/children":{"get":{"tags":["Backups"],"summary":"List the external-service child backups that belong to a parent backup.","description":"Each entry in `children` corresponds to one `external_service_backups` row,\njoined with `external_services` so the caller receives the service name and\ntype without a second request.\n\nReturns an empty `{ \"children\": [] }` — **not 404** — when the parent\nbackup exists but has no children (e.g. control-plane backups).\nReturns 404 when the parent backup itself does not exist.","operationId":"list_backup_children","parameters":[{"name":"id","in":"path","description":"Integer row id of the parent backup","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Child backup list (may be empty)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChildBackupListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Parent backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/blob":{"get":{"tags":["Blob"],"summary":"List blobs","operationId":"blob_list","parameters":[{"name":"limit","in":"query","description":"Maximum number of items to return","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"prefix","in":"query","description":"Prefix to filter by","required":false,"schema":{"type":"string"}},{"name":"cursor","in":"query","description":"Continuation token for pagination","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of blobs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListBlobsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Blob"],"summary":"Upload a blob","operationId":"blob_put","requestBody":{"description":"Binary blob data","content":{"application/octet-stream":{"schema":{"type":"string"}}},"required":true},"responses":{"201":{"description":"Blob uploaded successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlobResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Blob"],"summary":"Delete blobs","operationId":"blob_delete","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteBlobRequest"}}},"required":true},"responses":{"200":{"description":"Blobs deleted successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteBlobResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/blob/copy":{"post":{"tags":["Blob"],"summary":"Copy a blob to a new location","operationId":"blob_copy","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CopyBlobRequest"}}},"required":true},"responses":{"200":{"description":"Blob copied successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlobResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Source blob not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/blob/disable":{"delete":{"tags":["Blob Management"],"summary":"Disable Blob service","operationId":"blob_disable","responses":{"200":{"description":"Blob service disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DisableBlobResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Blob service not enabled"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/blob/enable":{"post":{"tags":["Blob Management"],"summary":"Enable Blob service","operationId":"blob_enable","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnableBlobRequest"}}},"required":true},"responses":{"200":{"description":"Blob service enabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnableBlobResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/blob/status":{"get":{"tags":["Blob Management"],"summary":"Get Blob service status","operationId":"blob_status","responses":{"200":{"description":"Blob service status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlobStatusResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/blob/update":{"patch":{"tags":["Blob Management"],"summary":"Update Blob service configuration","operationId":"blob_update","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBlobRequest"}}},"required":true},"responses":{"200":{"description":"Blob service updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBlobResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Blob service not enabled"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/blob/{project_id}/{path}":{"get":{"tags":["Blob"],"summary":"Download a blob","operationId":"blob_download","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","description":"Blob path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Blob content"},"404":{"description":"Blob not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"head":{"tags":["Blob"],"summary":"Get blob metadata","operationId":"blob_head","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","description":"Blob path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Blob metadata in headers"},"404":{"description":"Blob not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/dashboard/projects-analytics":{"get":{"tags":["Events"],"summary":"Get dashboard analytics for multiple projects in a single batch request","description":"Returns unique visitor counts and hourly sparkline data for all requested projects\nusing only 2 SQL queries instead of 2×N per-project queries.","operationId":"get_dashboard_projects_analytics","parameters":[{"name":"project_ids","in":"query","description":"Comma-separated list of project IDs","required":true,"schema":{"type":"string"}},{"name":"start_date","in":"query","description":"Start date for filtering","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved batch analytics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DashboardProjectsAnalyticsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/deployments/activity-graph":{"get":{"tags":["Deployments"],"summary":"Get deployment activity graph showing daily deployment counts\nSimilar to GitHub's contribution graph","operationId":"get_activity_graph","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"days","in":"query","description":"Number of days to include (default: 365)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved activity graph","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivityGraphResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/deployments/{deployment_id}/vulnerability-scan":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_scan_by_deployment","parameters":[{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Scan for the specified deployment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"No scan found for deployment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/deployments/{id}/metrics":{"get":{"tags":["Metrics"],"summary":"Fetch a time-series range for a single metric on a deployment.","operationId":"DeploymentMetricsGetRange","parameters":[{"name":"id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric","in":"query","description":"Metric name, e.g. `\"pg.connections_active\"`.","required":true,"schema":{"type":"string"}},{"name":"range","in":"query","description":"Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`.","required":false,"schema":{"type":"string"}},{"name":"percentile","in":"query","description":"Optional histogram percentile (0–100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile.","required":false,"schema":{"type":["number","null"],"format":"double"}}],"responses":{"200":{"description":"Metric time series data points","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MetricDataPoint"}}}}},"400":{"description":"Invalid query parameters"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/deployments/{id}/metrics/enable":{"patch":{"tags":["Metrics"],"summary":"Enable or disable OTLP metric ingestion for a deployment.","description":"When `enabled=true`, seeds the default container alert rules for the\ndeployment via [`temps_monitoring::seed_default_container_rules`] (idempotent).","operationId":"DeploymentMetricsToggle","parameters":[{"name":"id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToggleDeploymentMetricsRequest"}}},"required":true},"responses":{"200":{"description":"Metrics toggle applied"},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/deployments/{id}/metrics/latest":{"get":{"tags":["Metrics"],"summary":"Fetch the most-recent metric values for a deployment.","operationId":"DeploymentMetricsGetLatest","parameters":[{"name":"id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Map of metric name to latest value","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"number","format":"double"},"propertyNames":{"type":"string"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/dns-providers":{"get":{"tags":["DNS Providers"],"summary":"List all DNS providers","operationId":"list_dns_providers","responses":{"200":{"description":"List of DNS providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DnsProviderResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["DNS Providers"],"summary":"Create a new DNS provider","description":"The provider's credentials will be tested before creation.\nIf the connection test fails, the provider will not be created.","operationId":"create_dns_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDnsProviderRequest"}}},"required":true},"responses":{"201":{"description":"DNS provider created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsProviderResponse"}}}},"400":{"description":"Invalid request or connection test failed"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{id}":{"get":{"tags":["DNS Providers"],"summary":"Get a DNS provider by ID","operationId":"get_dns_provider","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"DNS provider details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsProviderResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["DNS Providers"],"summary":"Update a DNS provider","description":"If new credentials are supplied, they are tested before the update is\npersisted (same as creation) -- otherwise a provider's credentials (and,\nfor Pebble, its target URL) could be swapped for something invalid or\nunsafe without ever going through validation.","operationId":"update_provider","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDnsProviderRequest"}}},"required":true},"responses":{"200":{"description":"DNS provider updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsProviderResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["DNS Providers"],"summary":"Delete a DNS provider","operationId":"delete_dns_provider","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"DNS provider deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{id}/domains":{"get":{"tags":["DNS Providers"],"summary":"List managed domains for a provider","operationId":"list_managed_domains","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of managed domains","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ManagedDomainResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["DNS Providers"],"summary":"Add a managed domain to a provider","operationId":"add_managed_domain","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddManagedDomainApiRequest"}}},"required":true},"responses":{"201":{"description":"Managed domain added","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedDomainResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{id}/test":{"post":{"tags":["DNS Providers"],"summary":"Test provider connection","operationId":"test_provider_connection","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionTestResult"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{id}/zones":{"get":{"tags":["DNS Providers"],"summary":"List zones available in a provider","operationId":"list_provider_zones","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of zones","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ZoneListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{provider_id}/domains/{domain}":{"delete":{"tags":["DNS Providers"],"summary":"Remove a managed domain","operationId":"remove_managed_domain","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Managed domain removed"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["DNS Providers"],"summary":"Update a managed domain's settings (hostname mode, sync opt-in, auto-manage).","operationId":"update_managed_domain","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateManagedDomainApiRequest"}}},"required":true},"responses":{"200":{"description":"Managed domain updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedDomainResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{provider_id}/domains/{domain}/apply-hostname-mode":{"post":{"tags":["DNS Providers"],"summary":"Apply a hostname mode to a managed domain (persist + optional DNS sync +\nroute reload).","operationId":"apply_hostname_mode","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplyHostnameModeRequest"}}},"required":true},"responses":{"200":{"description":"Hostname mode applied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HostnamePreviewResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions or token lacks zone access"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{provider_id}/domains/{domain}/hostname-preview":{"get":{"tags":["DNS Providers"],"summary":"Preview the impact of switching a managed domain's hostname mode.","operationId":"preview_hostname_mode","parameters":[{"name":"mode","in":"query","description":"Target mode: standard|flat","required":true,"schema":{"type":"string"}},{"name":"sync","in":"query","description":"Include DNS record changes","required":false,"schema":{"type":"boolean"}},{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Hostname mode preview","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HostnamePreviewResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{provider_id}/domains/{domain}/verify":{"post":{"tags":["DNS Providers"],"summary":"Verify a managed domain","operationId":"verify_managed_domain","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Domain verification result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedDomainResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]}},"/dns/lookup":{"get":{"tags":["DNS"],"summary":"Lookup DNS A records for a domain","operationId":"lookup_dns_a_records","parameters":[{"name":"domain","in":"query","description":"Domain name to lookup","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved DNS A records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsLookupResponse"}}}},"400":{"description":"Invalid domain name or lookup failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsLookupError"}}}}}}},"/domains":{"get":{"tags":["Domains"],"summary":"List all domains","operationId":"list_domains","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"search","in":"query","description":"Search domains by name (substring match)","required":false,"schema":{"type":["string","null"]},"example":"example.com"}],"responses":{"200":{"description":"Domains retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListDomainsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Domains"],"summary":"Create a new domain","description":"Creates a new domain and automatically requests a Let's Encrypt challenge.\nYou can specify the challenge type (HTTP-01 or DNS-01) in the request.\n\n- **HTTP-01**: Validates domain ownership by placing a file on your web server at `/.well-known/acme-challenge/`\n- **DNS-01**: Validates domain ownership by adding a TXT record to your DNS (required for wildcard domains)","operationId":"create_domain","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDomainRequest"}}},"required":true},"responses":{"201":{"description":"Domain created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/by-host/{hostname}":{"get":{"tags":["Domains"],"summary":"Get domain details by hostname","operationId":"get_domain_by_host","parameters":[{"name":"hostname","in":"path","description":"Domain hostname","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Domain details retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/by-host/{hostname}/cert-status":{"get":{"tags":["Domains"],"summary":"Get on-demand TLS certificate status for a hostname","description":"Returns the current cert lifecycle state for a single hostname (from the\n`domains` row) plus the most recent on-demand issuance attempt (from the\n`on_demand_cert_attempts` audit log). This is the operator's first-line\ndiagnostic, surfaced by `temps domain cert-status` (ADR-018 §5). Returns the\nhostname with `None` fields when no on-demand activity exists for it (never a\n404, so the CLI can render \"no attempts recorded\").","operationId":"get_on_demand_cert_status","parameters":[{"name":"hostname","in":"path","description":"Domain hostname","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"On-demand cert status retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CertStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/on-demand-certs":{"get":{"tags":["Domains"],"summary":"List on-demand TLS certificate attempts","description":"Returns rows from the append-only `on_demand_cert_attempts` audit log\n(ADR-018 §5), newest first, each joined with the current authoritative cert\nstate (`status`, `expiration_time`, `backoff_until`) from the `domains` row.\nThis backs the console \"Certificates\" surface. No certificate or private-key\nmaterial is returned — only audit metadata.","operationId":"list_on_demand_certs","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20}],"responses":{"200":{"description":"On-demand cert attempts retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListOnDemandCertsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain_id}/order":{"get":{"tags":["Domains"],"summary":"Get ACME order for a domain","operationId":"get_domain_order","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Order retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AcmeOrderResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Order not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Domains"],"summary":"Create or recreate ACME order for a domain","description":"Creates a new ACME order with Let's Encrypt for the specified domain.\nIf an order already exists, you should cancel it first using the cancel-order endpoint.\nReturns the challenge details that need to be fulfilled (DNS record or HTTP token).","operationId":"create_or_recreate_order","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Order created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainChallengeResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Domains"],"summary":"Cancel ACME order for a domain","description":"Cancels the current ACME order for a domain and clears all challenge data.\nThis allows you to start over with a new order if the previous one failed or got stuck.","operationId":"cancel_domain_order","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Order cancelled successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain_id}/order/finalize":{"post":{"tags":["Domains"],"summary":"Finalize ACME order for a domain","description":"Finalizes the ACME order by completing the challenge validation and requesting the certificate.\nThis should be called after the challenge has been set up (DNS record added or HTTP token served).","operationId":"finalize_order","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Order finalized successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain or order not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain_id}/setup-dns":{"post":{"tags":["Domains"],"summary":"Setup DNS challenge records automatically using a DNS provider","description":"This endpoint automatically creates the required DNS TXT records for ACME DNS-01 challenge\nvalidation using a configured DNS provider. The domain must have an active DNS challenge\npending (created via POST /domains/{id}/order with dns-01 challenge type).\n\nThis is similar to how email domain DNS records are auto-provisioned.","operationId":"setup_dns_challenge","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupDnsChallengeRequest"}}},"required":true},"responses":{"200":{"description":"DNS records created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupDnsChallengeResponse"}}}},"400":{"description":"Bad request - DNS provider not configured or no challenge pending"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain or DNS provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}":{"get":{"tags":["Domains"],"summary":"Get domain by ID","operationId":"get_domain_by_id","parameters":[{"name":"domain","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Domain retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Domains"],"summary":"Delete a domain","operationId":"delete_domain","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Domain deleted successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/challenge-token":{"get":{"tags":["Domains"],"summary":"Get challenge token for a domain (returns plain text token)","operationId":"get_challenge_token","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Challenge token retrieved successfully","content":{"text/plain":{"schema":{"type":"string"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Challenge not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/http-challenge-debug":{"get":{"tags":["Domains"],"summary":"Get HTTP challenge debug information","description":"Returns detailed debug information for HTTP-01 challenge including:\n- Whether a challenge exists for the domain\n- The challenge token and URL that Let's Encrypt will access\n- DNS resolution information showing where the domain currently points\n\nThis is useful for debugging why HTTP-01 challenges fail.","operationId":"get_http_challenge_debug","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Debug information retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpChallengeDebugResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/provision":{"post":{"tags":["Domains"],"summary":"Provision a domain certificate","operationId":"provision_domain","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Certificate provisioning initiated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProvisionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/renew":{"post":{"tags":["Domains"],"summary":"Renew domain certificate","description":"For HTTP-01 domains: Automatically renews the certificate\nFor DNS-01 domains (wildcards): Creates a new ACME order and returns challenge data","operationId":"renew_domain","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Certificate renewal initiated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProvisionResponse"}}}},"202":{"description":"DNS challenge created - manual action required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainChallengeResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/status":{"get":{"tags":["Domains"],"summary":"Check domain status","operationId":"check_domain_status","parameters":[{"name":"domain","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Domain status retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/drop/inspect":{"post":{"tags":["Projects"],"summary":"Inspect a source ZIP without creating a project or retaining the upload.","operationId":"inspect_drop_archive","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/DropArchiveUpload"}}},"required":true},"responses":{"200":{"description":"Detected deployable project roots","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DropInspectionResponse"}}}},"400":{"description":"Invalid or unsupported archive"}},"security":[{"bearer_auth":[]}]}},"/email-domains":{"get":{"tags":["Email Domains"],"summary":"List all email domains","operationId":"list_email_domains","parameters":[{"name":"provider_id","in":"query","description":"Only return domains belonging to this provider","required":false,"schema":{"type":["integer","null"],"format":"int32"}}],"responses":{"200":{"description":"List of email domains","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EmailDomainResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Email Domains"],"summary":"Create a new email domain","operationId":"create_email_domain","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEmailDomainRequest"}}},"required":true},"responses":{"201":{"description":"Domain created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailDomainWithDnsResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/by-domain/{domain}":{"get":{"tags":["Email Domains"],"summary":"Get an email domain by domain name with DNS records","operationId":"get_domain_by_name","parameters":[{"name":"domain","in":"path","description":"Domain name (e.g., 'mail.example.com')","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Email domain details with DNS records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailDomainWithDnsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/{id}":{"get":{"tags":["Email Domains"],"summary":"Get an email domain by ID with DNS records","operationId":"get_domain","parameters":[{"name":"id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Email domain details with DNS records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailDomainWithDnsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Email Domains"],"summary":"Delete an email domain","operationId":"delete_email_domain","parameters":[{"name":"id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Domain deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/{id}/dns-records":{"get":{"tags":["Email Domains"],"summary":"Get DNS records for an email domain","operationId":"get_domain_dns_records","parameters":[{"name":"id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"DNS records for the domain","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecordResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/{id}/setup-dns":{"post":{"tags":["Email Domains"],"summary":"Setup DNS records for an email domain using a configured DNS provider","operationId":"setup_dns","parameters":[{"name":"id","in":"path","description":"Email Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupDnsRequest"}}},"required":true},"responses":{"200":{"description":"DNS records setup result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupDnsResponse"}}}},"400":{"description":"Invalid request or DNS provider not configured"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/{id}/verify":{"post":{"tags":["Email Domains"],"summary":"Verify an email domain's DNS configuration","operationId":"verify_domain","parameters":[{"name":"id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Domain verification result with DNS records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailDomainWithDnsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-providers":{"get":{"tags":["Email Providers"],"summary":"List all email providers","operationId":"list_email_providers","responses":{"200":{"description":"List of email providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EmailProviderResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Email Providers"],"summary":"Create a new email provider","operationId":"create_email_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEmailProviderRequest"}}},"required":true},"responses":{"201":{"description":"Provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailProviderResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-providers/{id}":{"get":{"tags":["Email Providers"],"summary":"Get an email provider by ID","operationId":"get_email_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Email provider details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailProviderResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Email Providers"],"summary":"Delete an email provider","operationId":"delete_email_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Provider deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Email Providers"],"summary":"Update an email provider","description":"Partial update — any field left out keeps its current value. Most importantly,\nomitting the credential block (`ses_credentials`/`scaleway_credentials`/`smtp_credentials`)\npreserves the stored secret, so operators can rename a provider without re-typing\npasswords. `provider_type` is immutable; to switch providers, delete and recreate.","operationId":"update_email_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEmailProviderRequest"}}},"required":true},"responses":{"200":{"description":"Provider updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailProviderResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"409":{"description":"Provider type mismatch"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-providers/{id}/test":{"post":{"tags":["Email Providers"],"summary":"Test an email provider by sending a test email to the logged-in user","operationId":"test_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestEmailRequest"}}},"required":true},"responses":{"200":{"description":"Test email result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestEmailResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-providers/{id}/tracking/setup":{"post":{"tags":["Email Providers"],"summary":"One-click AWS-side setup of SES event tracking (SNS topic + webhook\nsubscription + SESv2 event destination), using the provider's stored\ncredentials.","operationId":"setup_email_tracking","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Setup completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailTrackingSetupResponse"}}}},"400":{"description":"Provider does not support event tracking"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"502":{"description":"An AWS call failed — the response detail names the failed step"}},"security":[{"bearer_auth":[]}]}},"/email-providers/{id}/tracking/status":{"get":{"tags":["Email Providers"],"summary":"Live status of SES event tracking for a provider","operationId":"get_email_tracking_status","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Event tracking status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailTrackingStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/emails":{"get":{"tags":["Emails"],"summary":"List emails with optional filtering","operationId":"list_emails","parameters":[{"name":"domain_id","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"project_id","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"status","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"from_address","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"page","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"page_size","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"List of emails","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedEmailsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Emails"],"summary":"Send an email","operationId":"send_email","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendEmailRequestBody"}}},"required":true},"responses":{"201":{"description":"Email sent successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendEmailResponseBody"}}}},"400":{"description":"Invalid request or domain not verified"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/emails/events":{"get":{"tags":["Email Tracking"],"summary":"GET /emails/events","operationId":"get_global_events","parameters":[{"name":"event_type","in":"query","description":"Filter by event type (open, click)","required":false,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Paginated tracking events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedEventsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/emails/events/stats":{"get":{"tags":["Email Tracking"],"summary":"GET /emails/events/stats","operationId":"get_global_event_stats","responses":{"200":{"description":"Global tracking statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlobalEventStatsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/emails/stats":{"get":{"tags":["Emails"],"summary":"Get email statistics","operationId":"get_email_stats","parameters":[{"name":"domain_id","in":"query","description":"Optional domain ID to filter stats","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Email statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailStatsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/emails/validate":{"post":{"tags":["Email Validation"],"summary":"Validate an email address","operationId":"validate_email","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateEmailRequest"}}},"required":true},"responses":{"200":{"description":"Email validation result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateEmailResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/emails/{email_id}/track/click/{link_index}":{"get":{"tags":["Email Tracking"],"summary":"Track email link click - redirects to original URL","description":"This endpoint replaces original links in tracked emails.\nNo authentication required - it's called when the recipient clicks a link.","operationId":"track_click","parameters":[{"name":"email_id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}},{"name":"link_index","in":"path","description":"Link index","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"302":{"description":"Redirect to original URL"},"404":{"description":"Link not found"}}}},"/emails/{email_id}/track/open":{"get":{"tags":["Email Tracking"],"summary":"Track email open - returns a 1x1 transparent GIF","description":"This endpoint is embedded as an tag in emails.\nNo authentication required - it's called by the email client.","operationId":"track_open","parameters":[{"name":"email_id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"1x1 transparent tracking pixel"},"404":{"description":"Email not found"}}}},"/emails/{id}":{"get":{"tags":["Emails"],"summary":"Get an email by ID","operationId":"get_email","parameters":[{"name":"id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Email details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Email not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/emails/{id}/tracking":{"get":{"tags":["Email Tracking"],"summary":"Get email tracking summary","operationId":"get_email_tracking","parameters":[{"name":"id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Tracking summary","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailTrackingResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Email not found"}},"security":[{"bearer_auth":[]}]}},"/emails/{id}/tracking/events":{"get":{"tags":["Email Tracking"],"summary":"Get email tracking events","operationId":"get_email_events","parameters":[{"name":"id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}},{"name":"event_type","in":"query","description":"Filter by event type (open, click)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Tracking events","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TrackingEventResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Email not found"}},"security":[{"bearer_auth":[]}]}},"/emails/{id}/tracking/links":{"get":{"tags":["Email Tracking"],"summary":"Get tracked links for an email","operationId":"get_email_links","parameters":[{"name":"id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Tracked links","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TrackedLinkResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Email not found"}},"security":[{"bearer_auth":[]}]}},"/external-services":{"get":{"tags":["External Services"],"summary":"Get all external services","operationId":"list_services","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of external services","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}}},"500":{"description":"Internal server error"}}},"post":{"tags":["External Services"],"summary":"Create new external service","operationId":"create_service","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateExternalServiceRequest"}}},"required":true},"responses":{"201":{"description":"Service created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}}}},"/external-services/available-containers":{"get":{"tags":["External Services"],"summary":"List available Docker containers that can be imported as services","operationId":"list_available_containers","responses":{"200":{"description":"List of available containers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AvailableContainerInfo"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/by-slug/{slug}":{"get":{"tags":["External Services"],"summary":"Get external service details by slug","operationId":"get_service_by_slug","parameters":[{"name":"slug","in":"path","description":"External service slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"External service details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceDetails"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/health-status-batch":{"get":{"tags":["External Services"],"summary":"Current health status for many services at once","description":"Powers the status dot on the Storage list page. Pass a comma-separated\nlist of service IDs via `?ids=1,2,3`. Omit to get every service.","operationId":"list_service_health_statuses","parameters":[{"name":"ids","in":"query","description":"Comma-separated service IDs. Omit for all services.","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Batch of current health statuses","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceHealthStatusBatchResponse"}}}},"500":{"description":"Internal server error"}}}},"/external-services/import":{"post":{"tags":["External Services"],"summary":"Import an existing Docker container as a managed external service","operationId":"import_external_service","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportExternalServiceRequest"}}},"required":true},"responses":{"201":{"description":"Service imported successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/projects/{project_id}":{"get":{"tags":["External Services"],"summary":"List services linked to a project","operationId":"list_project_services","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of services linked to project","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectServiceInfo"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/external-services/projects/{project_id}/environment":{"get":{"tags":["External Services"],"summary":"Get all environment variables for all services linked to a project","operationId":"get_project_service_environment_variables","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Map of service IDs to their environment variables","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"propertyNames":{"type":"integer","format":"int32"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/external-services/providers/metadata":{"get":{"tags":["External Services"],"summary":"Get provider metadata (display names, icons, descriptions)","operationId":"get_providers_metadata","responses":{"200":{"description":"List of provider metadata","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderMetadata"}}}}},"500":{"description":"Internal server error"}}}},"/external-services/providers/metadata/{service_type}":{"get":{"tags":["External Services"],"summary":"Get metadata for a specific provider","operationId":"get_provider_metadata","parameters":[{"name":"service_type","in":"path","description":"Service type (mongodb, postgres, redis, s3)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Provider metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderMetadata"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}}}},"/external-services/types":{"get":{"tags":["External Services"],"summary":"Get available service types","operationId":"get_service_types","responses":{"200":{"description":"List of available service types","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ServiceTypeRoute"}}}}},"500":{"description":"Internal server error"}}}},"/external-services/types/{service_type}/parameters":{"get":{"tags":["External Services"],"summary":"Get parameter schema for a specific service type","operationId":"get_service_type_parameters","parameters":[{"name":"service_type","in":"path","description":"Service type","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Service type parameter schema"},"404":{"description":"Service type not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}":{"get":{"tags":["External Services"],"summary":"Get external service details","operationId":"get_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"External service details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceDetails"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}},"put":{"tags":["External Services"],"summary":"Update external service","operationId":"update_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateExternalServiceRequest"}}},"required":true},"responses":{"200":{"description":"Service updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Invalid request"},"404":{"description":"Service not found"},"409":{"description":"A major upgrade is in progress for this service"},"500":{"description":"Internal server error"}}},"delete":{"tags":["External Services"],"summary":"Delete external service","operationId":"delete_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Service deleted successfully"},"400":{"description":"Cannot delete: service is still linked to projects"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/cluster-health":{"get":{"tags":["External Services"],"summary":"Per-member health for a Postgres HA cluster.","description":"Reads pg_auto_failover's `pgautofailover.node` table from the cluster's\nmonitor (TLS, autoctl_node) and joins each member with its\n`pg_stat_replication` row from the current primary. Returns one row per\ndata member with role/state, sync state, and replay lag.\n\nReturns `200` with `monitor_error` set when the monitor is briefly\nunreachable (UI surfaces it as a banner above the table); the table\nitself is empty in that case. Returns `400` for non-cluster services.","operationId":"get_cluster_health","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Per-member cluster health report","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClusterHealthReportResponse"}}}},"400":{"description":"Service is not a cluster"},"401":{"description":"Unauthorized"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/health-check":{"post":{"tags":["External Services"],"summary":"Run a health check for one service right now","description":"Triggers the same engine-specific probe as the background monitor, writes\na history row, updates the denormalized fields on `external_services`, and\nfires alerts on the Nth consecutive failure (so consecutive-failure state\nstays honest). Returns the fresh snapshot the UI can display immediately.","operationId":"trigger_service_health_check","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Fresh health snapshot after probing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceHealthResponse"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"},"503":{"description":"Health monitor not running on this node"}}}},"/external-services/{id}/health-status":{"get":{"tags":["External Services"],"summary":"Persisted health status for an external service","description":"Returns the latest health probe result recorded by\n`ExternalServiceHealthMonitor`, plus recent check history for sparklines\nand a 24-hour uptime percentage. Safe to poll from the UI every 30s.","operationId":"get_service_health_status","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Max number of recent checks (default 50, max 200)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Current health + recent history","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceHealthResponse"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/members":{"post":{"tags":["External Services"],"summary":"Begin adding a single new member to a running cluster.","description":"Currently only `replica` members can be added at runtime. The\nresponse is **202 Accepted** as soon as the validation passes and\nthe placeholder `service_members` row is inserted. The actual\ncontainer provisioning + DNS registration runs in the background;\npoll `GET /external-services/{id}/members/{member_id}` to watch\n`provisioning_step` advance through the phases.","operationId":"add_cluster_member","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddClusterMemberRequest"}}},"required":true},"responses":{"202":{"description":"Cluster member provisioning started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceMemberInfo"}}}},"400":{"description":"Validation failed (wrong topology, status, or role)"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/members/{member_id}":{"get":{"tags":["External Services"],"summary":"Get a single cluster member's current state.","description":"Used by the add-member page to poll the row every second while the\nbackground provisioning task walks through its phases. The\n`provisioning_step` field advances through `inserting_row` →\n`provisioning_container` → `registering_dns` → `done` (or `failed`\nwith `provisioning_error` set).","operationId":"get_cluster_member","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"member_id","in":"path","description":"Cluster member ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Cluster member details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceMemberInfo"}}}},"404":{"description":"Service or member not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["External Services"],"summary":"Remove a single member from a running cluster.","description":"Refuses to remove the monitor (singleton), the current primary\n(failover first), or any member if the cluster would drop below the\n2-data-member quorum required for HA. Stops + removes the container,\ndeletes the row, and drops the Tier-2 DNS record.","operationId":"remove_cluster_member","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"member_id","in":"path","description":"Cluster member ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Cluster member removed"},"400":{"description":"Validation failed (monitor, primary, or quorum violation)"},"404":{"description":"Service or member not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/members/{member_id}/promote":{"post":{"tags":["External Services"],"summary":"Promote a replica to primary by triggering a pg_auto_failover\nfailover. The monitor demotes the current primary and the chosen\nreplica transitions to primary; the role reconciler then refreshes\nthe role-aliased VIPs (≤30s).","operationId":"promote_cluster_member","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"member_id","in":"path","description":"Cluster member ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Promotion initiated"},"400":{"description":"Validation failed (monitor, already primary, not running, etc.)"},"404":{"description":"Service or member not found"},"500":{"description":"pg_autoctl perform promotion failed"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics":{"get":{"tags":["Metrics"],"summary":"Fetch a time-series range for a single metric on an external service.","description":"Pass `percentile` to compute a histogram quantile instead of a plain\ngauge/counter average.","operationId":"ExternalServiceMetricsGetRange","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric","in":"query","description":"Metric name, e.g. `\"pg.connections_active\"`.","required":true,"schema":{"type":"string"}},{"name":"range","in":"query","description":"Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`.","required":false,"schema":{"type":"string"}},{"name":"percentile","in":"query","description":"Optional histogram percentile (0–100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile.","required":false,"schema":{"type":["number","null"],"format":"double"}}],"responses":{"200":{"description":"Metric time series data points","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MetricDataPoint"}}}}},"400":{"description":"Invalid query parameters"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/alert-rules":{"get":{"tags":["Metrics"],"summary":"List all monitoring alert rules for an external service.","operationId":"ExternalServiceMetricsGetAlertRules","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of alert rules","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ServiceAlertRuleResponse"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Metrics"],"summary":"Create a monitoring alert rule for an external service.","description":"If metric collection is enabled and the service engine has default rules,\nseeding is idempotent (ON CONFLICT DO NOTHING).","operationId":"ExternalServiceMetricsCreateAlertRule","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceCreateAlertRuleRequest"}}},"required":true},"responses":{"201":{"description":"Alert rule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceAlertRuleResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/alert-rules/{rule_id}":{"put":{"tags":["Metrics"],"summary":"Update an existing monitoring alert rule for an external service.","operationId":"ExternalServiceMetricsUpdateAlertRule","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceUpdateAlertRuleRequest"}}},"required":true},"responses":{"200":{"description":"Updated alert rule","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceAlertRuleResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Metrics"],"summary":"Delete a monitoring alert rule for an external service.","operationId":"ExternalServiceMetricsDeleteAlertRule","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Alert rule deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/by-database":{"get":{"tags":["Metrics"],"summary":"Return the latest per-database metric values for a Postgres service.","description":"Groups `pg_stat_database` / size metrics by `datname` so the UI can show a\nbreakdown table (each database with its own size, cache-hit ratio, etc.)\nrather than collapsing every database into one value.","operationId":"ExternalServiceMetricsByDatabase","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Per-database metric breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatabaseMetricsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics not available"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/enable":{"patch":{"tags":["Metrics"],"summary":"Enable or disable metric collection for an external service.","description":"When `enabled=true`, seeds the default alert rules for the service's engine\nvia [`temps_monitoring::seed_default_rules`] (idempotent).","operationId":"ExternalServiceMetricsToggle","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToggleServiceMetricsRequest"}}},"required":true},"responses":{"200":{"description":"Metrics toggle applied"},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/latest":{"get":{"tags":["Metrics"],"summary":"Fetch the most-recent value for every tracked metric on an external service.","operationId":"ExternalServiceMetricsGetLatest","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Map of metric name to latest value","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"number","format":"double"},"propertyNames":{"type":"string"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/status":{"get":{"tags":["Metrics"],"summary":"Return the freshness status (last-received timestamp) for a service.","description":"Cheap O(1) lookup against `service_metrics_status` — used by the UI to show\n\"last received at …\" without scanning the metrics hypertable.","operationId":"ExternalServiceMetricsStatus","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Metrics freshness status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetricsStatusResponse"}}}},"503":{"description":"Metrics not available"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/parameters/{param_name}":{"get":{"tags":["External Services"],"summary":"Reveal one sensitive service parameter. Service detail responses never\ncontain plaintext values; every successful reveal is recorded separately.","operationId":"reveal_service_parameter","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"param_name","in":"path","description":"Sensitive parameter name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sensitive parameter value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensitiveValueResponse"}}}},"400":{"description":"Parameter is not sensitive"},"403":{"description":"Caller cannot access a project linked to this service"},"404":{"description":"Service or parameter not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/preview-environment-masked":{"get":{"tags":["External Services"],"summary":"Get environment variables preview with masked sensitive values","operationId":"get_service_preview_environment_variables_masked","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Preview of environment variables with sensitive values masked as ***","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/preview-environment-names":{"get":{"tags":["External Services"],"summary":"Get environment variable names preview (safe - no sensitive values)","operationId":"get_service_preview_environment_variable_names","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environment variable names that would be provided","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"}}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/projects":{"get":{"tags":["External Services"],"summary":"List projects linked to service","operationId":"list_service_projects","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of linked projects","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectServiceInfo"}}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["External Services"],"summary":"Link service to project","operationId":"link_service_to_project","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkServiceRequest"}}},"required":true},"responses":{"201":{"description":"Service linked to project successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectServiceInfo"}}}},"404":{"description":"Service or project not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/projects/{project_id}":{"delete":{"tags":["External Services"],"summary":"Unlink service from project","operationId":"unlink_service_from_project","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Service unlinked from project successfully"},"404":{"description":"Service link not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/projects/{project_id}/environment":{"get":{"tags":["External Services"],"summary":"Get all environment variables for a service-project pair","operationId":"get_service_environment_variables","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environment variables","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentVariableInfo"}}}}},"404":{"description":"Service or project not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/projects/{project_id}/environment/{var_name}":{"get":{"tags":["External Services"],"summary":"Get specific environment variable for a service-project pair","operationId":"get_service_environment_variable","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"var_name","in":"path","description":"Environment variable name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Environment variable value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableInfo"}}}},"403":{"description":"Plaintext secret access is not permitted"},"404":{"description":"Service, project, or variable not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/resources":{"patch":{"tags":["External Services"],"summary":"Update a service's resource limits (memory, CPU caps).","description":"Persists the new caps to the encrypted config AND live-applies them\nvia Docker's update API. Memory and CPU can be hot-changed without a\nrestart on running containers; stopped containers also accept the\nupdate and pick up the new caps on next start.\n\nPass `null` (or omit) any field to leave it unlimited. A request where\nevery field is `null` removes any existing limits.\n\nThe response includes a per-container `applied[]` list so the caller\ncan tell which members got the update and which were skipped (e.g.,\ncontainer not yet created, or `docker update` rejected because the\nnew memory cap is below current usage).","operationId":"update_service_resources","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceResourceLimits"}}},"required":true},"responses":{"200":{"description":"Updated resource limits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceLimitsUpdateResponse"}}}},"400":{"description":"Invalid resource limits"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/restore":{"post":{"tags":["Restore"],"operationId":"start_restore","parameters":[{"name":"id","in":"path","description":"External service id (source for the restore)","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartRestoreRequest"}}},"required":true},"responses":{"202":{"description":"Restore run started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestoreRunView"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup or service not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/restore-capabilities":{"get":{"tags":["Restore"],"operationId":"get_restore_capabilities","parameters":[{"name":"id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Capabilities declared by the service","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestoreCapabilitiesResponse"}}}},"404":{"description":"Service not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/restore-plan":{"post":{"tags":["Restore"],"operationId":"plan_restore","parameters":[{"name":"id","in":"path","description":"Target service id","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartRestoreRequest"}}},"required":true},"responses":{"200":{"description":"Preview of what the restore will do","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestorePlan"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup or service not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/restore-runs":{"get":{"tags":["Restore"],"operationId":"list_restore_runs_for_service","parameters":[{"name":"id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Recent restore runs for the service","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RestoreRunView"}}}}}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/retry":{"post":{"tags":["External Services"],"summary":"Retry a failed cluster service initialization.","description":"Cleans up any leftover containers from the previous attempt and\nre-runs cluster initialization with the provided member specifications.","operationId":"retry_cluster","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RetryClusterRequest"}}},"required":true},"responses":{"200":{"description":"Cluster retry initiated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Service is not a failed cluster"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/runtime":{"get":{"tags":["External Services"],"summary":"Inspect a service's container(s): status, restart count, OOM-killed flag,\nexit code, and the cgroup limits actually applied.","operationId":"get_service_runtime","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Container runtime snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceRuntimeReport"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/start":{"post":{"tags":["External Services"],"summary":"Start an external service","operationId":"start_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Service started successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"404":{"description":"Service not found"},"409":{"description":"A Postgres major upgrade is in progress for this service"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/stats":{"get":{"tags":["External Services"],"summary":"Sample current CPU/memory usage from each of a service's containers.\nOne-shot sample, no streaming. Cheap to call (single Docker round-trip\nper member) so the UI can poll on a 5–10s interval.","operationId":"get_service_stats","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Container stats snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceStatsReport"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/stop":{"post":{"tags":["External Services"],"summary":"Stop an external service","operationId":"stop_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Service stopped successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/upgrade":{"post":{"tags":["External Services"],"summary":"Upgrade external service to new Docker image with data migration\nThis endpoint uses service-specific upgrade procedures (e.g., pg_upgrade for PostgreSQL)","operationId":"upgrade_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpgradeExternalServiceRequest"}}},"required":true},"responses":{"200":{"description":"Service upgraded successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Invalid request or upgrade not supported"},"404":{"description":"Service not found"},"409":{"description":"A major upgrade is already in progress for this service"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/wal-health":{"get":{"tags":["External Services"],"summary":"Postgres WAL & archive health snapshot","description":"Returns the latest WAL/archive health snapshot recorded by the background\nhealth monitor for a Postgres external service. Powers the warning banner\non the service detail page when the disk is filling up due to stale\nreplication slots, archive backlog, or misconfigured `archive_command`.\n\nReturns 404 when no snapshot exists yet (probe hasn't run, or the service\nisn't Postgres).","operationId":"getPostgresWalHealth","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Latest WAL health snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostgresWalHealth"}}}},"404":{"description":"Service not found, or no WAL snapshot available"},"500":{"description":"Internal server error"}}}},"/external-services/{service_id}/pg-stat-statements/enable":{"post":{"tags":["External Services"],"summary":"Enable `pg_stat_statements` on a standalone Postgres service.","description":"Stops the container and restarts it so that the\n`shared_preload_libraries=pg_stat_statements` CMD flag (baked into every\nnew standalone Postgres container) takes effect. The named data volume is\nreused unchanged — no data is lost.\n\n**Clustered (HA) services are rejected** with 422 — a blind single-container\nrestart bypasses controlled failover. For clustered services the response\nbody describes the manual rolling-restart steps.\n\nConfirmation is the caller's responsibility (UI dialog / CLI `--yes` flag)\nbefore invoking this endpoint.","operationId":"ExternalServiceEnablePgStatStatements","parameters":[{"name":"service_id","in":"path","description":"ID of the provisioned standalone Postgres service","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Container restarted; pg_stat_statements now active","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnablePgStatStatementsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions (requires external_services:write)"},"404":{"description":"Service not found"},"422":{"description":"Service is not standalone Postgres (cluster or wrong type)"},"500":{"description":"Restart failed"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/pg-stat-statements/reset":{"post":{"tags":["External Services"],"summary":"Reset all statistics accumulated by `pg_stat_statements` for a Postgres\nservice. This affects every user, database, and normalized query tracked by\nthe target Postgres instance and cannot be undone.","operationId":"ExternalServiceResetPgStatStatements","parameters":[{"name":"service_id","in":"path","description":"ID of the provisioned Postgres service","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"Explicit confirmation of the global, irreversible reset","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPgStatStatementsRequest"}}},"required":true},"responses":{"200":{"description":"All accumulated pg_stat_statements statistics cleared","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPgStatStatementsResponse"}}}},"400":{"description":"Missing or invalid reset confirmation"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions (requires external_services:write)"},"404":{"description":"Service not found"},"422":{"description":"Service is not Postgres"},"502":{"description":"Target Postgres rejected or failed the reset operation"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/pg-stat-statements/slow-queries":{"get":{"tags":["External Services"],"operationId":"get_slow_queries","parameters":[{"name":"service_id","in":"path","description":"ID of the provisioned Postgres service","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based). Defaults to 1.","required":false,"schema":{"type":["integer","null"],"format":"int32","minimum":0}},{"name":"page_size","in":"query","description":"Number of rows per page (1–100). Defaults to 20.","required":false,"schema":{"type":["integer","null"],"format":"int32","minimum":0}},{"name":"sort_by","in":"query","description":"Column to sort by: one of `calls`, `total_exec_time_ms`,\n`mean_exec_time_ms`, `rows`, `cache_hit_ratio`. Defaults to\n`mean_exec_time_ms`. Applied server-side so ordering stays\nconsistent across pages.","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","description":"Sort direction: `asc` or `desc`. Defaults to `desc`.","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Paginated slow queries from pg_stat_statements","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SlowQueriesResponse"}}}},"400":{"description":"Invalid pagination or sort parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions (requires external_services:read)"},"404":{"description":"Service not found"},"422":{"description":"Service is not a Postgres service"},"503":{"description":"pg_stat_statements extension not available (container restart required)"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers":{"get":{"tags":["External Services - Query"],"summary":"List containers at the root level (databases, keyspaces, etc.)","operationId":"list_root_containers","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of root containers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ContainerResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}":{"get":{"tags":["External Services - Query"],"summary":"List containers at a specific path\nPath segments are separated by forward slashes\nExample: /external-services/1/query/containers/mydb lists schemas in database \"mydb\"","operationId":"list_containers_at_path","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of containers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ContainerResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/entities":{"get":{"tags":["External Services - Query"],"summary":"List entities (tables, collections, etc.) in a container\nExample: /external-services/1/query/containers/mydb/public/entities lists tables in the public schema","operationId":"list_entities","parameters":[{"name":"limit","in":"query","description":"Maximum number of entities to return (default: 100, max: 1000)","required":false,"schema":{"type":"integer","minimum":0}},{"name":"token","in":"query","description":"Continuation token for pagination","required":false,"schema":{"type":"string"}},{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated list of entities","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedEntitiesResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/entities/{entity}":{"get":{"tags":["External Services - Query"],"summary":"Get detailed information about an entity (table schema)","operationId":"get_entity_info","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}},{"name":"entity","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Entity details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntityInfoResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service, container, or entity not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/entities/{entity}/data":{"post":{"tags":["External Services - Query"],"summary":"Query data from an entity with optional filters, pagination, and sorting","operationId":"query_data","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}},{"name":"entity","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryDataRequest"}}},"required":true},"responses":{"200":{"description":"Query results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryDataResponse"}}}},"400":{"description":"Invalid query"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service, container, or entity not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/entities/{entity}/download":{"get":{"tags":["External Services - Query"],"summary":"Download an object (S3 only) as a streaming response","operationId":"download_object","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}},{"name":"entity","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Object data stream","content":{"application/octet-stream":{}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Object not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/info":{"get":{"tags":["External Services - Query"],"summary":"Get information about a specific container","operationId":"get_container_info","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/explorer-support":{"get":{"tags":["External Services - Query"],"summary":"Check if a service supports query explorer functionality","operationId":"check_explorer_support","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Explorer support information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExplorerSupportResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades":{"get":{"tags":["Postgres Upgrades"],"summary":"List recent upgrades for a single service (newest first, page size 50).","operationId":"list_pg_upgrades","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Recent upgrades","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}}},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Postgres Upgrades"],"summary":"Start a new PostgreSQL major-version upgrade for a service.","operationId":"start_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartPgUpgradeRequest"}}},"required":true},"responses":{"201":{"description":"Upgrade started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"400":{"description":"Invalid request"},"409":{"description":"An upgrade is already running for this service"},"412":{"description":"No default S3 source configured"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}":{"get":{"tags":["Postgres Upgrades"],"summary":"Get a single upgrade by id, scoped to a service.","operationId":"get_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Upgrade","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"404":{"description":"Not found"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}/cancel":{"post":{"tags":["Postgres Upgrades"],"summary":"Cancel an in-flight upgrade. The orchestrator stops at its next phase\nboundary; already-terminal upgrades return 409.","operationId":"cancel_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Cancellation requested","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Upgrade already terminal"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}/logs":{"get":{"tags":["Postgres Upgrades"],"summary":"Get the accumulated JSONL log content for an upgrade (for dashboard display).","operationId":"get_pg_upgrade_logs","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Log content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeLogResponse"}}}},"404":{"description":"Not found"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}/retry":{"post":{"tags":["Postgres Upgrades"],"summary":"Retry a failed upgrade. The phase is preserved, so the state machine\nresumes from where it failed.","operationId":"retry_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Retry scheduled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"400":{"description":"Upgrade is not in a retriable state"},"404":{"description":"Not found"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}/rollback":{"post":{"tags":["Postgres Upgrades"],"summary":"Roll a completed upgrade back to its pre-upgrade PGDATA volume and old image.\nOnly valid while the rollback retention window is still open (see\n`ROLLBACK_RETENTION_DAYS`) and the rollback volume has not been swept.","operationId":"rollback_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Rollback complete","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Upgrade is not in a rollbackable state (not completed, volume swept, or retention expired)"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/files/{file_path}":{"get":{"tags":["Files"],"operationId":"get_file","parameters":[{"name":"file_path","in":"path","description":"Relative path to the file from static directory","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"File content retrieved successfully","content":{"application/octet-stream":{}}},"401":{"description":"Authentication required"},"403":{"description":"Access denied - path outside static directory or insufficient permissions"},"404":{"description":"File not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/flags/exposure":{"post":{"tags":["Feature Flags"],"summary":"Record which flags a running app actually evaluated.","description":"This is what makes `last_evaluated_at` mean something. The snapshot\nendpoint hands the SDK every flag in the environment and evaluation then\nhappens locally, so the control plane cannot otherwise tell a flag that is\nreferenced by live code from one nothing has called in a year. Stamping on\nsnapshot fetch would mark every flag as freshly used and defeat the point.\n\nScope comes from the deployment token, never the body. The endpoint writes\nonly `last_evaluated_at` — never a flag's value — so \"a deployment token\ncannot change what a flag serves\" still holds despite this being a write.","operationId":"record_flag_exposure","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecordExposureRequest"}}},"required":true},"responses":{"200":{"description":"Exposure recorded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecordExposureResponse"}}}},"400":{"description":"Deployment token required"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/flags/snapshot":{"get":{"tags":["Feature Flags"],"summary":"Every flag for the caller's environment, collapsed to what the evaluator\nneeds.","description":"Scope comes from the deployment token, never from the URL: a container's\nbaked-in `TEMPS_API_TOKEN` identifies exactly one project (and usually one\nenvironment), so a compromised app cannot read another tenant's flags by\nchanging a path parameter.\n\nSupports `If-None-Match`, so the SDK's background poll is a 304 in the\ncommon case.","operationId":"get_flag_snapshot","parameters":[{"name":"environment_id","in":"query","description":"Required only when the calling token is project-wide rather than scoped\nto a single environment.","required":false,"schema":{"type":["integer","null"],"format":"int32"}}],"responses":{"200":{"description":"Snapshot for the environment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagSnapshotResponse"}}}},"304":{"description":"Snapshot unchanged"},"400":{"description":"Environment could not be determined"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/geo/{ip}":{"get":{"tags":["geo"],"summary":"Get geolocation information for an IP address","operationId":"get_ip_geolocation","parameters":[{"name":"ip","in":"path","description":"IP address to geolocate (IPv4 or IPv6)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Geolocation information retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeoLocationResponse"}}}},"400":{"description":"Invalid IP address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"IP address not found in database","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/git-connections":{"get":{"tags":["Git Providers"],"summary":"List user's git provider connections","operationId":"list_connections","parameters":[{"name":"page","in":"query","description":"Page number for pagination (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Number of items per page (default: 30, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"sort","in":"query","description":"Sort field (created_at, updated_at, account_name)","required":false,"schema":{"type":"string"}},{"name":"direction","in":"query","description":"Sort direction (asc, desc), default: desc","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of connections","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionListResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}":{"delete":{"tags":["Git Providers"],"summary":"Permanently delete a git provider connection","operationId":"delete_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Connection deleted successfully"},"400":{"description":"Connection is in use by projects and cannot be deleted"},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/activate":{"post":{"tags":["Git Providers"],"summary":"Activate a git provider connection","operationId":"activate_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection activated successfully"},"400":{"description":"Provider is deactivated and connection cannot be activated"},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/deactivate":{"post":{"tags":["Git Providers"],"summary":"Deactivate a git provider connection","operationId":"deactivate_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection deactivated successfully"},"400":{"description":"Connection is in use by projects and cannot be deactivated"},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/health-check":{"post":{"tags":["Git Provider Connections"],"summary":"Run an on-demand health check for a git connection.","description":"Probes the upstream (GitHub App, PAT, or OAuth token), persists the result,\nand fires admin notifications on status transitions. Returns the updated\nconnection.","operationId":"run_connection_health_check","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Health check completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/repositories":{"get":{"tags":["Git Providers"],"summary":"List repositories for a specific connection","description":"Fetches repositories from the connected git provider with support for pagination, search, and filtering.\nThis endpoint calls the provider's API directly to get the most up-to-date repository list.","operationId":"list_repositories_by_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"sort","in":"query","description":"Sort field (name, created_at, updated_at, stars, etc.)","required":false,"schema":{"type":"string"}},{"name":"direction","in":"query","description":"Sort direction (asc, desc)","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Search term to filter repositories","required":false,"schema":{"type":"string"}},{"name":"owner","in":"query","description":"Filter by repository owner","required":false,"schema":{"type":"string"}},{"name":"language","in":"query","description":"Filter by programming language","required":false,"schema":{"type":"string"}},{"name":"private","in":"query","description":"Filter by private status (true/false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of repositories","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/sync":{"post":{"tags":["Git Providers"],"summary":"Start a repository sync for a connection","description":"Kicks off a background sync of the connection's repositories from the\nprovider. Returns `202 Accepted` immediately — the caller should poll\nthe connection endpoint for `syncing` / `synced_repository_count`\nupdates rather than waiting on this response. The sync is guarded by\na hard deadline and always releases the `syncing` flag on exit, so a\nclient that disconnects mid-sync will not leave the connection stuck.","operationId":"sync_repositories","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Repository sync started in background","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositorySyncStartedResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"409":{"description":"Sync already in progress"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/update-token":{"post":{"tags":["Git Provider Connections"],"summary":"Update access token for a connection (when tokens expire or are rotated)","operationId":"update_connection_token","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTokenRequest"}}},"required":true},"responses":{"200":{"description":"Token updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTokenResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/validate":{"get":{"tags":["Git Provider Connections"],"summary":"Validate a connection by testing the access token","operationId":"validate_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection validation result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers":{"get":{"tags":["Git Providers"],"summary":"List all git providers","operationId":"list_git_providers","responses":{"200":{"description":"List of providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderResponse"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Git Providers"],"summary":"Create a new git provider configuration","operationId":"create_git_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProviderRequest"}}},"required":true},"responses":{"201":{"description":"Provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/bitbucket":{"post":{"tags":["Git Providers"],"summary":"Create a Bitbucket Cloud provider with access token or app password authentication","operationId":"create_bitbucket_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBitbucketRequest"}}},"required":true},"responses":{"201":{"description":"Bitbucket provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request — missing or invalid auth fields"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/generic":{"post":{"tags":["Git Providers"],"summary":"Create a Generic git provider for self-hosted or arbitrary HTTPS git hosts.\nSupports public repositories (no token) and private repositories (token-based).","operationId":"create_generic_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGenericRequest"}}},"required":true},"responses":{"201":{"description":"Generic git provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request — invalid clone URL or missing fields"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/gitea/pat":{"post":{"tags":["Git Providers"],"summary":"Create a Gitea Personal Access Token provider","operationId":"create_gitea_pat_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGiteaPATRequest"}}},"required":true},"responses":{"201":{"description":"Gitea PAT provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request — invalid URL or missing fields"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/github/pat":{"post":{"tags":["Git Providers"],"summary":"Create a GitHub Personal Access Token provider","operationId":"create_github_pat_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGitHubPATRequest"}}},"required":true},"responses":{"201":{"description":"GitHub PAT provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/gitlab/oauth":{"post":{"tags":["Git Providers"],"summary":"Create a GitLab OAuth provider","operationId":"create_gitlab_oauth_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGitLabOAuthRequest"}}},"required":true},"responses":{"201":{"description":"GitLab OAuth provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/gitlab/pat":{"post":{"tags":["Git Providers"],"summary":"Create a GitLab PAT provider","operationId":"create_gitlab_pat_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGitLabPATRequest"}}},"required":true},"responses":{"201":{"description":"GitLab PAT provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}":{"get":{"tags":["Git Providers"],"summary":"Get a specific git provider","operationId":"get_git_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Provider details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Git Providers"],"summary":"Permanently delete a git provider","operationId":"delete_git_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Provider deleted successfully"},"400":{"description":"Provider has connections and cannot be deleted"},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/activate":{"post":{"tags":["Git Providers"],"summary":"Activate a git provider","operationId":"activate_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Provider activated successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/callback":{"get":{"tags":["Git Providers"],"summary":"Handle OAuth callback for a git provider","operationId":"handle_git_provider_oauth_callback","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"code","in":"query","description":"OAuth authorization code","required":true,"schema":{"type":"string"}},{"name":"state","in":"query","description":"CSRF state token","required":true,"schema":{"type":"string"}}],"responses":{"302":{"description":"Redirect to success page"},"400":{"description":"Bad request"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}}}},"/git-providers/{provider_id}/connections":{"get":{"tags":["Git Providers"],"summary":"Get connections for a specific git provider","operationId":"get_provider_connections","parameters":[{"name":"provider_id","in":"path","description":"Provider ID to get connections for","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of connections for the provider","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ConnectionResponse"}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/credentials":{"patch":{"tags":["Git Providers"],"summary":"Partially update credentials for an existing git provider. Only the fields\nyou send are replaced; omitted fields keep their stored values. Fields that\ndon't apply to the provider's auth method are ignored on the service side.","operationId":"update_git_provider_credentials","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProviderCredentialsRequest"}}},"required":true},"responses":{"200":{"description":"Credentials updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/deactivate":{"post":{"tags":["Git Providers"],"summary":"Deactivate a git provider","operationId":"deactivate_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Provider deactivated successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/deletion-check":{"get":{"tags":["Git Providers"],"summary":"Check if a git provider can be safely deleted","operationId":"check_provider_deletion_safety","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deletion check result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderDeletionCheckResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/oauth/authorize":{"get":{"tags":["Git Providers"],"summary":"Start OAuth flow for a git provider","operationId":"start_git_provider_oauth","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"302":{"description":"Redirect to OAuth provider"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/repositories":{"get":{"tags":["Git Providers"],"summary":"List all repositories for a specific provider","description":"Lists repositories synced to the database across every connection under\nthis provider, with the same pagination/filtering as `/repositories`.","operationId":"list_repositories_by_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"sort","in":"query","description":"Sort field (name, created_at, updated_at, stars, watchers, size, issues)","required":false,"schema":{"type":"string"}},{"name":"direction","in":"query","description":"Sort direction (asc, desc)","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Search term to filter repositories","required":false,"schema":{"type":"string"}},{"name":"owner","in":"query","description":"Filter by repository owner","required":false,"schema":{"type":"string"}},{"name":"language","in":"query","description":"Filter by programming language","required":false,"schema":{"type":"string"}},{"name":"private","in":"query","description":"Filter by private status (true/false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of repositories","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/safe-delete":{"delete":{"tags":["Git Providers"],"summary":"Safely delete a git provider (only if no projects are using it)","operationId":"delete_provider_safely","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Provider successfully deleted"},"400":{"description":"Cannot delete provider because it's in use"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git/public/{provider}/{owner}/{repo}":{"get":{"tags":["Public Repositories"],"summary":"Get information about a public repository (supports GitHub and GitLab)","operationId":"get_public_repository","parameters":[{"name":"provider","in":"path","description":"Git provider (github or gitlab)","required":true,"schema":{"type":"string"}},{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Repository information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicRepositoryInfo"}}}},"400":{"description":"Provider not supported"},"404":{"description":"Repository not found"},"429":{"description":"API rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/git/public/{provider}/{owner}/{repo}/branches":{"get":{"tags":["Public Repositories"],"summary":"Get branches for a public repository (supports GitHub and GitLab)","operationId":"get_public_branches","parameters":[{"name":"provider","in":"path","description":"Git provider (github or gitlab)","required":true,"schema":{"type":"string"}},{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of branches","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BranchListResponse"}}}},"400":{"description":"Provider not supported"},"404":{"description":"Repository not found"},"429":{"description":"API rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/git/public/{provider}/{owner}/{repo}/presets":{"get":{"tags":["Public Repositories"],"summary":"Detect presets for a public repository (supports GitHub and GitLab)","operationId":"detect_public_presets","parameters":[{"name":"provider","in":"path","description":"Git provider (github or gitlab)","required":true,"schema":{"type":"string"}},{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"branch","in":"query","description":"Branch name to detect presets for (default: repository's default branch)","required":false,"schema":{"type":["string","null"]}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Detected presets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicPresetResponse"}}}},"400":{"description":"Provider not supported"},"404":{"description":"Repository or branch not found"},"429":{"description":"API rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/imports/discover":{"post":{"tags":["Imports"],"summary":"Discover workloads from a source","operationId":"discover_workloads","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscoverRequest"}}},"required":true},"responses":{"200":{"description":"List of discovered workloads","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscoverResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/imports/execute":{"post":{"tags":["Imports"],"summary":"Execute an import","operationId":"execute_import","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteImportRequest"}}},"required":true},"responses":{"202":{"description":"Import execution started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteImportResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/imports/plan":{"post":{"tags":["Imports"],"summary":"Create an import plan","operationId":"create_plan","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePlanRequest"}}},"required":true},"responses":{"200":{"description":"Import plan created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePlanResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/imports/sources":{"get":{"tags":["Imports"],"summary":"List available import sources","operationId":"list_sources","responses":{"200":{"description":"List of available import sources","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ImportSourceInfo"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/imports/{session_id}":{"get":{"tags":["Imports"],"summary":"Get import status","operationId":"get_import_status","parameters":[{"name":"session_id","in":"path","description":"Import session ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Import status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Import session not found"}},"security":[{"bearer_auth":[]}]}},"/incidents/{incident_id}":{"get":{"tags":["Status Page"],"summary":"Get an incident by ID","operationId":"get_incident","parameters":[{"name":"incident_id","in":"path","description":"Incident ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved incident","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Incident not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/incidents/{incident_id}/status":{"patch":{"tags":["Status Page"],"summary":"Update incident status","operationId":"update_incident_status","parameters":[{"name":"incident_id","in":"path","description":"Incident ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateIncidentStatusRequest"}}},"required":true},"responses":{"200":{"description":"Incident status updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Incident not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/incidents/{incident_id}/updates":{"get":{"tags":["Status Page"],"summary":"Get incident updates","operationId":"get_incident_updates","parameters":[{"name":"incident_id","in":"path","description":"Incident ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved incident updates","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/IncidentUpdateResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Incident not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes":{"get":{"tags":["Nodes"],"summary":"List all registered nodes (admin — session auth via RequireAuth)","operationId":"admin_list_nodes","responses":{"200":{"description":"List of nodes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodeListResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes/register":{"post":{"tags":["Nodes"],"summary":"Register a new worker node or reconnect an existing one","operationId":"register_node","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterNodeApiRequest"}}},"required":true},"responses":{"200":{"description":"Node reconnected successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterNodeResponse"}}}},"201":{"description":"Node registered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterNodeResponse"}}}},"400":{"description":"Validation error"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}":{"get":{"tags":["Nodes"],"summary":"Get a specific node by ID (admin — session auth via RequireAuth)","operationId":"admin_get_node","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Node details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodeInfoResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Nodes"],"summary":"Remove a node from the cluster entirely. The node should be drained first\nto ensure containers have been rescheduled. If the node still has active\ncontainers, it will be drained automatically before removal.","operationId":"admin_remove_node","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Node removed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoveNodeResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"409":{"description":"Node still has active containers"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes/{node_id}/containers":{"get":{"tags":["Nodes"],"summary":"List all containers running on a specific node","operationId":"admin_list_node_containers","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Containers on this node","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodeContainerListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes/{node_id}/dns/ack":{"post":{"tags":["Internal DNS"],"summary":"`POST /internal/nodes/{node_id}/dns/ack`","operationId":"post_dns_ack","parameters":[{"name":"node_id","in":"path","description":"Node id, must match the bearer token's node","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsAckRequest"}}},"required":true},"responses":{"200":{"description":"ACK accepted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsAckResponse"}}}},"400":{"description":"ACK higher than server generation"},"401":{"description":"Missing or invalid bearer token"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}/dns/changes":{"get":{"tags":["Internal DNS"],"summary":"`GET /internal/nodes/{node_id}/dns/changes?since=N`","operationId":"get_dns_changes","parameters":[{"name":"node_id","in":"path","description":"Node id, must match the bearer token's node","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"since","in":"query","description":"Highest generation the agent has already applied. Pass `0` to\nrequest a full zone snapshot. Defaults to `0` if omitted.","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Diff or full snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsChangesResponse"}}}},"401":{"description":"Missing or invalid bearer token"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}/drain":{"get":{"tags":["Nodes"],"summary":"Get the drain status for a node, including migration progress.","description":"Returns container counts and whether the drain is complete.\nCan be polled to track drain progress.","operationId":"admin_drain_status","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Drain status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DrainStatusResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Nodes"],"summary":"Drain a node: mark it as \"draining\" so no new replicas are scheduled on it,\nand trigger redeployment of all affected environments so their containers\nare rescheduled to healthy nodes.","operationId":"admin_drain_node","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Node drain initiated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DrainNodeResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Nodes"],"summary":"Undrain (reactivate) a node so it can accept new deployments again.\nOnly works for nodes in \"draining\" or \"drained\" status.","operationId":"admin_undrain_node","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Node reactivated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UndrainNodeResponse"}}}},"400":{"description":"Node not in drainable state"},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes/{node_id}/heartbeat":{"post":{"tags":["Nodes"],"summary":"Receive a heartbeat from a worker node","operationId":"node_heartbeat","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HeartbeatApiRequest"}}},"required":true},"responses":{"200":{"description":"Heartbeat received","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HeartbeatResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}/network/peers":{"get":{"tags":["Nodes"],"summary":"`GET /internal/nodes/{node_id}/network/peers`","operationId":"list_peers","parameters":[{"name":"node_id","in":"path","description":"Node id, must match the bearer token's node","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Peer list and self-allocation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PeerListResponse"}}}},"401":{"description":"Missing or invalid bearer token"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}/s3-credentials/{s3_source_id}":{"get":{"tags":["Nodes"],"summary":"Get decrypted S3 credentials for a backup/restore operation.","description":"Agents call this endpoint to receive the S3 credentials they need to upload\nor download backups. The credentials are decrypted from the stored S3 source\nand returned over the authenticated TLS/WireGuard channel.","operationId":"get_s3_credentials","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"s3_source_id","in":"path","description":"S3 source ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"S3 credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3CredentialsResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"S3 source not found"},"500":{"description":"Internal server error"}}}},"/ip-access-control":{"get":{"tags":["IP Access Control"],"summary":"List all IP access control rules","operationId":"list_ip_access_control","parameters":[{"name":"action","in":"query","description":"Filter by action (\"block\" or \"allow\")","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of IP access control rules","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/IpAccessControlResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["IP Access Control"],"summary":"Create a new IP access control rule","operationId":"create_ip_access_control","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIpAccessControlRequest"}}},"required":true},"responses":{"201":{"description":"IP access control rule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IpAccessControlResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"409":{"description":"Duplicate IP address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ip-access-control/check/{ip}":{"get":{"tags":["IP Access Control"],"summary":"Check if an IP address is blocked","operationId":"check_ip_blocked","parameters":[{"name":"ip","in":"path","description":"IP address to check","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"IP block status"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ip-access-control/{id}":{"get":{"tags":["IP Access Control"],"summary":"Get a single IP access control rule by ID","operationId":"get_ip_access_control","parameters":[{"name":"id","in":"path","description":"IP access control rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"IP access control rule details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IpAccessControlResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"IP access control rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["IP Access Control"],"summary":"Delete an IP access control rule","operationId":"delete_ip_access_control","parameters":[{"name":"id","in":"path","description":"IP access control rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"IP access control rule deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"IP access control rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["IP Access Control"],"summary":"Update an IP access control rule","operationId":"update_ip_access_control","parameters":[{"name":"id","in":"path","description":"IP access control rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateIpAccessControlRequest"}}},"required":true},"responses":{"200":{"description":"IP access control rule updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IpAccessControlResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"IP access control rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/kv/del":{"post":{"tags":["KV Store"],"summary":"Delete one or more keys","operationId":"kv_del","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DelRequest"}}},"required":true},"responses":{"200":{"description":"Keys deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DelResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/disable":{"delete":{"tags":["KV Management"],"summary":"Disable KV service","operationId":"kv_disable","responses":{"200":{"description":"KV service disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DisableKvResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"KV service not enabled"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/enable":{"post":{"tags":["KV Management"],"summary":"Enable KV service","operationId":"kv_enable","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnableKvRequest"}}},"required":true},"responses":{"200":{"description":"KV service enabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnableKvResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/expire":{"post":{"tags":["KV Store"],"summary":"Set expiration on a key","operationId":"kv_expire","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExpireRequest"}}},"required":true},"responses":{"200":{"description":"Expiration set","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExpireResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/get":{"post":{"tags":["KV Store"],"summary":"Get a value by key","operationId":"kv_get","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetRequest"}}},"required":true},"responses":{"200":{"description":"Value retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/incr":{"post":{"tags":["KV Store"],"summary":"Increment a numeric value","operationId":"kv_incr","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncrRequest"}}},"required":true},"responses":{"200":{"description":"Value incremented","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncrResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/keys":{"post":{"tags":["KV Store"],"summary":"Get keys matching a pattern","operationId":"kv_keys","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeysRequest"}}},"required":true},"responses":{"200":{"description":"Keys retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeysResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/set":{"post":{"tags":["KV Store"],"summary":"Set a value with optional expiration","operationId":"kv_set","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetRequest"}}},"required":true},"responses":{"200":{"description":"Value set","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/status":{"get":{"tags":["KV Management"],"summary":"Get KV service status","operationId":"kv_status","responses":{"200":{"description":"KV service status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KvStatusResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/ttl":{"post":{"tags":["KV Store"],"summary":"Get time-to-live for a key","operationId":"kv_ttl","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TtlRequest"}}},"required":true},"responses":{"200":{"description":"TTL retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TtlResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/update":{"patch":{"tags":["KV Management"],"summary":"Update KV service configuration","operationId":"kv_update","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateKvRequest"}}},"required":true},"responses":{"200":{"description":"KV service updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateKvResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"KV service not enabled"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/lb/routes":{"get":{"tags":["Load Balancer"],"operationId":"list_routes","responses":{"200":{"description":"List of routes","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RouteResponse"}}}}},"500":{"description":"Internal server error"}}},"post":{"tags":["Load Balancer"],"operationId":"create_route","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRouteRequest"}}},"required":true},"responses":{"201":{"description":"Route created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteResponse"}}}},"400":{"description":"Invalid request"}}}},"/lb/routes/{domain}":{"get":{"tags":["Load Balancer"],"operationId":"get_route","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Route found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteResponse"}}}},"404":{"description":"Route not found"}}},"put":{"tags":["Load Balancer"],"operationId":"update_route","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRouteRequest"}}},"required":true},"responses":{"200":{"description":"Route updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteResponse"}}}},"404":{"description":"Route not found"}}},"delete":{"tags":["Load Balancer"],"operationId":"delete_route","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Route deleted successfully"},"404":{"description":"Route not found"}}}},"/logout":{"post":{"tags":["Authentication"],"operationId":"logout","responses":{"200":{"description":"Successfully logged out"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/logs/context":{"get":{"tags":["Logs"],"summary":"Get context lines surrounding a specific log line","operationId":"get_log_context","parameters":[{"name":"chunk_id","in":"query","description":"Chunk ID","required":true,"schema":{"type":"string"}},{"name":"line_offset","in":"query","description":"Line offset within the chunk","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"lines","in":"query","description":"Context lines before and after (default: 25)","required":false,"schema":{"type":"integer","format":"int32","minimum":0}}],"responses":{"200":{"description":"Context lines","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContextLogsResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Chunk not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/logs/search":{"post":{"tags":["Logs"],"summary":"Search logs with structured filters and full text search","operationId":"search_logs","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchLogsRequest"}}},"required":true},"responses":{"200":{"description":"Search results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchLogsResponse"}}}},"400":{"description":"Invalid search parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/logs/tail":{"get":{"tags":["Logs"],"summary":"Live tail logs via Server-Sent Events","operationId":"tail_logs","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"string"}},{"name":"service","in":"query","description":"Service name","required":true,"schema":{"type":"string"}},{"name":"env","in":"query","description":"Environment","required":true,"schema":{"type":"string"}},{"name":"levels","in":"query","description":"Optional level filters","required":true,"schema":{"type":"array","items":{"type":"string"}}},{"name":"text","in":"query","description":"Optional text filter","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"SSE stream of log lines"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/monitors-health/projects":{"get":{"tags":["Status Page"],"summary":"Get monitor-based health summaries for multiple projects in a single query","operationId":"get_projects_monitor_health","parameters":[{"name":"project_ids","in":"query","description":"Comma-separated list of project IDs","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Health summaries per project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectsMonitorHealthResponse"}}}},"400":{"description":"Invalid parameters"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/monitors/{monitor_id}":{"get":{"tags":["Status Page"],"summary":"Get a monitor by ID","operationId":"get_monitor","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved monitor","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Status Page"],"summary":"Delete a monitor","operationId":"delete_monitor","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Monitor deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/monitors/{monitor_id}/bucketed":{"get":{"tags":["Status Page"],"summary":"Get bucketed status data for a monitor using TimescaleDB","operationId":"get_bucketed_status","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"interval","in":"query","description":"Bucket interval: '5min', 'hourly', or 'daily' (default: hourly)","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601) (default: 24 hours ago)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (ISO 8601) (default: now)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved bucketed status data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusBucketedResponse"}}}},"400":{"description":"Invalid parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/monitors/{monitor_id}/current-status":{"get":{"tags":["Status Page"],"summary":"Get current status and uptime metrics for a monitor","operationId":"get_current_monitor_status","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","description":"Custom start time (ISO 8601) - overrides timeframe","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"Custom end time (ISO 8601)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved current status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CurrentStatusResponse"}}}},"400":{"description":"Invalid time parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/monitors/{monitor_id}/uptime":{"get":{"tags":["Status Page"],"summary":"Get uptime history for a monitor","operationId":"get_uptime_history","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"days","in":"query","description":"Number of days of history (default: 60) - ignored if start_time/end_time provided","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601) - overrides days parameter","required":true,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (ISO 8601) - defaults to now","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved uptime history","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UptimeHistoryResponse"}}}},"400":{"description":"Invalid time parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/nodes/{id}/metrics":{"get":{"tags":["Metrics"],"summary":"Fetch a time-series range for a single metric on a node.","operationId":"NodeMetricsGetRange","parameters":[{"name":"id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric","in":"query","description":"Metric name, e.g. `\"pg.connections_active\"`.","required":true,"schema":{"type":"string"}},{"name":"range","in":"query","description":"Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`.","required":false,"schema":{"type":"string"}},{"name":"percentile","in":"query","description":"Optional histogram percentile (0–100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile.","required":false,"schema":{"type":["number","null"],"format":"double"}}],"responses":{"200":{"description":"Metric time series data points","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MetricDataPoint"}}}}},"400":{"description":"Invalid query parameters"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/notification-preferences":{"get":{"tags":["Notification Preferences"],"summary":"Get notification preferences","operationId":"get_preferences","responses":{"200":{"description":"Successfully retrieved preferences","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationPreferencesResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Notification Preferences"],"summary":"Update notification preferences","operationId":"update_preferences","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePreferencesRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated preferences","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationPreferencesResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Notification Preferences"],"summary":"Delete notification preferences","operationId":"delete_preferences","responses":{"204":{"description":"Successfully deleted preferences"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers":{"get":{"tags":["Notification Providers"],"summary":"List all notification providers","operationId":"list_notification_providers","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Successfully retrieved providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}}},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Notification Providers"],"summary":"Create a new notification provider","operationId":"create_notification_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/cloudflare":{"post":{"tags":["Notification Providers"],"summary":"Create a new Cloudflare Email Sending notification provider","operationId":"create_cloudflare_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCloudflareProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created Cloudflare provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/cloudflare/{id}":{"put":{"tags":["Notification Providers"],"summary":"Update a Cloudflare Email Sending notification provider","operationId":"update_cloudflare_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCloudflareProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated Cloudflare provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/email":{"post":{"tags":["Notification Providers"],"summary":"Create a new Email notification provider","operationId":"create_notification_email_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateNotificationEmailProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created Email provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/email/{id}":{"put":{"tags":["Notification Providers"],"summary":"Update an Email notification provider","operationId":"update_notification_email_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateNotificationEmailProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated Email provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/slack":{"post":{"tags":["Notification Providers"],"summary":"Create a new Slack notification provider","operationId":"create_slack_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSlackProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created Slack provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/slack/{id}":{"put":{"tags":["Notification Providers"],"summary":"Update a Slack notification provider","operationId":"update_slack_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSlackProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated Slack provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/webhook":{"post":{"tags":["Notification Providers"],"summary":"Create a new Webhook notification provider","description":"Webhook providers send notifications as JSON payloads to any HTTP endpoint.\nYou can configure custom headers for authentication (Bearer tokens, API keys, etc.).\nThe webhook will receive a JSON payload with notification details including:\nid, title, message, type, priority, severity, timestamp, and metadata.","operationId":"create_webhook_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created Webhook provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/webhook/{id}":{"put":{"tags":["Notification Providers"],"summary":"Update a Webhook notification provider","operationId":"update_webhook_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWebhookProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated Webhook provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/{id}":{"get":{"tags":["Notification Providers"],"summary":"Get a single notification provider","operationId":"get_notification_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Notification Providers"],"summary":"Update a notification provider","operationId":"update_notification_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid masked provider configuration"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Notification Providers"],"summary":"Delete a notification provider","operationId":"delete_notification_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Successfully deleted provider"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/{id}/config/{field}":{"get":{"tags":["Notification Providers"],"operationId":"reveal_notification_provider_config","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"field","in":"path","description":"Sensitive field, such as password or headers.Authorization","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sensitive provider configuration value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensitiveConfigValueResponse"}}}},"400":{"description":"Field is not revealable"},"403":{"description":"Missing secrets:read permission"},"404":{"description":"Provider or field not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/{id}/test":{"post":{"tags":["Notification Providers"],"summary":"Test a notification provider","operationId":"test_notification_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/orders":{"get":{"tags":["Domains"],"summary":"List all ACME orders","operationId":"list_orders","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Orders retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListOrdersResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/otel/alerts":{"get":{"tags":["Alerts"],"summary":"List alert rules for a project (newest first, paginated).","operationId":"list_alerts","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Alert rules for the project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricAlertsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Alerts"],"summary":"Create a new alert rule for a project.","operationId":"create_alert","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMetricAlertRequest"}}},"required":true},"responses":{"201":{"description":"Alert rule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricAlertRuleResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/alerts/preview":{"post":{"tags":["Alerts"],"summary":"Backtest an anomaly detector over a time range without saving a rule.","description":"Replays the metric against the same band the evaluator would use, returning\nthe per-bucket band + which points would have fired. Powers the form's\n\"would this have fired?\" preview and the explorer band overlay. Read-only.","operationId":"preview_alert","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnomalyPreviewRequest"}}},"required":true},"responses":{"200":{"description":"Per-bucket band + breach points","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnomalyPreviewResponse"}}}},"400":{"description":"Not an anomaly detector / bad input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/alerts/{id}":{"get":{"tags":["Alerts"],"summary":"Fetch a single alert rule by id.","operationId":"get_alert","parameters":[{"name":"id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the lookup)","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alert rule","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricAlertRuleResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Alert rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Alerts"],"summary":"Delete an alert rule.","operationId":"delete_alert","parameters":[{"name":"id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the delete)","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Alert rule deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Alert rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Alerts"],"summary":"Update an alert rule's fields.","operationId":"update_alert","parameters":[{"name":"id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the update)","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMetricAlertRequest"}}},"required":true},"responses":{"200":{"description":"Alert rule updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricAlertRuleResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Alert rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/dashboards":{"get":{"tags":["Dashboards"],"summary":"List dashboards for a project (newest first, paginated).","operationId":"list_dashboards","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Dashboards for the project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelDashboardsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Dashboards"],"summary":"Create a new dashboard for a project.","operationId":"create_dashboard","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDashboardRequest"}}},"required":true},"responses":{"201":{"description":"Dashboard created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelDashboardResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/dashboards/{id}":{"get":{"tags":["Dashboards"],"summary":"Fetch a single dashboard by id.","operationId":"get_dashboard","parameters":[{"name":"id","in":"path","description":"Dashboard ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the lookup)","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Dashboard","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelDashboardResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Dashboard not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Dashboards"],"summary":"Delete a dashboard.","operationId":"delete_dashboard","parameters":[{"name":"id","in":"path","description":"Dashboard ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the delete)","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Dashboard deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Dashboard not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Dashboards"],"summary":"Update a dashboard's name and/or layout.","operationId":"update_dashboard","parameters":[{"name":"id","in":"path","description":"Dashboard ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the update)","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDashboardRequest"}}},"required":true},"responses":{"200":{"description":"Dashboard updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelDashboardResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Dashboard not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/genai/traces":{"get":{"tags":["GenAI"],"summary":"Query GenAI trace summaries — traces containing spans with `gen_ai.*` attributes.","description":"`duration_ms` is the only field guaranteed to be milliseconds. `gen_ai.*`\nspan attributes (e.g. time-to-first-token, token latency) often follow the\nOTel GenAI semantic conventions, which use **seconds** (a fractional\ndouble), not milliseconds — do not read them as ms without converting.","operationId":"query_genai_traces","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"gen_ai_system","in":"query","description":"Filter by AI system (openai, anthropic, etc.)","required":false,"schema":{"type":"string"}},{"name":"gen_ai_model","in":"query","description":"Filter by model (gpt-4, claude-sonnet-4-20250514, etc.)","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max traces to return (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"GenAI trace summaries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenAiTraceSummariesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/genai/traces/{project_id}/{trace_id}":{"get":{"tags":["GenAI"],"summary":"Get GenAI span details for a specific trace.","description":"`duration_ms` is the only field guaranteed to be milliseconds. `gen_ai.*`\nspan attributes (e.g. time-to-first-token, token latency) often follow the\nOTel GenAI semantic conventions, which use **seconds** (a fractional\ndouble), not milliseconds — do not read them as ms without converting.","operationId":"get_genai_trace","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trace_id","in":"path","description":"Trace ID (hex)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"GenAI trace span details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenAiTraceDetailResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/global/traces/{trace_id}":{"get":{"tags":["Traces"],"summary":"Assemble a unified cross-project span waterfall (Phase 2).","description":"Fans out to every project that holds spans for `trace_id` (up to 20\nprojects, 10,000 total spans). Spans are annotated with\n`project_id`/`project_name` and sorted by `start_time ASC`.\n`truncated: true` signals a hit on either cap; `truncated_projects`\nlists the dropped project IDs. See ADR-027 §4 for the full design.","operationId":"getUnifiedTrace","parameters":[{"name":"trace_id","in":"path","description":"Trace ID (32 lowercase hex characters)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Unified cross-project trace waterfall","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnifiedTrace"}}}},"400":{"description":"trace_id is not 32 lowercase hex characters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions or deployment token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/health/{project_id}":{"get":{"tags":["OTel"],"summary":"Get health summaries for a project.","operationId":"get_health","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Health summaries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/insights/{project_id}":{"get":{"tags":["Insights"],"summary":"List anomaly insights for a project.","operationId":"list_insights","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"status","in":"query","description":"Filter by status (active, resolved)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max insights to return (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Insights list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsightsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/logs":{"get":{"tags":["Telemetry Logs"],"summary":"Query log records with optional filters.","operationId":"query_logs","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"severity","in":"query","description":"Filter by severity (TRACE, DEBUG, INFO, WARN, ERROR, FATAL)","required":false,"schema":{"type":"string"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Full-text search in log body (ILIKE)","required":false,"schema":{"type":"string"}},{"name":"trace_id","in":"query","description":"Filter by correlated trace ID","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max logs to return (default: 100, max: 1000)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Log records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LogsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/metric-label-keys":{"get":{"tags":["Telemetry Metrics"],"summary":"List the attribute (label) keys observed on a metric — powers the\nlabel-filter key autocomplete.","operationId":"list_metric_label_keys","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric_name","in":"query","description":"Metric to inspect","required":true,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Window start (RFC 3339); defaults to 24h before end","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"Window end (RFC 3339); defaults to now","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Distinct label keys","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricLabelKeysResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/metric-label-values":{"get":{"tags":["Telemetry Metrics"],"summary":"List the distinct values seen for a label key on a metric — powers value\nautocomplete once a key is chosen.","operationId":"list_metric_label_values","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric_name","in":"query","description":"Metric to inspect","required":true,"schema":{"type":"string"}},{"name":"label_key","in":"query","description":"Label key whose values to list (must match [a-zA-Z0-9_.:-])","required":true,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Window start (RFC 3339); defaults to 24h before end","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"Window end (RFC 3339); defaults to now","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Distinct label values","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricLabelValuesResponse"}}}},"400":{"description":"Invalid label key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/metric-names/{project_id}":{"get":{"tags":["Telemetry Metrics"],"summary":"List distinct metric names for a project.","operationId":"list_metric_names","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of metric names","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricNamesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/metrics":{"get":{"tags":["Telemetry Metrics"],"summary":"Query metrics with time bucketing.","operationId":"query_metrics","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric_name","in":"query","description":"Filter by metric name","required":false,"schema":{"type":"string"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"environment","in":"query","description":"Filter by deployment environment","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"bucket_interval","in":"query","description":"Bucket interval (e.g. '1 hour', '5 minutes')","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max buckets to return (default: 1000)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"metric_type","in":"query","description":"Filter by metric type (gauge, sum, histogram, exponential_histogram, summary)","required":false,"schema":{"type":"string"}},{"name":"aggregation","in":"query","description":"Per-bucket aggregation: avg (default), sum, min, max, count, rate, p50/p95/p99, quantile:0.95","required":false,"schema":{"type":"string"}},{"name":"label_filters","in":"query","description":"Comma-separated key=value data-point label filters (keys must match [a-zA-Z0-9_.:-])","required":false,"schema":{"type":"string"}},{"name":"group_by","in":"query","description":"Comma-separated label keys to group series by","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Metrics data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricsResponse"}}}},"400":{"description":"Invalid label key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/pipeline-stats":{"get":{"tags":["OTel"],"summary":"Get OTel pipeline statistics (admin/system view).","operationId":"get_pipeline_stats","responses":{"200":{"description":"Pipeline statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PipelineStatsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/quota/{project_id}":{"get":{"tags":["OTel"],"summary":"Get storage quota for a project.","operationId":"get_quota","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Storage quota","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuotaResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/trace-summaries":{"get":{"tags":["Traces"],"summary":"Query trace summaries — one row per trace with span count, error count,\nroot span info, and proper trace-level pagination.","operationId":"query_trace_summaries","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trace_id","in":"query","description":"Filter by trace ID","required":false,"schema":{"type":"string"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Filter by status (OK, ERROR)","required":false,"schema":{"type":"string"}},{"name":"min_duration_ms","in":"query","description":"Minimum trace duration in ms","required":false,"schema":{"type":"number","format":"double"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"name_pattern","in":"query","description":"Filter by span name pattern (ILIKE)","required":false,"schema":{"type":"string"}},{"name":"sort_by","in":"query","description":"Sort field: 'start_time' (default) or 'duration'","required":false,"schema":{"type":"string"}},{"name":"sort_order","in":"query","description":"Sort direction: 'asc' or 'desc' (default)","required":false,"schema":{"type":"string"}},{"name":"include_total","in":"query","description":"Compute the `total` count (default: true). Set false to skip the second aggregation when only the page is needed","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Max traces to return (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Trace summaries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TraceSummariesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/traces":{"get":{"tags":["Traces"],"summary":"Query trace spans with optional filters.","description":"Each returned span has a `duration_ms` field (float, milliseconds) — this is\nthe ONLY field guaranteed to be in milliseconds. Spans also carry an\n`attributes` map of raw key/value pairs exactly as reported by the\ninstrumenting library: numeric attribute values may be seconds, milliseconds,\nmicroseconds, or nanoseconds depending on that library's convention, and\nnothing in this response labels the unit. Never assume an attribute's\nnumeric value shares `duration_ms`'s unit, and never state a duration in\nmilliseconds unless it came from a `duration_ms` field.","operationId":"query_traces","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trace_id","in":"query","description":"Filter by trace ID","required":false,"schema":{"type":"string"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Filter by status (OK, ERROR, UNSET)","required":false,"schema":{"type":"string"}},{"name":"min_duration_ms","in":"query","description":"Minimum span duration in ms","required":false,"schema":{"type":"number","format":"double"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Max spans to return (default: 100, max: 1000)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Trace spans","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TracesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/traces/cross-project/{trace_id}":{"get":{"tags":["Traces"],"summary":"Discover sibling projects that share the same `trace_id` (Phase 1 banner).","description":"Returns an empty `siblings` list when the trace is single-project — never\n404. Project names are included so the UI can render navigation links\nwithout a second round-trip. See ADR-027 §3 for the full auth model and\ntopology-disclosure trade-offs.","operationId":"getCrossProjectTraceSiblings","parameters":[{"name":"trace_id","in":"path","description":"Trace ID (32 lowercase hex characters)","required":true,"schema":{"type":"string"}},{"name":"exclude_project_id","in":"query","description":"Project ID to exclude (the caller's own project) so the UI does not render a self-link","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Sibling projects sharing this trace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrossProjectTraceResponse"}}}},"400":{"description":"trace_id is not 32 lowercase hex characters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions or deployment token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/traces/{project_id}/{trace_id}":{"get":{"tags":["Traces"],"summary":"Get all spans for a specific trace.","description":"Each span has a `duration_ms` field (float, milliseconds) — the ONLY field\nguaranteed to be in milliseconds — plus an `attributes` map of raw\nkey/value pairs exactly as the instrumenting library reported them.\nNumeric attribute values (e.g. connection-pool wait times, queue delays)\nmay be in seconds, milliseconds, microseconds, or nanoseconds depending on\nthat library's own convention; this response never labels the unit. When\nexplaining what a span spent time on, only quote milliseconds from\n`duration_ms` (or from `start_time`/`end_time` deltas) — never assume a raw\nattribute number is already in milliseconds.","operationId":"get_trace","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trace_id","in":"path","description":"Trace ID (hex)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Trace spans tree","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TracesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/v1/logs":{"post":{"tags":["OTel Ingest"],"summary":"Ingest log records via OTLP/HTTP protobuf.","description":"Authenticates via API key in header, decompresses, decodes protobuf,\nchecks rate limit and storage quota, routes high-severity logs\nto DB and all logs to S3.","operationId":"ingest_logs","requestBody":{"description":"OTLP ExportLogsServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Logs accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/metrics":{"post":{"tags":["OTel Ingest"],"summary":"Ingest metrics via OTLP/HTTP protobuf.","description":"Authenticates via API key in header, decompresses, decodes protobuf,\nchecks rate limit and storage quota, then stores.","operationId":"ingest_metrics","requestBody":{"description":"OTLP ExportMetricsServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Metrics accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/traces":{"post":{"tags":["OTel Ingest"],"summary":"Ingest trace spans via OTLP/HTTP protobuf.","description":"Authenticates via API key in header, decompresses, decodes protobuf,\nchecks rate limit and storage quota, then stores spans.","operationId":"ingest_traces","requestBody":{"description":"OTLP ExportTraceServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Traces accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/{project_id}/{environment_id}/{deployment_id}/logs":{"post":{"tags":["OTel Ingest"],"summary":"Ingest log records with project/environment/deployment in the URL path.","operationId":"ingest_logs_by_path","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"OTLP ExportLogsServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Logs accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/{project_id}/{environment_id}/{deployment_id}/metrics":{"post":{"tags":["OTel Ingest"],"summary":"Ingest metrics with project/environment/deployment in the URL path.","operationId":"ingest_metrics_by_path","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"OTLP ExportMetricsServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Metrics accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/{project_id}/{environment_id}/{deployment_id}/traces":{"post":{"tags":["OTel Ingest"],"summary":"Ingest trace spans with project/environment/deployment in the URL path.","operationId":"ingest_traces_by_path","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"OTLP ExportTraceServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Traces accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/performance/has-metrics":{"get":{"tags":["Performance"],"summary":"Check if performance metrics exist for a project","operationId":"has_performance_metrics","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully checked performance metrics availability","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HasMetricsResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/performance/metrics":{"get":{"tags":["Performance"],"summary":"Get performance metrics","operationId":"get_performance_metrics","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Deployment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"device_type","in":"query","description":"Device type filter: desktop or mobile (optional)","required":false,"schema":{"type":"string"}},{"name":"include_bots","in":"query","description":"Include crawler/datacenter bot samples (default false)","required":false,"schema":{"type":"boolean"}},{"name":"filter_path","in":"query","description":"Filter to one page pathname (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_country","in":"query","description":"Filter to one country (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Filter to one region (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Filter to one city (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_browser","in":"query","description":"Filter to one browser (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_operating_system","in":"query","description":"Filter to one operating system (optional)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved performance metrics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PerformanceMetricsResponse"}}}},"400":{"description":"Invalid date format or missing parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/performance/metrics-over-time":{"get":{"tags":["Performance"],"summary":"Get metrics over time","operationId":"get_metrics_over_time","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DDTHH:MM:SSZ","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DDTHH:MM:SSZ","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Deployment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"device_type","in":"query","description":"Device type filter: desktop or mobile (optional)","required":false,"schema":{"type":"string"}},{"name":"include_bots","in":"query","description":"Include crawler/datacenter bot samples (default false)","required":false,"schema":{"type":"boolean"}},{"name":"filter_path","in":"query","description":"Filter to one page pathname (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_country","in":"query","description":"Filter to one country (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Filter to one region (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Filter to one city (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_browser","in":"query","description":"Filter to one browser (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_operating_system","in":"query","description":"Filter to one operating system (optional)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved metrics over time","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetricsOverTimeResponse"}}}},"400":{"description":"Invalid date format or missing parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/performance/page-metrics":{"get":{"tags":["Performance"],"summary":"Get grouped page metrics","operationId":"get_grouped_page_metrics","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DDTHH:MM:SSZ","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DDTHH:MM:SSZ","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Deployment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"group_by","in":"query","description":"Group by: path, country, region, city, device_type, browser, operating_system","required":true,"schema":{"type":"string"}},{"name":"device_type","in":"query","description":"Device type filter: desktop or mobile (optional)","required":false,"schema":{"type":"string"}},{"name":"include_bots","in":"query","description":"Include crawler/datacenter bot samples (default false)","required":false,"schema":{"type":"boolean"}},{"name":"filter_path","in":"query","description":"Filter to one page pathname (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_country","in":"query","description":"Filter to one country (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Filter to one region (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Filter to one city (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_browser","in":"query","description":"Filter to one browser (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_operating_system","in":"query","description":"Filter to one operating system (optional)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved grouped page metrics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroupedPageMetricsResponse"}}}},"400":{"description":"Invalid date format, missing parameters, or invalid group_by value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/platform/access-info":{"get":{"tags":["Platform"],"summary":"Get information about how the service is being accessed","description":"Returns details about the server's access mode, public IP address, private IP address,\nand domain creation capabilities. Both IP addresses are always included when available.","operationId":"get_access_info","responses":{"200":{"description":"Service access information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceAccessInfo"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/platform/private-ip":{"get":{"tags":["Platform"],"summary":"Get private/local IP address of the server","operationId":"get_private_ip","responses":{"200":{"description":"Successfully retrieved private IP address"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/platform/public-ip":{"get":{"tags":["Platform"],"summary":"Get public IP address of the server","operationId":"get_public_ip","responses":{"200":{"description":"Successfully retrieved public IP address"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/presets":{"get":{"tags":["Presets"],"summary":"List all available presets","operationId":"list_presets","responses":{"200":{"description":"List of available presets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListPresetsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/presets/{slug}/dockerfile":{"post":{"tags":["Presets"],"summary":"Generate a Dockerfile from a preset","description":"Returns the Dockerfile content and build arguments for a given preset slug.\nThe CLI can use this to build Docker images locally without needing a Dockerfile\nin the project directory, enabling zero-config deployments.","operationId":"generate_preset_dockerfile","parameters":[{"name":"slug","in":"path","description":"Preset slug (e.g., nextjs, vite, python)","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateDockerfileRequest"}}},"required":true},"responses":{"200":{"description":"Generated Dockerfile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateDockerfileResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Preset not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/logs":{"get":{"tags":["Preview Gateway"],"operationId":"get_preview_gateway_logs","parameters":[{"name":"tail","in":"query","description":"Lines to tail (default 200, max 2000)","required":false,"schema":{"type":"integer","minimum":0}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LogsResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/restart":{"post":{"tags":["Preview Gateway"],"operationId":"restart_preview_gateway","responses":{"204":{"description":"Gateway restarted"}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/settings":{"get":{"tags":["Preview Gateway"],"operationId":"get_preview_gateway_settings","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewGatewaySettingsResponse"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Preview Gateway"],"operationId":"patch_preview_gateway_settings","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PatchSettingsRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewGatewaySettingsResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/status":{"get":{"tags":["Preview Gateway"],"operationId":"get_preview_gateway_status","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayStatus"}}}}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/upgrade":{"post":{"tags":["Preview Gateway"],"operationId":"upgrade_preview_gateway","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpgradeRequest"}}},"required":true},"responses":{"204":{"description":"Gateway upgraded"}},"security":[{"bearer_auth":[]}]}},"/projects":{"get":{"tags":["Projects"],"summary":"Get a list of all projects","operationId":"get_projects","parameters":[{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"per_page","in":"query","description":"Number of items per page","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"List of projects","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedProjectList"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Projects"],"summary":"Create a new project","operationId":"create_project","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectRequest"}}},"required":true},"responses":{"200":{"description":"Project created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"400":{"description":"Invalid input"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/by-slug/{slug}":{"get":{"tags":["Projects"],"summary":"Get details of a specific project by slug","operationId":"get_project_by_slug","parameters":[{"name":"slug","in":"path","description":"Project slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Project details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]}},"/projects/from-template":{"post":{"tags":["Projects"],"summary":"Create a new project from a template","description":"Creates a new repository from a template and sets up the project with the\nspecified configuration. The template is cloned to a new repository under\nthe authenticated user's account or specified organization.","operationId":"create_project_from_template","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectFromTemplateRequest"}}},"required":true},"responses":{"201":{"description":"Project created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectFromTemplateResponse"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Template not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/statistics":{"get":{"tags":["Projects"],"summary":"Get project statistics","operationId":"get_project_statistics","responses":{"200":{"description":"Project statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectStatisticsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{id}":{"get":{"tags":["Projects"],"summary":"Get details of a specific project","operationId":"get_project","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Project details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Projects"],"operationId":"update_project","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectRequest"}}},"required":true},"responses":{"200":{"description":"Project updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Projects"],"operationId":"delete_project","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Project deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{id}/deployments":{"get":{"tags":["Projects"],"operationId":"get_project_deployments","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"per_page","in":"query","description":"Items per page","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"environment_id","in":"query","description":"Environment ID filter","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of deployments","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentListResponse"}}}},"404":{"description":"Project not found"}}}},"/projects/{id}/last-deployment":{"get":{"tags":["Deployments"],"summary":"Get the last deployment for a specific project","operationId":"get_last_deployment","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Last deployment details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentResponse"}}}},"404":{"description":"Project not found or no deployments"},"500":{"description":"Internal server error"}}}},"/projects/{id}/source":{"patch":{"tags":["Projects"],"summary":"Change a project's source type to a Git-less type (docker_image /\nstatic_files / manual). Switching TO Git is done via the Git settings\nendpoint (`POST /projects/{id}/git`), which also supplies the repository and\nprovider connection.","operationId":"change_project_source","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeProjectSourceRequest"}}},"required":true},"responses":{"200":{"description":"Source type changed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"400":{"description":"Invalid source type change (e.g. switching to Git here)"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{id}/trigger-pipeline":{"post":{"tags":["Projects"],"summary":"Trigger pipeline for a specific project","operationId":"trigger_project_pipeline","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerPipelinePayload"}}},"required":true},"responses":{"200":{"description":"Pipeline triggered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerPipelineResponse"}}}},"400":{"description":"Invalid request"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/access":{"get":{"tags":["Teams"],"operationId":"list_project_access","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Access grants","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectAccessResponse"}}}}},"403":{"description":"Insufficient permissions or no access to this project"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Teams"],"operationId":"grant_project_access","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectAccessRequest"}}},"required":true},"responses":{"201":{"description":"Access granted (idempotent upsert)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectAccessResponse"}}}},"403":{"description":"Insufficient permissions or no access to this project"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/access/{team_id}":{"delete":{"tags":["Teams"],"operationId":"revoke_project_access","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Access revoked"},"403":{"description":"Insufficient permissions or no access to this project"},"404":{"description":"Grant not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/active-visitors":{"get":{"tags":["Events"],"summary":"Get active visitors count","operationId":"get_active_visitors","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved active visitors count","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActiveVisitorsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents":{"get":{"tags":["Agents"],"operationId":"list_agents","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of agents for project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListAgentsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertAgentRequest"}}},"required":true},"responses":{"201":{"description":"Agent created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentConfigResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/cli-status":{"get":{"tags":["Agents"],"operationId":"get_cli_status","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"provider","in":"query","description":"AI provider: claude_cli or codex_cli","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"CLI status"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs":{"get":{"tags":["Agents"],"operationId":"list_all_runs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of all agent runs for a project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListRunsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/latest-for-source":{"get":{"tags":["Agents"],"operationId":"latest_run_for_source","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trigger_source_type","in":"query","description":"Trigger source type, e.g. 'error_group'","required":true,"schema":{"type":"string"}},{"name":"trigger_source_id","in":"query","description":"Trigger source ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Latest matching run, or null if none","content":{"application/json":{"schema":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AgentRunResponse"}]}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/{run_id}":{"get":{"tags":["Agents"],"operationId":"get_run_with_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Run with logs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunWithLogsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/{run_id}/cancel":{"post":{"tags":["Agents"],"operationId":"cancel_run","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Agent run ID to cancel","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Run cancelled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunResponse"}}}},"400":{"description":"Run is already in a terminal state"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/{run_id}/retry":{"post":{"tags":["Agents"],"summary":"Retry a completed, failed, cancelled, or no_fix run with the same trigger context.\nCreates a new run record and spawns the executor.","operationId":"retry_run","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID to retry","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"New run created from retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunResponse"}}}},"400":{"description":"Run is still active"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/{run_id}/stream":{"get":{"tags":["Agents"],"summary":"SSE endpoint for real-time streaming of run events.\nPolls the agent_run_logs table every 500ms for new entries and streams them.\nCloses when the run reaches a terminal status.","operationId":"stream_run_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Agent run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Server-Sent Events stream of run log events and terminal status","content":{"text/event-stream":{}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/sandbox-status":{"get":{"tags":["Agents"],"operationId":"get_sandbox_status","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Project-scoped sandbox readiness (Docker + agent image)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/smoke-test":{"post":{"tags":["Agents"],"summary":"Run a smoke test to verify the selected AI CLI works in the environment\nwhere agents will actually execute (host or sandbox container). If no\n`provider_id` is supplied the globally active provider is tested.","operationId":"smoke_test_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"provider_id","in":"query","description":"Provider id to test; defaults to the globally active provider","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Smoke test result for the AI CLI in the agent's execution environment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SmokeTestResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/{slug}":{"get":{"tags":["Agents"],"operationId":"get_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Agent config","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentConfigResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertAgentRequest"}}},"required":true},"responses":{"200":{"description":"Agent updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentConfigResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Agent deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/{slug}/runs":{"get":{"tags":["Agents"],"operationId":"list_agent_runs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of runs for a specific agent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListRunsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/{slug}/trigger":{"post":{"tags":["Agents"],"operationId":"trigger_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerAgentRequest"}}},"required":true},"responses":{"202":{"description":"Agent run created and queued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"402":{"description":"Daily budget exceeded"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"},"422":{"description":"AI CLI not installed"},"429":{"description":"Cooldown active"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/aggregated-buckets":{"get":{"tags":["Events"],"summary":"Get aggregated metrics by time bucket","operationId":"get_aggregated_buckets","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for the query range","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for the query range","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Optional environment filter","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Optional deployment filter","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors (default: events)","required":false,"schema":{"type":"string"}},{"name":"bucket_size","in":"query","description":"Time bucket size: '1 hour', '1 day', '1 week', etc. (default: '1 hour')","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved aggregated buckets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AggregatedBucketsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations":{"get":{"tags":["AI Chat"],"summary":"Find the existing chat for a context (returns `null` if none yet). Requires\nthe per-project `ai_debug_chat_enabled` toggle to be on; returns 403 when the\nfeature is disabled so revoking it consistently hides existing chat content.","operationId":"find_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"context_type","in":"query","required":true,"schema":{"type":"string"}},{"name":"context_id","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ConversationResponse"}]}}}},"401":{"description":""},"403":{"description":""}},"security":[{"bearer_auth":[]}]},"post":{"tags":["AI Chat"],"summary":"Get-or-create the chat for a context (seeds it on first open).","operationId":"create_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateConversationRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/list":{"get":{"tags":["AI Chat"],"summary":"List all active conversations for a project, most-recently-active first.\nPowers the conversation switcher in the AI assistant sidebar.","operationId":"list_conversations","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ConversationResponse"}}}}},"401":{"description":""},"403":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/{public_id}":{"get":{"tags":["AI Chat"],"summary":"Full conversation history (excluding the internal system seed).","operationId":"get_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationDetailResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["AI Chat"],"summary":"Rename a conversation (set its human-facing title).","operationId":"rename_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenameConversationRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationResponse"}}}},"400":{"description":""},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/{public_id}/archive":{"post":{"tags":["AI Chat"],"summary":"Archive (soft-delete) a conversation.","operationId":"archive_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":""},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/{public_id}/messages":{"post":{"tags":["AI Chat"],"summary":"Send a user message; stream the assistant reply as Server-Sent Events.","operationId":"send_message","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendMessageRequest"}}},"required":true},"responses":{"200":{"description":"SSE stream of assistant text deltas","content":{"text/event-stream":{}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/{public_id}/pending-actions":{"get":{"tags":["AI Chat"],"summary":"List all pending actions for a conversation (most-recently-proposed first).","operationId":"list_pending_actions","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","description":"Conversation public id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PendingActionResponse"}}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/pending-actions/{action_public_id}":{"get":{"tags":["AI Chat"],"summary":"Get a single pending action by its public id (scoped to the project).","operationId":"get_pending_action","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"action_public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PendingActionResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/pending-actions/{action_public_id}/confirm":{"post":{"tags":["AI Chat"],"summary":"Confirm a proposed AI action: validate permission, atomically claim, execute,\npersist outcome. The execution uses the CONFIRMING user's auth — never the model's.","operationId":"confirm_pending_action","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"action_public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PendingActionResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""},"409":{"description":""},"503":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/pending-actions/{action_public_id}/reject":{"post":{"tags":["AI Chat"],"summary":"Reject a proposed AI action (no execution). Status transitions to \"rejected\".","operationId":"reject_pending_action","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"action_public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PendingActionResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""},"409":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/readiness":{"get":{"tags":["AI Chat"],"summary":"Report which AI prerequisites this project satisfies.","description":"Read-only and cheap, so the UI can decide up front whether to show a working\nentry point, an onboarding path, or nothing — instead of letting the user\nclick something that fails with a 409 they can't act on.","operationId":"get_chat_readiness","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Which AI prerequisites are met","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatReadinessResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/alarms":{"get":{"tags":["Alarms"],"summary":"List alarms for a project with optional filters.","operationId":"listProjectAlarms","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"alarm_type","in":"query","description":"Filter by alarm type (e.g. `container_restart`, `outage`).","required":false,"schema":{"type":["string","null"]}},{"name":"status","in":"query","description":"Filter by status: `firing`, `acknowledged`, or `resolved`.","required":false,"schema":{"type":["string","null"]}},{"name":"severity","in":"query","description":"Filter by severity: `info`, `warning`, or `critical`.","required":false,"schema":{"type":["string","null"]}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"service_id","in":"query","description":"Filter by external service ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based, default 1).","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default 20, max 100).","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"Paginated list of alarms","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlarmListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/alarms/summary":{"get":{"tags":["Alarms"],"summary":"Get alarm counts by status/severity/type for a project (dashboard summary widget).","operationId":"getProjectAlarmsSummary","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alarm summary counts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlarmSummaryResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/alarms/{alarm_id}/acknowledge":{"post":{"tags":["Alarms"],"summary":"Acknowledge a firing alarm (marks it as seen but not resolved).","operationId":"acknowledgeAlarm","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"alarm_id","in":"path","description":"Alarm ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alarm acknowledged"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Alarm not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/alarms/{alarm_id}/resolve":{"post":{"tags":["Alarms"],"summary":"Resolve an alarm.","operationId":"resolveAlarm","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"alarm_id","in":"path","description":"Alarm ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alarm resolved"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Alarm not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/analyze":{"post":{"tags":["Autofixer"],"summary":"Start an autofixer analysis run for the given error group.\nCreates the run record immediately and spawns analysis in the background.","operationId":"start_analysis","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartAnalysisRequest"}}},"required":true},"responses":{"202":{"description":"Analysis started; returns run_id for streaming","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutofixerRunResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}":{"get":{"tags":["Autofixer"],"summary":"Get a single autofixer run with its logs.","operationId":"get_run","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Run with logs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutofixerRunWithLogsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/add-context":{"post":{"tags":["Autofixer"],"summary":"Append a user message to the run's context field.","operationId":"add_context","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddContextRequest"}}},"required":true},"responses":{"200":{"description":"Context appended"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/cancel":{"post":{"tags":["Autofixer"],"summary":"Cancel an autofixer run and clean up the work directory.","operationId":"cancel","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Run cancelled"},"400":{"description":"Run is already in a terminal state"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/create-pr":{"post":{"tags":["Autofixer"],"summary":"Push the fix branch and create a pull request.\nRequires phase == \"fix_ready\".","operationId":"create_pr","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"201":{"description":"PR created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePrResponse"}}}},"400":{"description":"Run not in fix_ready phase"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/fix":{"post":{"tags":["Autofixer"],"summary":"Transition from analysis to fix phase.\nRequires phase == \"analyzed\".","operationId":"start_fix","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Fix generation started"},"400":{"description":"Run not in analyzed phase"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/re-analyze":{"post":{"tags":["Autofixer"],"summary":"Continue the conversation with user feedback.\nUses the same Claude session (--continue) in the existing work directory.\nRequires phase == \"analyzed\".","operationId":"re_analyze","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Conversation continued with feedback"},"400":{"description":"Run not in analyzed phase"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/stream":{"get":{"tags":["Agents"],"summary":"SSE endpoint: streams run log events in real-time.\nPolls every 500 ms. Keeps the connection open through \"analyzed\" and \"fix_ready\"\nwaiting states; closes only on terminal statuses.","operationId":"stream_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Autofixer run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Server-Sent Events stream of autofixer run logs and status updates","content":{"text/event-stream":{}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/automatic-deploy":{"post":{"tags":["Projects"],"summary":"Update automatic deployment setting for a project","operationId":"update_automatic_deploy","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAutomaticDeployRequest"}}},"required":true},"responses":{"200":{"description":"Automatic deployment setting updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/custom-domains":{"get":{"tags":["Custom Domains"],"summary":"List all custom domains for a project","operationId":"list_custom_domains_for_project","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Custom domains retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListCustomDomainsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Custom Domains"],"summary":"Create a custom domain for a project","operationId":"create_custom_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainRequest"}}},"required":true},"responses":{"201":{"description":"Custom domain created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainResponse"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"409":{"description":"Domain already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/custom-domains/{domain_id}":{"get":{"tags":["Custom Domains"],"summary":"Get a custom domain by ID","operationId":"get_custom_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Custom domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Custom domain retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Custom domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Custom Domains"],"summary":"Update a custom domain","operationId":"update_custom_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Custom domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCustomDomainRequest"}}},"required":true},"responses":{"200":{"description":"Custom domain updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainResponse"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"404":{"description":"Custom domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Custom Domains"],"summary":"Delete a custom domain","operationId":"delete_custom_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Custom domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Custom domain deleted successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Custom domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/custom-domains/{domain_id}/link-certificate/{certificate_id}":{"post":{"tags":["Custom Domains"],"summary":"Link a custom domain to a certificate","operationId":"link_custom_domain_to_certificate","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Custom domain ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"certificate_id","in":"path","description":"Certificate ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Custom domain linked to certificate successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Custom domain or certificate not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployment-config":{"patch":{"tags":["Projects"],"summary":"Update deployment configuration for a project","operationId":"update_project_deployment_config","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDeploymentConfigRequest"}}},"required":true},"responses":{"200":{"description":"Deployment configuration updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"400":{"description":"Invalid deployment configuration"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployment-tokens":{"get":{"tags":["Deployment Tokens"],"summary":"List all deployment tokens for a project","operationId":"list_deployment_tokens","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of deployment tokens","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentTokenListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Deployment Tokens"],"summary":"Create a new deployment token for a project","operationId":"create_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDeploymentTokenRequest"}}},"required":true},"responses":{"201":{"description":"Deployment token created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDeploymentTokenResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"409":{"description":"Token with this name already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployment-tokens/{token_id}":{"get":{"tags":["Deployment Tokens"],"summary":"Get a specific deployment token","operationId":"get_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"token_id","in":"path","description":"Deployment token ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment token details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment token not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Deployment Tokens"],"summary":"Delete a deployment token","operationId":"delete_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"token_id","in":"path","description":"Deployment token ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Deployment token deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment token not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Deployment Tokens"],"summary":"Update a deployment token","operationId":"update_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"token_id","in":"path","description":"Deployment token ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDeploymentTokenRequest"}}},"required":true},"responses":{"200":{"description":"Deployment token updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentTokenResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment token not found"},"409":{"description":"Token with this name already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployment-tokens/{token_id}/rotate":{"post":{"tags":["Deployment Tokens"],"summary":"Rotate a deployment token, invalidating its old secret and issuing a new one","operationId":"rotate_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"token_id","in":"path","description":"Deployment token ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment token rotated successfully; the response contains the new plaintext token, shown only once","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDeploymentTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment token not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployments/{deployment_id}":{"get":{"tags":["Deployments"],"summary":"Get a specific deployment by ID for a project (identified by ID or slug)","operationId":"get_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentResponse"}}}},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/cancel":{"post":{"tags":["Projects"],"summary":"Cancel a deployment","operationId":"cancel_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment cancelled successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentStateResponse"}}}},"400":{"description":"Deployment cannot be cancelled (already completed, failed, or cancelled)"},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/container-logs":{"get":{"tags":["Deployments"],"summary":"List the captured (historical) container-log dumps for a deployment.","description":"Container runtime logs are normally only available live from the running\ncontainer. When a deployment is superseded its containers are torn down and\nthose logs would be lost — so just before teardown we capture each\ncontainer's logs to durable storage. This endpoint lists what was captured\nfor a given (often older) deployment, so a user can read the logs of a\ncontainer that no longer exists.","operationId":"list_deployment_container_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Captured container logs for the deployment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentContainerLogsListResponse"}}}},"404":{"description":"Deployment not found in this project"},"500":{"description":"Internal server error"}},"security":[{"bearer_token":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/container-logs/{log_id}":{"get":{"tags":["Deployments"],"summary":"Get the captured text content of a single historical container-log dump.","operationId":"get_deployment_container_log_content","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"log_id","in":"path","description":"Captured log ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Captured container log content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentContainerLogContentResponse"}}}},"404":{"description":"Captured log not found in this project"},"500":{"description":"Internal server error"}},"security":[{"bearer_token":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/jobs":{"get":{"tags":["Deployments"],"summary":"Get jobs for a specific deployment","description":"Returns all jobs (workflow tasks) for a deployment, ordered by execution order.\nThis replaces the old deployment stages endpoint.","operationId":"get_deployment_jobs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Jobs retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentJobsResponse"}}}},"404":{"description":"Deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/jobs/{job_id}/logs":{"get":{"tags":["Deployments"],"summary":"Get logs for a specific deployment job","operationId":"get_deployment_job_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"job_id","in":"path","description":"Job ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Job logs retrieved successfully","content":{"text/plain":{"schema":{"type":"string"}}}},"404":{"description":"Job or logs not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_token":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/jobs/{job_id}/logs/tail":{"get":{"tags":["Deployments"],"summary":"Tail logs for a specific deployment job in real-time via WebSocket","description":"**WebSocket Streaming**: Logs are sent as raw text, one line per WebSocket message.\n\n**Authentication**: Requires authentication via session cookie (browser clients)\nor API key (API clients). For browser-based WebSocket connections, ensure the user\nis logged in - the browser automatically includes session cookies in the WebSocket\nupgrade request.\n\n**API Client Authentication**: Include API key in Authorization header:\n```text\nAuthorization: Bearer tk_your_api_key_here\n```","operationId":"tail_deployment_job_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"job_id","in":"path","description":"Job ID","required":true,"schema":{"type":"string"}}],"responses":{"101":{"description":"WebSocket connection established for streaming deployment job logs"},"404":{"description":"Job or logs not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_token":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/operations":{"get":{"tags":["Deployments"],"summary":"Get all operations for a deployment","operationId":"get_deployment_operations","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of operations","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperationResultsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Deployments"],"summary":"Execute a deployment operation (deploy, mark_complete, take_screenshot)","operationId":"execute_deployment_operation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteOperationRequest"}}},"required":true},"responses":{"202":{"description":"Operation executed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperationResultResponse"}}}},"400":{"description":"Invalid operation"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/operations/{operation_type}":{"get":{"tags":["Deployments"],"summary":"Get the status of a specific operation type","operationId":"get_deployment_operation_status","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","required":true,"schema":{"type":"string"}},{"name":"operation_type","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Operation status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperationResultResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Operation not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/pause":{"post":{"tags":["Projects"],"summary":"Pause a deployment","operationId":"pause_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment paused successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentStateResponse"}}}},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/promote":{"post":{"tags":["Deployments"],"summary":"Promote a deployment to another environment","description":"Creates a new deployment in the target environment using the source deployment's\nDocker image. Useful for promoting a validated preview/staging deployment to production.","operationId":"promote_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Source deployment ID to promote","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromoteDeploymentRequest"}}},"required":true},"responses":{"200":{"description":"Promotion initiated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentResponse"}}}},"400":{"description":"Invalid deployment state for promotion"},"404":{"description":"Project, deployment, or target environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/resume":{"post":{"tags":["Projects"],"summary":"Resume a deployment","operationId":"resume_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment resumed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentStateResponse"}}}},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/rollback":{"post":{"tags":["Projects"],"operationId":"rollback_to_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID to rollback to","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Rollback initiated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentResponse"}}}},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/teardown":{"delete":{"tags":["Projects"],"summary":"Teardown a specific deployment","operationId":"teardown_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Deployment torn down successfully"},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/dsns":{"get":{"tags":[],"summary":"List all DSNs for a project","operationId":"list_dsns","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of DSNs","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectDSNResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":[],"summary":"Create a new DSN for a project","operationId":"create_dsn","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDSNRequest"}}},"required":true},"responses":{"201":{"description":"DSN created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDSNResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/dsns/get-or-create":{"post":{"tags":[],"summary":"Get or create DSN for a project/environment/deployment combination","operationId":"get_or_create_dsn","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetOrCreateDSNRequest"}}},"required":true},"responses":{"200":{"description":"DSN retrieved or created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDSNResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/dsns/{dsn_id}/regenerate":{"post":{"tags":[],"summary":"Regenerate DSN keys (rotate keys)","operationId":"regenerate_dsn","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"dsn_id","in":"path","description":"DSN ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegenerateDSNRequest"}}},"required":true},"responses":{"200":{"description":"DSN keys regenerated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDSNResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"DSN not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/dsns/{dsn_id}/revoke":{"post":{"tags":[],"summary":"Revoke (deactivate) a DSN","operationId":"revoke_dsn","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"dsn_id","in":"path","description":"DSN ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"DSN revoked"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"DSN not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/env-vars":{"get":{"tags":["Projects"],"summary":"Get environment variables for a project, optionally filtered by environment","operationId":"get_environment_variables","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Optional environment ID to filter by","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environment variables","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentVariableResponse"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["Projects"],"summary":"Create a new environment variable","operationId":"create_environment_variable","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEnvironmentVariableRequest"}}},"required":true},"responses":{"201":{"description":"Environment variables created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableResponse"}}}},"400":{"description":"Invalid input"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/env-vars/resolved":{"get":{"tags":["Projects"],"summary":"Resolved env vars for a project (manual + integration-sourced, merged).","description":"Returns the effective set of environment variables a deployment would see,\ncombining manually-defined vars with those contributed by linked external\nservices (Postgres, Redis, S3, etc.). Each entry is tagged with its source\nso the UI can render an integration icon, and manual entries that shadow an\nintegration key carry a reference to the integration they override.\n\nValues are always returned as a masked preview. Use the per-key reveal\nendpoint for plaintext (audit-logged).","operationId":"get_resolved_environment_variables","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Optional environment ID to filter manual vars by","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Resolved environment variables","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ResolvedEnvVarResponse"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/env-vars/resolved/{key}/value":{"get":{"tags":["Projects"],"summary":"Reveal the plaintext value of a resolved environment variable.","description":"Mirrors `GET /projects/{id}/env-vars/{key}/value` but handles keys sourced\nfrom linked integrations (which are not stored in the `env_vars` table).\nResolution order mirrors the merged view:\n\n1. Manual env var with this key — this endpoint reads the manual store when\n the key exists there, then writes its own reveal audit event so callers\n can safely use one endpoint regardless of source.\n2. Integration env var supplied by a linked external service.\n\nReturns 404 when neither a manual var nor an integration produces the key.","operationId":"get_resolved_environment_variable_value","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Environment variable key","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Optional environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"var_id","in":"query","description":"Exact manual environment-variable row ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"service_id","in":"query","description":"Integration service ID shown by the resolved list","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Resolved environment variable value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableValueResponse"}}}},"403":{"description":"Plaintext secret access is not permitted"},"404":{"description":"Project, key, or integration not found"},"409":{"description":"Environment variable key is ambiguous"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/env-vars/{key}/value":{"get":{"tags":["Projects"],"summary":"Get environment variable value by key","operationId":"get_environment_variable_value","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Environment variable key","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Optional environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"var_id","in":"query","description":"Exact environment-variable row ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Environment variable value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableValueResponse"}}}},"403":{"description":"Plaintext secret access is not permitted"},"404":{"description":"Project or variable not found"},"409":{"description":"Environment variable key is ambiguous"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/env-vars/{var_id}":{"put":{"tags":["Projects"],"summary":"Update an environment variable","operationId":"update_environment_variable","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"var_id","in":"path","description":"Environment variable ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEnvironmentVariableRequest"}}},"required":true},"responses":{"200":{"description":"Environment variables updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableResponse"}}}},"400":{"description":"Invalid input"},"404":{"description":"Project or variable not found"},"500":{"description":"Internal server error"}}},"delete":{"tags":["Projects"],"summary":"Delete an environment variable","operationId":"delete_environment_variable","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"var_id","in":"path","description":"Environment variable ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Environment variable deleted successfully"},"404":{"description":"Project or variable not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments":{"get":{"tags":["Projects"],"summary":"Get all environments for a project","operationId":"get_environments","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environments","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentResponse"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["Projects"],"summary":"Create a new environment for a project","operationId":"create_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEnvironmentRequest"}}},"required":true},"responses":{"201":{"description":"Environment created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"400":{"description":"Invalid input"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}":{"get":{"tags":["Projects"],"summary":"Get a specific environment by ID or slug","operationId":"get_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Environment details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}},"delete":{"tags":["Projects"],"summary":"Delete an environment permanently","description":"Permanently deletes an environment and all related data. Cannot delete:\n- Production environments (name = \"Production\")\n\nWarning: This action is permanent and cannot be undone.\nActive deployments are automatically cancelled before deletion.","operationId":"delete_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Environment permanently deleted"},"400":{"description":"Cannot delete production environment"},"404":{"description":"Project or environment not found"},"428":{"description":"Recent MFA verification required"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/crons":{"get":{"tags":["Crons"],"operationId":"get_environment_crons","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of cron jobs","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CronInfo"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/crons/{cron_id}":{"get":{"tags":["Crons"],"operationId":"get_cron_by_id","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"cron_id","in":"path","description":"Cron Job ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Cron job details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CronInfo"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Cron job not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/crons/{cron_id}/executions":{"get":{"tags":["Crons"],"operationId":"get_cron_executions","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"cron_id","in":"path","description":"Cron Job ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"per_page","in":"query","description":"Items per page (default: 20)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"List of cron job executions","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CronExecutionInfo"}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Cron job not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/domains":{"get":{"tags":["Projects"],"summary":"Get all environment domains for a specific environment","operationId":"get_environment_domains","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environment domains","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentDomainResponse"}}}}},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["Projects"],"summary":"Add a new environment domain","operationId":"add_environment_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddEnvironmentDomainRequest"}}},"required":true},"responses":{"201":{"description":"Domain added successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentDomainResponse"}}}},"400":{"description":"Invalid input"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/domains/{domain_id}":{"delete":{"tags":["Projects"],"summary":"Delete an environment domain","operationId":"delete_environment_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Domain deleted successfully"},"404":{"description":"Project, environment, or domain not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/settings":{"put":{"tags":["Projects"],"summary":"Update environment settings","operationId":"update_environment_settings","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEnvironmentSettingsRequest"}}},"required":true},"responses":{"200":{"description":"Environment settings updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/sleep":{"post":{"tags":["Environments"],"summary":"Sleep an on-demand environment","description":"Manually put an on-demand environment to sleep. Stops containers and sets\n`sleeping = true`. If no OnDemandWaker is available, falls back to DB flag only.","operationId":"sleep_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Environment put to sleep","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"400":{"description":"On-demand not enabled for this environment"},"404":{"description":"Environment not found"},"429":{"description":"Too many state transitions, retry after cooldown"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/subdomain":{"patch":{"tags":["Projects"],"summary":"Rename the auto-managed subdomain for an environment.","description":"Replaces the environment's previous subdomain entirely — the old\nhostname stops resolving once the proxy reloads its route table.\nCustom domains attached to the environment are unaffected.","operationId":"update_environment_subdomain","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEnvironmentSubdomainRequest"}}},"required":true},"responses":{"200":{"description":"Subdomain updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"400":{"description":"Invalid subdomain or conflict with another environment"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/teardown":{"delete":{"tags":["Projects"],"summary":"Teardown an environment and all its active deployments","operationId":"teardown_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Environment torn down successfully"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/wake":{"post":{"tags":["Environments"],"summary":"Wake a sleeping on-demand environment","description":"Manually wake an environment that has been put to sleep by the on-demand\nidle timeout. Starts containers, waits for health checks, then sets\n`sleeping = false`. If no OnDemandWaker is available (proxy not running\nin same process), falls back to setting the DB flag only.","operationId":"wake_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Environment woken up","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"400":{"description":"On-demand not enabled for this environment"},"404":{"description":"Environment not found"},"429":{"description":"Too many state transitions, retry after cooldown"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/container-logs":{"get":{"tags":["Deployments"],"summary":"Get logs for a container in an environment via WebSocket","operationId":"get_container_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for logs","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"end_date","in":"query","description":"End date for logs","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tail","in":"query","description":"Number of lines to tail (or 'all')","required":false,"schema":{"type":"string"}},{"name":"container_name","in":"query","description":"Optional container name (defaults to first/primary container)","required":false,"schema":{"type":"string"}},{"name":"timestamps","in":"query","description":"Include timestamps in log output (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"follow","in":"query","description":"Follow log output in real-time (default: true)","required":false,"schema":{"type":"boolean"}}],"responses":{"101":{"description":"WebSocket connection established for streaming container logs"},"400":{"description":"Not a server-type project"},"404":{"description":"Project, deployment, or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers":{"get":{"tags":["Deployments"],"summary":"List all containers for an environment","operationId":"list_containers","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of containers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerListResponse"}}}},"400":{"description":"Not a server-type project"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}":{"get":{"tags":["Containers"],"summary":"Get detailed information about a specific container","operationId":"get_container_detail","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerDetailResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/environment/{variable_name}":{"get":{"tags":["Containers"],"operationId":"get_container_environment_variable","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}},{"name":"variable_name","in":"path","description":"Environment variable name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Environment variable value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerEnvironmentVariableValueResponse"}}}},"403":{"description":"Plaintext secret access is not permitted"},"404":{"description":"Container or environment variable not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/logs":{"get":{"tags":["Deployments"],"summary":"Get logs for a specific container by container ID via WebSocket","operationId":"get_container_logs_by_id","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}},{"name":"start_date","in":"query","description":"Start date for logs","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"end_date","in":"query","description":"End date for logs","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tail","in":"query","description":"Number of lines to tail (or 'all')","required":false,"schema":{"type":"string"}},{"name":"timestamps","in":"query","description":"Include timestamps in log output (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"follow","in":"query","description":"Follow log output in real-time (default: true)","required":false,"schema":{"type":"boolean"}}],"responses":{"101":{"description":"WebSocket connection established for streaming container logs"},"400":{"description":"Not a server-type project"},"404":{"description":"Project, environment, or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/metrics":{"get":{"tags":["Containers"],"summary":"Get metrics/stats for a specific container","operationId":"get_container_metrics","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container metrics retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerMetricsResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/metrics/history":{"get":{"tags":["Containers"],"summary":"Fetch a time-series range for a single container resource metric\n(recorded by the container health monitor every ~30s).","description":"Useful metric names: `container.cpu_percent`,\n`container.cpu_utilization_percent`, `container.memory_used_bytes`,\n`container.memory_percent`, `container.network_rx_bytes_delta`,\n`container.network_tx_bytes_delta`.","operationId":"ContainerMetricsGetHistory","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}},{"name":"metric","in":"query","description":"Dotted metric name, e.g. `container.cpu_percent` or\n`container.memory_used_bytes`.","required":true,"schema":{"type":"string"}},{"name":"range","in":"query","description":"Time window: `1h`, `6h`, `24h`, or `7d` (defaults to `1h`).","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Metric time series data points","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ContainerMetricHistoryPoint"}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Container not found"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/metrics/stream":{"get":{"tags":["Containers"],"summary":"Stream container metrics via Server-Sent Events (SSE)","operationId":"stream_container_metrics","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}},{"name":"interval","in":"query","description":"Update interval in milliseconds (default: 1000)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Metrics stream established (Server-Sent Events)"},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/restart":{"post":{"tags":["Containers"],"summary":"Restart a container","operationId":"restart_container","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container restarted successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerActionResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/start":{"post":{"tags":["Containers"],"summary":"Start a container","operationId":"start_container","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container started successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerActionResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/stop":{"post":{"tags":["Containers"],"summary":"Stop a specific container","operationId":"stop_container","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container stopped successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerActionResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/deploy/image":{"post":{"tags":["Deployments"],"summary":"Deploy from an external Docker image","description":"Triggers a deployment using a pre-built Docker image from an external registry.\nThe image will be pulled and deployed to the specified environment.","operationId":"deploy_from_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeployFromImageRequest"}}},"required":true},"responses":{"202":{"description":"Deployment started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoteDeploymentResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/deploy/image-upload":{"post":{"tags":["Deployments"],"summary":"Deploy from an uploaded Docker image tarball","description":"Uploads a Docker image tarball (from `docker save`) and deploys it directly.\nThe image is imported using `docker load` and then deployed to the specified environment.\nThis is useful when you want to deploy an image without pushing to a registry first.\n\nThe uploaded file should be a tarball created by `docker save myimage:tag > image.tar`\nor `docker save myimage:tag | gzip > image.tar.gz` (gzip compressed tarballs are also supported).","operationId":"deploy_from_image_upload","parameters":[{"name":"tag","in":"query","description":"Tag to apply to the imported image (e.g., \"myapp:v1.0\")\nIf not provided, a unique tag will be generated","required":false,"schema":{"type":["string","null"]}},{"name":"health_check_path","in":"query","description":"Optional HTTP health-check path override (e.g. \"/api/healthz\").\nMust start with '/'. When omitted, defaults to \"/\".","required":false,"schema":{"type":["string","null"]}},{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Image imported and deployment started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoteDeploymentResponse"}}}},"400":{"description":"Invalid request or unsupported format"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project or environment not found"},"413":{"description":"Image tarball too large"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/deploy/source":{"post":{"tags":["Deployments"],"summary":"Upload source code and immediately start a preset-based deployment.","operationId":"deploy_from_uploaded_source","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/SourceArchiveUpload"}}},"required":true},"responses":{"202":{"description":"Source deployment started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoteDeploymentResponse"}}}},"400":{"description":"Invalid source archive"},"404":{"description":"Project or environment not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/deploy/static":{"post":{"tags":["Deployments"],"summary":"Deploy from an uploaded static bundle","description":"Triggers a deployment using a previously uploaded static file bundle.","operationId":"deploy_from_static","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeployFromStaticRequest"}}},"required":true},"responses":{"202":{"description":"Deployment started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoteDeploymentResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project, environment, or bundle not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/error-alert-rules":{"get":{"tags":["error-alert-rules"],"summary":"List all alert rules for a project","operationId":"list_alert_rules","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of alert rules","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AlertRuleResponse"}}}}},"500":{"description":"Internal server error"}}},"post":{"tags":["error-alert-rules"],"summary":"Create a new alert rule","operationId":"create_alert_rule","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAlertRuleRequest"}}},"required":true},"responses":{"201":{"description":"Alert rule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertRuleResponse"}}}},"400":{"description":"Validation error"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-alert-rules/{rule_id}":{"get":{"tags":["error-alert-rules"],"summary":"Get a specific alert rule","operationId":"get_alert_rule","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alert rule details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertRuleResponse"}}}},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}}},"put":{"tags":["error-alert-rules"],"summary":"Update an existing alert rule","operationId":"update_alert_rule","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAlertRuleRequest"}}},"required":true},"responses":{"200":{"description":"Alert rule updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertRuleResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}}},"delete":{"tags":["error-alert-rules"],"summary":"Delete an alert rule","operationId":"delete_alert_rule","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Alert rule deleted"},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-dashboard-stats":{"get":{"tags":["error-tracking"],"summary":"Get error dashboard statistics","operationId":"get_error_dashboard_stats","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"end_time","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"environment_id","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"compare_to_previous","in":"query","required":false,"schema":{"type":["boolean","null"]}}],"responses":{"200":{"description":"Error dashboard statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDashboardStatsResponse"}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-groups":{"get":{"tags":["error-tracking"],"summary":"List error groups for a project","operationId":"list_error_groups","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"status","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"environment_id","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_date","in":"query","required":false,"schema":{"type":["string","null"],"format":"date-time"}},{"name":"end_date","in":"query","required":false,"schema":{"type":["string","null"],"format":"date-time"}},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated list of error groups","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedErrorGroupsResponse"}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-groups/{group_id}":{"get":{"tags":["error-tracking"],"summary":"Get a specific error group","operationId":"get_error_group","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"group_id","in":"path","description":"Error group ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Error group details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorGroupResponse"}}}},"404":{"description":"Error group not found"},"500":{"description":"Internal server error"}}},"put":{"tags":["error-tracking"],"summary":"Update error group status","operationId":"update_error_group","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"group_id","in":"path","description":"Error group ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateErrorGroupRequest"}}},"required":true},"responses":{"200":{"description":"Error group updated successfully"},"404":{"description":"Error group not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-groups/{group_id}/events":{"get":{"tags":["error-tracking"],"summary":"List error events for a specific group","operationId":"list_error_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"group_id","in":"path","description":"Error group ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Paginated list of error events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedErrorEventsResponse"}}}},"404":{"description":"Error group not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-groups/{group_id}/events/{event_id}":{"get":{"tags":["error-tracking"],"summary":"Get a specific error event","operationId":"get_error_event","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"group_id","in":"path","description":"Error group ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"event_id","in":"path","description":"Error event ID","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Error event details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEventResponse"}}}},"404":{"description":"Event not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-stats":{"get":{"tags":["error-tracking"],"summary":"Get error statistics for a project","operationId":"get_error_stats","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Error statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorGroupStatsResponse"}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-time-series":{"get":{"tags":["error-tracking"],"summary":"Get error time series data for charts","operationId":"get_error_time_series","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"end_time","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"bucket","in":"query","description":"Time bucket size (e.g., \"1h\", \"15m\", \"1d\", \"1 hour\", \"30 minutes\")","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Error time series data","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ErrorTimeSeriesDataResponse"}}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/events":{"get":{"tags":["Events"],"summary":"Get event counts with filtering","operationId":"get_events_count","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering events","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering events","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Maximum number of events to return (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"custom_events_only","in":"query","description":"Only return custom events, excluding system events like page_view, page_leave, heartbeat (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors (default: events)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved event counts","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventCount"}}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/breakdown":{"get":{"tags":["Events"],"summary":"Get event type breakdown","operationId":"get_event_type_breakdown","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering events","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering events","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors (default: events)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved event type breakdown","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventTypeBreakdown"}}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/ingest":{"post":{"tags":["Events"],"summary":"Record an analytics event via the console API with explicit project ID.","description":"The app backend forwards the user's encrypted Temps cookies, so visitor/session\nidentity is resolved automatically by middleware. No geolocation or user-agent\nenrichment is performed — this is a lightweight server-side ingestion path.","operationId":"record_console_event","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsoleEventPayload"}}},"required":true},"responses":{"200":{"description":"Event recorded successfully"},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/properties/breakdown":{"get":{"tags":["Events"],"summary":"Get property breakdown by grouping events by a column","operationId":"get_property_breakdown","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"group_by","in":"query","description":"Column to group by (channel, device_type, browser, etc.)","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"event_name","in":"query","description":"Filter by event name","required":false,"schema":{"type":"string"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors - default: events","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Maximum number of results (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"filter_country","in":"query","description":"Filter by country (for region/city drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Filter by region (for city drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_browser","in":"query","description":"Filter by browser name (for version drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_os","in":"query","description":"Filter by OS name (for version drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_channel","in":"query","description":"Filter by channel name (for channel drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_referrer","in":"query","description":"Filter by referrer hostname (for referrer drill-downs)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved property breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PropertyBreakdownResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/properties/timeline":{"get":{"tags":["Events"],"summary":"Get property timeline by grouping events by a column over time","operationId":"get_property_timeline","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"group_by","in":"query","description":"Column to group by (channel, device_type, browser, etc.)","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"event_name","in":"query","description":"Filter by event name","required":false,"schema":{"type":"string"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors - default: events","required":false,"schema":{"type":"string"}},{"name":"bucket_size","in":"query","description":"Time bucket: hour, day, week, month (default: auto-detect)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved property timeline","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PropertyTimelineResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/timeline":{"get":{"tags":["Events"],"summary":"Get events timeline","operationId":"get_events_timeline","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering events","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering events","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"event_name","in":"query","description":"Filter by specific event name","required":false,"schema":{"type":"string"}},{"name":"bucket_size","in":"query","description":"Bucket size: hour, day, or week (auto-detected if not specified)","required":false,"schema":{"type":"string"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors (default: events)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved events timeline","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventTimeline"}}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/unique":{"get":{"tags":["Funnels"],"summary":"Get all unique/distinct event types for a project (paginated)","operationId":"get_unique_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Unique event types retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventTypesResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/external-images":{"get":{"tags":["External Images"],"summary":"List external images for a project","operationId":"list_remote_external_images","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default: 20)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of external images","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedExternalImagesResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["External Images"],"summary":"Register an external Docker image","description":"Registers an external Docker image reference without triggering a deployment.\nThe image can be deployed later using the deploy/image endpoint.","operationId":"register_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterImageRequest"}}},"required":true},"responses":{"201":{"description":"Image registered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalImageResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/external-images/{image_id}":{"get":{"tags":["External Images"],"summary":"Get details of a specific external image","operationId":"get_remote_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"image_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Image details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalImageResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Image not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["External Images"],"summary":"Delete an external image","operationId":"delete_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"image_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Image deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Image not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/flags":{"get":{"tags":["Feature Flags"],"operationId":"list_flags","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"include_archived","in":"query","description":"Include archived flags. Defaults to false.","required":false,"schema":{"type":"boolean"}},{"name":"page","in":"query","description":"1-indexed page number. Defaults to 1.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page. Defaults to 20, capped at 100.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"Flags listed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Feature Flags"],"operationId":"create_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFlagRequest"}}},"required":true},"responses":{"201":{"description":"Flag created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"409":{"description":"Flag key already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/flags/{key}":{"get":{"tags":["Feature Flags"],"operationId":"get_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Flag retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Feature Flags"],"operationId":"archive_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Flag archived","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArchiveFlagResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Feature Flags"],"operationId":"update_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateFlagRequest"}}},"required":true},"responses":{"200":{"description":"Flag updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/flags/{key}/environments/{environment_id}":{"put":{"tags":["Feature Flags"],"summary":"Set a flag's value in one environment, and/or flip its kill switch.","operationId":"set_flag_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetFlagEnvironmentRequest"}}},"required":true},"responses":{"200":{"description":"Environment value set","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagEnvironmentResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag or environment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/flags/{key}/restore":{"post":{"tags":["Feature Flags"],"summary":"Bring an archived flag back.","description":"Archiving is otherwise one-way: the key stays reserved so the flag cannot\neven be re-created under the same name, which makes an accidental archive\nunrecoverable through the API.","operationId":"restore_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Flag restored","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/funnels":{"get":{"tags":["Funnels"],"summary":"List all funnels for a project","operationId":"list_funnels","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Funnels retrieved successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/FunnelResponse"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Funnels"],"summary":"Create a new funnel","operationId":"create_funnel","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFunnelRequest"}}},"required":true},"responses":{"201":{"description":"Funnel created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFunnelResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/funnels/preview":{"post":{"tags":["Funnels"],"summary":"Preview funnel metrics without creating the funnel","operationId":"preview_funnel_metrics","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFunnelRequest"}}},"required":true},"responses":{"200":{"description":"Funnel metrics preview","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FunnelMetricsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/funnels/{funnel_id}":{"put":{"tags":["Funnels"],"summary":"Update a funnel","operationId":"update_funnel","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"funnel_id","in":"path","description":"Funnel ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFunnelRequest"}}},"required":true},"responses":{"200":{"description":"Funnel updated successfully"},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"404":{"description":"Funnel not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Funnels"],"summary":"Delete a funnel","operationId":"delete_funnel","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"funnel_id","in":"path","description":"Funnel ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Funnel deleted successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Funnel not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/funnels/{funnel_id}/metrics":{"get":{"tags":["Funnels"],"summary":"Get funnel metrics","operationId":"get_funnel_metrics","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"funnel_id","in":"path","description":"Funnel ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID filter","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"country_code","in":"query","description":"Country code filter","required":false,"schema":{"type":"string"}},{"name":"start_date","in":"query","description":"Start date filter (ISO 8601)","required":false,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date filter (ISO 8601)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Funnel metrics retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FunnelMetricsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"404":{"description":"Funnel not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/git":{"post":{"tags":["Projects"],"summary":"Update git settings for a project","operationId":"update_git_settings","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateGitSettingsRequest"}}},"required":true},"responses":{"200":{"description":"Git settings updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"400":{"description":"Invalid git configuration or branch does not exist"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/gitlab/reinstall-webhook":{"post":{"tags":["Projects"],"summary":"Reinstall the GitLab webhook for a project","description":"Removes the existing webhook (if any) and installs a fresh one.\nUse this when a webhook has been manually deleted on the GitLab side\nand automatic deployments have stopped working.","operationId":"reinstall_gitlab_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Webhook reinstalled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReinstallWebhookResponse"}}}},"400":{"description":"Project is not connected to a GitLab repository"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/has-error-groups":{"get":{"tags":["error-tracking"],"summary":"Check if project has any error groups","operationId":"has_error_groups","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Error groups existence check","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HasErrorGroupsResponse"}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/has-events":{"get":{"tags":["Events"],"summary":"Check if project has any analytics events","operationId":"has_analytics_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully checked for events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HasEventsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/hourly-visits":{"get":{"tags":["Events"],"summary":"Get hourly visits","operationId":"get_hourly_visits","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering visits","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering visits","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events (page views), sessions (unique sessions), or visitors (unique visitors) - default: events","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved hourly visits","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventTimeline"}}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/images":{"get":{"tags":["External Images"],"summary":"List all external images for a project","operationId":"list_external_images","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of external images","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PushedExternalImageResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/images/push":{"post":{"tags":["External Images"],"summary":"Push an external Docker image","operationId":"push_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushImageRequest"}}},"required":true},"responses":{"201":{"description":"Image pushed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushedExternalImageResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/images/{image_id}":{"get":{"tags":["External Images"],"summary":"Get details of a specific external image","operationId":"get_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"image_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Image details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushedExternalImageResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Image not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/incidents":{"get":{"tags":["Status Page"],"summary":"List incidents for a project","operationId":"list_incidents","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"status","in":"query","description":"Filter by status","required":false,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Successfully retrieved incidents"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Status Page"],"summary":"Create a new incident","operationId":"create_incident","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIncidentRequest"}}},"required":true},"responses":{"201":{"description":"Incident created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/incidents/bucketed":{"get":{"tags":["Status Page"],"summary":"Get bucketed incident data for a project","operationId":"get_bucketed_incidents","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"interval","in":"query","description":"Bucket interval: '5min', 'hourly', or 'daily' (default: hourly)","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601) (default: 7 days ago)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (ISO 8601) (default: now)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved bucketed incident data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentBucketedResponse"}}}},"400":{"description":"Invalid parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/logs":{"delete":{"tags":["Logs"],"summary":"Purge all logs for a project before a given timestamp","operationId":"purge_project_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurgeLogsRequest"}}},"required":true},"responses":{"200":{"description":"Purge completed"},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/mcp-servers":{"get":{"tags":["Agents"],"operationId":"list_mcps","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListMcpsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_mcp","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMcpRequest"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/mcp-servers/{slug}":{"get":{"tags":["Agents"],"operationId":"get_mcp","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_mcp","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMcpRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_mcp","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"MCP server deleted"},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/mcp-servers/{slug}/config/{field}":{"get":{"tags":["Agents"],"operationId":"reveal_mcp_config","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}},{"name":"field","in":"path","description":"Sensitive field path, such as url or env.API_TOKEN","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensitiveMcpConfigValueResponse"}}}},"400":{"description":"Field is not revealable"},"401":{"description":"Unauthorized"},"403":{"description":"Missing secrets:read permission"},"404":{"description":"MCP server or field not found"},"500":{"description":"Configuration read or audit failed"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/monitors":{"get":{"tags":["Status Page"],"summary":"List monitors for a project","operationId":"list_monitors","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved monitors","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MonitorResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Status Page"],"summary":"Create a new monitor","operationId":"create_monitor","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMonitorRequest"}}},"required":true},"responses":{"201":{"description":"Monitor created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/observe/events":{"get":{"tags":["Observability"],"summary":"List a merged page of observability events for a project.","description":"Each row carries everything the side panel needs to render — no\nfollow-up fetch is required for the common case. Heavy fields\n(stacktraces, headers, span attributes) are truncated server-side and\nexpose a `*_truncated` flag; clients fetch the full row from the\n`/full` endpoint only when the user explicitly clicks \"Show full\".","operationId":"observability_list_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"kinds","in":"query","description":"Comma-separated kinds: `log,request,span,error,revenue`. Empty or\nmissing returns every kind.","required":false,"schema":{"type":"string"}},{"name":"from","in":"query","description":"Inclusive lower bound on event timestamp (ISO 8601, `Z` suffix).","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","description":"Inclusive upper bound on event timestamp.","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"deployment_id","in":"query","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"search","in":"query","description":"Free-text substring matched against per-kind summary fields\n(request path / error class / revenue event_type).","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Page size (default 50, max 200).","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"hide_bots","in":"query","description":"When `true`, exclude bot/crawler request rows. When `false`, only\ninclude bot rows. Omitted means \"include everything\" (default).\nOnly affects the `Request` kind.","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Merged event page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventsResponse"}}}},"400":{"description":"Invalid filter (kinds, time range, …)","content":{"text/plain":{"schema":{"type":"string"}}}},"401":{"description":"Unauthorized","content":{"text/plain":{"schema":{"type":"string"}}}},"403":{"description":"Insufficient permissions","content":{"text/plain":{"schema":{"type":"string"}}}},"500":{"description":"Internal server error","content":{"text/plain":{"schema":{"type":"string"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/observe/events/{kind}/{event_id}/full":{"get":{"tags":["Observability"],"summary":"Fetch the un-truncated form of one event by `(kind, id)`. Side panel\n\"Show full\" action calls this — the list response carries truncated\npreviews + a `*_truncated` flag to let the UI decide whether to fetch.","operationId":"observability_full_event","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"kind","in":"path","description":"Event kind discriminator","required":true,"schema":{"$ref":"#/components/schemas/EventKind"}},{"name":"event_id","in":"path","description":"Per-kind identity: request_id for requests, `{trace_id}:{span_id}` for spans, serial id for errors/revenue","required":true,"schema":{"type":"string"}},{"name":"ts","in":"query","description":"The row's event timestamp as returned by the list endpoint. Optional,\nbut strongly recommended: it bounds the lookup to the storage\npartitions/chunks around that instant instead of scanning the whole\nretention window.","required":false,"schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"Full row","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FullEvent"}}}},"401":{"description":"Unauthorized","content":{"text/plain":{"schema":{"type":"string"}}}},"403":{"description":"Insufficient permissions","content":{"text/plain":{"schema":{"type":"string"}}}},"404":{"description":"Event not found in project","content":{"text/plain":{"schema":{"type":"string"}}}},"500":{"description":"Internal server error","content":{"text/plain":{"schema":{"type":"string"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/releases/{release}/source-files":{"get":{"tags":["source-maps"],"summary":"List uploaded source files for a release (metadata only).","operationId":"list_source_files","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of source files","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceFileListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["source-maps"],"summary":"Upload a raw source file for a release (native symbolication).","description":"Accepts a multipart form with:\n- `file`: the source file bytes (required)\n- `file_path`: the path of the file as it appears in stack frames (required;\n derived from the uploaded filename if omitted). Normalized with the `~`\n prefix convention, matching source-map storage.\n\nRequires the project's `error_source_context_enabled` toggle to be on.\nUpserts on (project, release, file_path).","operationId":"upload_source_file","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"Source file uploaded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceFileResponse"}}}},"400":{"description":"Missing fields"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"409":{"description":"Source context disabled for project"},"413":{"description":"Source file too large"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["source-maps"],"summary":"Delete all uploaded source files for a release.","operationId":"delete_release_source_files","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Source files deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/releases/{release}/source-maps":{"get":{"tags":["source-maps"],"summary":"List all source maps for a specific release","operationId":"list_source_maps","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of source maps","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceMapListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["source-maps"],"summary":"Upload a source map for a release.","description":"Accepts a multipart form with:\n- `file`: The .map file (required)\n- `file_path`: The URL path of the minified file as it appears in stack traces (required).\n Uses the ~ prefix convention (e.g., \"~/assets/main.js\").\n If a full URL is provided, it will be normalized automatically.\n- `dist`: Optional distribution identifier\n\nIf a source map already exists for the same (project, release, file_path), it is replaced.","operationId":"upload_source_map","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"Source map uploaded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceMapResponse"}}}},"400":{"description":"Invalid source map or missing fields"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"413":{"description":"Source map too large"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["source-maps"],"summary":"Delete all source maps for a specific release","operationId":"delete_release_source_maps","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Source maps deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/events":{"get":{"tags":["Revenue"],"summary":"Recent ingested events for the activity feed.","operationId":"revenue_recent_events","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RecentEventResponse"}}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations":{"get":{"tags":["Revenue"],"summary":"List revenue integrations for a project.","operationId":"revenue_list_integrations","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/IntegrationResponse"}}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Revenue"],"summary":"Create a new revenue integration. Response contains the generated\nwebhook path that the user must paste into their provider's dashboard.","operationId":"revenue_create_integration","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIntegrationBody"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationResponse"}}}},"400":{"description":"Validation error"},"409":{"description":"Already connected"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}":{"delete":{"tags":["Revenue"],"summary":"Delete a revenue integration (permanent — use rotate_token to refresh\ncredentials without breaking history).","operationId":"revenue_delete_integration","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/config":{"post":{"tags":["Revenue"],"summary":"Replace the typed provider config on an integration. Passing `null`\nclears the config back to the accept-everything default. The config's\nprovider tag must match the integration's provider.","operationId":"revenue_update_config","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateConfigBody"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Integration not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/import/invoices":{"post":{"tags":["Revenue"],"summary":"Import a Stripe invoices CSV export. Each paid invoice becomes an\n`invoice.paid` event so historical MRR/charge totals populate the\ntimeseries. Ingestion is idempotent: re-uploading the same file is a\nno-op.","operationId":"revenue_import_invoices_csv","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportOutcomeResponse"}}}},"400":{"description":"Malformed CSV or wrong provider"},"404":{"description":"Integration not found"},"413":{"description":"CSV too large"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/import/subscriptions":{"post":{"tags":["Revenue"],"summary":"Import a Stripe subscriptions CSV export. Use this to backfill MRR /\nactive subscriptions when migrating from Stripe without providing\nAPI keys. Webhooks remain the source of truth for live updates —\nCSV rows never overwrite newer webhook state.","operationId":"revenue_import_subscriptions_csv","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportOutcomeResponse"}}}},"400":{"description":"Malformed CSV or wrong provider"},"404":{"description":"Integration not found"},"413":{"description":"CSV too large"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/rotate-token":{"post":{"tags":["Revenue"],"summary":"Rotate the webhook path token. Returns the new integration state —\nthe user must paste the new URL into their provider's dashboard.","operationId":"revenue_rotate_token","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/update-secret":{"post":{"tags":["Revenue"],"summary":"Replace the stored signing secret without rotating the webhook URL.\nUse this after rotating the secret in the provider's dashboard.","operationId":"revenue_update_secret","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSecretBody"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Integration not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/metrics/customers":{"get":{"tags":["Revenue"],"summary":"New + churned customers per bucket.","operationId":"revenue_metrics_customers","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CustomerMovementResponse"}}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/metrics/mrr":{"get":{"tags":["Revenue"],"summary":"Bucketed MRR timeseries for the revenue chart.","operationId":"revenue_metrics_mrr","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MrrBucketResponse"}}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/metrics/summary":{"get":{"tags":["Revenue"],"summary":"Current MRR / ARR / churn / ARPU for a project, in one currency.","operationId":"revenue_metrics_summary","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetricsSummaryResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/secrets":{"get":{"tags":["Secrets"],"summary":"List project secrets (metadata only — values never returned).","operationId":"listProjectSecrets","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Optional environment filter","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of secrets (metadata only, no values)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectSecretResponse"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["Secrets"],"summary":"Create a new secret. The value is encrypted before storage and will be\nmounted as a file at `/run/secrets/` on the next deployment.\nThe plaintext value is NOT returned — the response carries only metadata.","operationId":"createProjectSecret","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectSecretRequest"}}},"required":true},"responses":{"201":{"description":"Secret created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectSecretResponse"}}}},"400":{"description":"Invalid key or value too large"},"409":{"description":"Key already exists in project"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/secrets/{secret_id}":{"put":{"tags":["Secrets"],"summary":"Update a project secret. Value rotation requires a redeploy to take effect —\nrunning containers keep their currently-mounted values until the next\ndeployment.","operationId":"updateProjectSecret","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"secret_id","in":"path","description":"Secret ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProjectSecretRequest"}}},"required":true},"responses":{"200":{"description":"Secret updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectSecretResponse"}}}},"400":{"description":"Value too large"},"404":{"description":"Secret not found"},"500":{"description":"Internal server error"}}},"delete":{"tags":["Secrets"],"summary":"Delete a project secret. Running containers keep their mounted secret files\nuntil they are redeployed.","operationId":"deleteProjectSecret","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"secret_id","in":"path","description":"Secret ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Secret deleted"},"404":{"description":"Secret not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/settings":{"post":{"tags":["Projects"],"summary":"Update project settings","operationId":"update_project_settings","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProjectSettingsRequest"}}},"required":true},"responses":{"200":{"description":"Project settings updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/skills":{"get":{"tags":["Agents"],"operationId":"list_skills","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSkillsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSkillRequest"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/skills/upload":{"post":{"tags":["Agents"],"summary":"Upload a skill with an archive (tar.gz) — project-scoped.","operationId":"upload_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"string"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/skills/{slug}":{"get":{"tags":["Agents"],"operationId":"get_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSkillRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Skill deleted"},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/skills/{slug}/archive":{"get":{"tags":["Agents"],"summary":"Download a skill's archive (tar.gz) — project-scoped.","operationId":"download_skill_archive","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Skill archive tar.gz","content":{"application/gzip":{}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found or has no archive"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/source-map-releases":{"get":{"tags":["source-maps"],"summary":"List all releases that have source maps for a project","operationId":"list_releases","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of releases","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReleaseListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/source-maps/{source_map_id}":{"delete":{"tags":["source-maps"],"summary":"Delete a specific source map by ID","operationId":"delete_source_map","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"source_map_id","in":"path","description":"Source map ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Source map deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Source map not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/static-bundles":{"get":{"tags":["Static Bundles"],"summary":"List static bundles for a project","operationId":"list_static_bundles","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default: 20)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of static bundles","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedStaticBundlesResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/static-bundles/{bundle_id}":{"get":{"tags":["Static Bundles"],"summary":"Get details of a specific static bundle","operationId":"get_static_bundle","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"bundle_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Bundle details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaticBundleResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Bundle not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Static Bundles"],"summary":"Delete a static bundle","operationId":"delete_static_bundle","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"bundle_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Bundle deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Bundle not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/status":{"get":{"tags":["Status Page"],"summary":"Get status page overview","operationId":"get_status_overview","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved status overview","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusPageOverview"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/unique-counts":{"get":{"tags":["Events"],"summary":"Get unique counts over time frame","operationId":"get_unique_counts","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"metric","in":"query","description":"Metric to count: 'sessions' (unique sessions), 'visitors' (unique visitors), 'returning_visitors' (visitors seen before the range), or 'page_views' (total page views) (default: 'sessions')","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved count","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UniqueCountsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/upload/static":{"post":{"tags":["Static Bundles"],"summary":"Upload a static bundle for later deployment","description":"Uploads a tar.gz or zip file containing static assets. The bundle can be\ndeployed later using the deploy/static endpoint.","operationId":"upload_static_bundle","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"201":{"description":"Bundle uploaded successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaticBundleResponse"}}}},"400":{"description":"Invalid request or unsupported format"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"},"413":{"description":"Bundle too large"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/vulnerability-scans":{"get":{"tags":["Vulnerability Scans"],"operationId":"list_project_scans","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of vulnerability scans","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ScanResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Vulnerability Scans"],"operationId":"trigger_scan","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerScanRequest"}}},"required":true},"responses":{"202":{"description":"Scan triggered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerScanResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/vulnerability-scans/environments":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_latest_scans_per_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Latest scans per environment for current deployments","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ScanResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/vulnerability-scans/latest":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_latest_scan","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Latest scan for project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"No scans found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks":{"get":{"tags":["Webhooks"],"summary":"List all webhooks for a project","operationId":"list_webhooks","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of webhooks","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/WebhookResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Webhooks"],"summary":"Create a new webhook","operationId":"create_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookRequestBody"}}},"required":true},"responses":{"201":{"description":"Webhook created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks/{webhook_id}":{"get":{"tags":["Webhooks"],"summary":"Get a specific webhook","operationId":"get_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Webhook details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Webhook not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Webhooks"],"summary":"Update a webhook","operationId":"update_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWebhookRequestBody"}}},"required":true},"responses":{"200":{"description":"Webhook updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Webhook not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Webhooks"],"summary":"Delete a webhook","operationId":"delete_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Webhook deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Webhook not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks/{webhook_id}/deliveries":{"get":{"tags":["Webhook Deliveries"],"summary":"List webhook deliveries","operationId":"list_deliveries","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Number of deliveries to return (default: 50)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of deliveries","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/WebhookDeliveryResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks/{webhook_id}/deliveries/{delivery_id}":{"get":{"tags":["Webhook Deliveries"],"summary":"Get a specific webhook delivery by ID","operationId":"get_delivery","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"delivery_id","in":"path","description":"Delivery ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Delivery details including full payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeliveryResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Delivery not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks/{webhook_id}/deliveries/{delivery_id}/retry":{"post":{"tags":["Webhook Deliveries"],"summary":"Retry a failed delivery","operationId":"retry_delivery","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"delivery_id","in":"path","description":"Delivery ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Delivery retried","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeliveryResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Delivery not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/workflows/dry-run":{"post":{"tags":["Workflows"],"operationId":"workflow_dry_run","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkflowDryRunRequest"}}},"required":true},"responses":{"202":{"description":"Ephemeral run created and queued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunResponse"}}}},"400":{"description":"Validation error (bad YAML, oversized payload, capped limits exceeded)"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/proxy-logs":{"get":{"tags":["Proxy Logs"],"summary":"Get proxy logs with optional filters and pagination","operationId":"get_proxy_logs","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"session_id","in":"query","description":"Filter by session ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"visitor_id","in":"query","description":"Filter by visitor ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering (ISO 8601 format).\n\n**Defaults to 1 hour before `end_date` (or before now) when omitted.**\nThe listing is always time-bounded: an unbounded query would have to\nconsider the entire retention window — 100M+ rows on a busy deployment —\nto return a single page. Pass an explicit `start_date` to widen the\nwindow, up to the configured retention horizon.\n\nThe maximum span between `start_date` and `end_date` is 7 days when\n`project_id` is omitted, or 30 days when a single `project_id` is set —\na project-scoped query is bounded by that project's own row count\nrather than the whole deployment's. A wider request is rejected with a\n400 naming the applicable cap.","required":false,"schema":{"type":["string","null"],"format":"date-time"}},{"name":"end_date","in":"query","description":"End date for filtering (ISO 8601 format). Defaults to now.","required":false,"schema":{"type":["string","null"],"format":"date-time"}},{"name":"method","in":"query","description":"Filter by HTTP method (GET, POST, etc.)","required":false,"schema":{"type":["string","null"]}},{"name":"host","in":"query","description":"Filter by host header","required":false,"schema":{"type":["string","null"]}},{"name":"path","in":"query","description":"Filter by path (supports partial match)","required":false,"schema":{"type":["string","null"]}},{"name":"client_ip","in":"query","description":"Filter by client IP address","required":false,"schema":{"type":["string","null"]}},{"name":"status_code","in":"query","description":"Filter by HTTP status code","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"response_time_min","in":"query","description":"Filter by minimum response time in ms","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"response_time_max","in":"query","description":"Filter by maximum response time in ms","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"routing_status","in":"query","description":"Filter by routing status (routed, no_project, error, pending)","required":false,"schema":{"type":["string","null"]}},{"name":"request_source","in":"query","description":"Filter by request source (proxy, api, console, cli)","required":false,"schema":{"type":["string","null"]}},{"name":"is_system_request","in":"query","description":"Filter by system request flag","required":false,"schema":{"type":["boolean","null"]}},{"name":"user_agent","in":"query","description":"Filter by user agent string (partial match)","required":false,"schema":{"type":["string","null"]}},{"name":"browser","in":"query","description":"Filter by browser name","required":false,"schema":{"type":["string","null"]}},{"name":"operating_system","in":"query","description":"Filter by operating system","required":false,"schema":{"type":["string","null"]}},{"name":"device_type","in":"query","description":"Filter by device type (mobile, desktop, tablet)","required":false,"schema":{"type":["string","null"]}},{"name":"is_bot","in":"query","description":"Filter by bot detection","required":false,"schema":{"type":["boolean","null"]}},{"name":"exclude_bots","in":"query","description":"When `true`, exclude rows flagged as bots while KEEPING rows whose\n`is_bot` is NULL (older rows without detection metadata). This is the\ntri-state complement of `is_bot=false`, which matches only rows\nexplicitly detected as non-bots. `false`/omitted is a no-op.","required":false,"schema":{"type":["boolean","null"]}},{"name":"bot_name","in":"query","description":"Filter by bot name","required":false,"schema":{"type":["string","null"]}},{"name":"ai_provider","in":"query","description":"Filter by AI provider (e.g. `OpenAI`, `Anthropic`, `Perplexity`). Matches\nthe canonical provider returned by the AI agent detector.","required":false,"schema":{"type":["string","null"]}},{"name":"ai_agent","in":"query","description":"Filter by AI agent name (e.g. `GPTBot`, `ChatGPT-User`). Equivalent to\nfiltering `bot_name` against a known AI taxonomy.","required":false,"schema":{"type":["string","null"]}},{"name":"is_ai_agent","in":"query","description":"When `true`, only return requests classified as known AI agents\n(regardless of provider/agent). Mutually compatible with the above.","required":false,"schema":{"type":["boolean","null"]}},{"name":"request_size_min","in":"query","description":"Filter by minimum request size in bytes","required":false,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"request_size_max","in":"query","description":"Filter by maximum request size in bytes","required":false,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"response_size_min","in":"query","description":"Filter by minimum response size in bytes","required":false,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"response_size_max","in":"query","description":"Filter by maximum response size in bytes","required":false,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"cache_status","in":"query","description":"Filter by cache status","required":false,"schema":{"type":["string","null"]}},{"name":"container_id","in":"query","description":"Filter by container ID","required":false,"schema":{"type":["string","null"]}},{"name":"upstream_host","in":"query","description":"Filter by upstream host","required":false,"schema":{"type":["string","null"]}},{"name":"has_error","in":"query","description":"Filter by presence of error message","required":false,"schema":{"type":["boolean","null"]}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"sort_by","in":"query","description":"Sort by field (default: timestamp)","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","description":"Sort order (asc or desc, default: desc)","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of proxy logs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProxyLogsPaginatedResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/ai-agents/known":{"get":{"tags":["Proxy Logs"],"summary":"List every AI agent the detector knows how to classify.","description":"Returned in the same order as the internal taxonomy so the UI can use it as\na stable dropdown.","operationId":"list_known_ai_agents","responses":{"200":{"description":"Known AI agents","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KnownAiAgentsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/request/{request_id}":{"get":{"tags":["Proxy Logs"],"summary":"Get a proxy log by request ID (for tracing)","operationId":"get_proxy_log_by_request_id","parameters":[{"name":"request_id","in":"path","description":"Request ID from pingora","required":true,"schema":{"type":"string"}},{"name":"timestamp","in":"query","description":"Event time of the log row (ISO 8601). When provided, the lookup is\nbounded to the hypertable chunks around this instant instead of\nscanning (and decompressing) the whole retention window. The list\nendpoint already returns this value per row — always pass it when\nnavigating from a list.","required":false,"schema":{"type":["string","null"],"format":"date-time"}}],"responses":{"200":{"description":"Proxy log found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProxyLogResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Proxy log not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-agent-pages":{"get":{"tags":["Proxy Logs"],"summary":"Get the top pages accessed by a specific AI agent over a time window.","description":"Returns page paths ranked by request count, scoped to a single canonical\nagent name (e.g. `ChatGPT-User`). Use `GET /proxy-logs/ai-agents/known` to\nlist all valid agent names. Unknown agent names return an empty items array.","operationId":"get_ai_agent_pages","parameters":[{"name":"agent","in":"query","description":"Canonical agent name to filter by (e.g. `ChatGPT-User`, `ClaudeBot`).\nMust be a name returned by `GET /proxy-logs/ai-agents/known`.","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Filter by project ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"limit","in":"query","description":"Maximum rows to return. Capped at 100 server-side.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"Pages breakdown for the requested agent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiAgentPagesResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-agents":{"get":{"tags":["Proxy Logs"],"summary":"Get the per-AI-agent breakdown for a project over a time window.","operationId":"get_ai_agent_breakdown","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID (recommended for per-project analytics).","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"limit","in":"query","description":"Maximum rows to return. Capped at 100 server-side.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"path","in":"query","description":"Optional exact path filter. Only used by the AI pages breakdown — when\nset, returns the single matching page so callers can ask \"how many AI\nagents hit this page?\".","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"AI agent breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiAgentBreakdownResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-agents/timeline":{"get":{"tags":["Proxy Logs"],"summary":"Time-bucketed AI-agent request volume, split by provider or agent.","description":"Powers the \"AI agents over time\" stacked chart. Same data source as the AI\nagent breakdown (request logs), just bucketed.","operationId":"get_ai_agent_timeline","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"group_by","in":"query","description":"Grouping dimension: `provider` (default) or `agent`.","required":false,"schema":{"type":["string","null"]},"example":"provider"},{"name":"bucket","in":"query","description":"Bucket interval override (e.g. `1 hour`, `1 day`). Auto-selected from the\nwindow width when omitted.","required":false,"schema":{"type":["string","null"]},"example":"1 hour"}],"responses":{"200":{"description":"AI agent timeline","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiAgentTimelineResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-pages":{"get":{"tags":["Proxy Logs"],"summary":"Get the top pages crawled by AI agents over a time window.","operationId":"get_ai_page_breakdown","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID (recommended for per-project analytics).","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"limit","in":"query","description":"Maximum rows to return. Capped at 100 server-side.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"path","in":"query","description":"Optional exact path filter. Only used by the AI pages breakdown — when\nset, returns the single matching page so callers can ask \"how many AI\nagents hit this page?\".","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"AI page breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiPageBreakdownResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-status":{"get":{"tags":["Proxy Logs"],"summary":"HTTP status-class breakdown for AI-agent traffic — are bots being served\n(2xx) or hitting broken/blocked pages (4xx/5xx)?","operationId":"get_ai_status_breakdown","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID (recommended for per-project analytics).","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"limit","in":"query","description":"Maximum rows to return. Capped at 100 server-side.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"path","in":"query","description":"Optional exact path filter. Only used by the AI pages breakdown — when\nset, returns the single matching page so callers can ask \"how many AI\nagents hit this page?\".","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"AI status breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiStatusBreakdownResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/projects-health":{"get":{"tags":["Proxy Logs"],"summary":"Get health summaries for multiple projects (last 1 hour)","operationId":"get_projects_health","parameters":[{"name":"project_ids","in":"query","description":"Comma-separated list of project IDs","required":true,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Optional start time (ISO 8601). Defaults to `end_time - 1h`.","required":false,"schema":{"type":["string","null"]},"example":"2025-10-23T00:00:00Z"},{"name":"end_time","in":"query","description":"Optional end time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2025-10-23T23:59:59Z"},{"name":"is_bot","in":"query","description":"Filter by bot detection. Pass `false` to exclude bots, `true` for bots only.","required":false,"schema":{"type":["boolean","null"]}}],"responses":{"200":{"description":"Health summaries per project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectsHealthResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/time-buckets":{"get":{"tags":["Proxy Logs"],"summary":"Get time-bucketed statistics with optional filters","operationId":"get_time_bucket_stats","parameters":[{"name":"start_time","in":"query","description":"Start time (ISO 8601 format)","required":true,"schema":{"type":"string"},"example":"2025-10-23T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601 format)","required":true,"schema":{"type":"string"},"example":"2025-10-23T23:59:59Z"},{"name":"bucket_interval","in":"query","description":"Bucket interval (e.g., \"1 hour\", \"1 day\", \"5 minutes\")","required":false,"schema":{"type":"string"}},{"name":"method","in":"query","description":"Filter by HTTP method","required":false,"schema":{"type":"string"}},{"name":"client_ip","in":"query","description":"Filter by client IP","required":false,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Filter by project ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"host","in":"query","description":"Filter by host","required":false,"schema":{"type":"string"}},{"name":"status_code","in":"query","description":"Filter by status code","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"status_code_class","in":"query","description":"Filter by status code class (e.g. \"2xx\", \"3xx\", \"4xx\", \"5xx\")","required":false,"schema":{"type":"string"}},{"name":"routing_status","in":"query","description":"Filter by routing status","required":false,"schema":{"type":"string"}},{"name":"request_source","in":"query","description":"Filter by request source","required":false,"schema":{"type":"string"}},{"name":"is_bot","in":"query","description":"Filter by bot detection","required":false,"schema":{"type":"boolean"}},{"name":"device_type","in":"query","description":"Filter by device type","required":false,"schema":{"type":"string"}},{"name":"has_project","in":"query","description":"When true, only count requests that matched a project\n(project_id IS NOT NULL). Makes chart totals line up with the\nper-project health cards.","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Time-bucketed statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimeBucketStatsResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/today":{"get":{"tags":["Proxy Logs"],"summary":"Get today's request count with optional filters","operationId":"get_today_stats","parameters":[{"name":"method","in":"query","description":"Filter by HTTP method","required":false,"schema":{"type":["string","null"]}},{"name":"client_ip","in":"query","description":"Filter by client IP","required":false,"schema":{"type":["string","null"]}},{"name":"project_id","in":"query","description":"Filter by project ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"host","in":"query","description":"Filter by host","required":false,"schema":{"type":["string","null"]}},{"name":"status_code","in":"query","description":"Filter by status code","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"status_code_class","in":"query","description":"Filter by status code class (e.g. \"2xx\", \"3xx\", \"4xx\", \"5xx\")","required":false,"schema":{"type":["string","null"]}},{"name":"routing_status","in":"query","description":"Filter by routing status","required":false,"schema":{"type":["string","null"]}},{"name":"request_source","in":"query","description":"Filter by request source","required":false,"schema":{"type":["string","null"]}},{"name":"is_bot","in":"query","description":"Filter by bot detection","required":false,"schema":{"type":["boolean","null"]}},{"name":"device_type","in":"query","description":"Filter by device type","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Today's request count","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TodayStatsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/{id}":{"get":{"tags":["Proxy Logs"],"summary":"Get a single proxy log by ID","operationId":"get_proxy_log_by_id","parameters":[{"name":"id","in":"path","description":"Proxy log ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"timestamp","in":"query","description":"Event time of the log row (ISO 8601). When provided, the lookup is\nbounded to the hypertable chunks around this instant instead of\nscanning (and decompressing) the whole retention window. The list\nendpoint already returns this value per row — always pass it when\nnavigating from a list.","required":false,"schema":{"type":["string","null"],"format":"date-time"}}],"responses":{"200":{"description":"Proxy log found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProxyLogResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Proxy log not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/repositories":{"get":{"tags":["Git Providers"],"summary":"List synced repositories with advanced filtering","description":"Lists repositories that have been synced to the database with filtering options.\nThis provides fast access to repository metadata with filtering by connection, search, and other criteria.","operationId":"list_synced_repositories","parameters":[{"name":"page","in":"query","description":"Page number for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"sort","in":"query","description":"Sort field (name, created_at, updated_at, stars, watchers, size, issues)","required":false,"schema":{"type":"string"}},{"name":"direction","in":"query","description":"Sort direction (asc, desc)","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Search term to filter repositories","required":false,"schema":{"type":"string"}},{"name":"owner","in":"query","description":"Filter by repository owner","required":false,"schema":{"type":"string"}},{"name":"language","in":"query","description":"Filter by programming language","required":false,"schema":{"type":"string"}},{"name":"private","in":"query","description":"Filter by private status (true/false)","required":false,"schema":{"type":"boolean"}},{"name":"git_provider_connection_id","in":"query","description":"Filter by git provider connection ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of synced repositories","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryListResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{name}":{"get":{"tags":["Git Providers"],"summary":"Get repository by owner and name from any connection","operationId":"get_repository_by_name","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"connection_id","in":"query","description":"Optional specific connection ID to search","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Repository found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryResponse"}}}},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{name}/all":{"get":{"tags":["Git Providers"],"summary":"Get all repositories with same owner/name from all git providers","operationId":"get_all_repositories_by_name","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Repositories found from all providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RepositoryResponse"}}}}},"404":{"description":"No repositories found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{name}/preset":{"get":{"tags":["Git Providers"],"summary":"Get repository preset by owner and name","operationId":"get_repository_preset_by_name","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"branch","in":"query","description":"Git branch to check (defaults to repository's default branch)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Repository preset calculated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryPresetResponse"}}}},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{repo}/branches":{"get":{"tags":["Repositories"],"summary":"Get repository branches","operationId":"get_repository_branches","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"connection_id","in":"query","description":"Git provider connection ID (required when multiple connections have the same repo)","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of branches","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BranchListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{repo}/tags":{"get":{"tags":["Repositories"],"summary":"Get repository tags","operationId":"get_repository_tags","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"connection_id","in":"query","description":"Git provider connection ID (required when multiple connections have the same repo)","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of tags","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"429":{"description":"Fresh tag lookup rate limit exceeded"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{repository_id}/preset/live":{"get":{"tags":["Git Providers"],"operationId":"get_repository_preset_live","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"branch","in":"query","description":"Git branch to check (defaults to repository's default branch)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Repository presets calculated successfully - includes root preset and projects in subdirectories","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryPresetResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"The git provider rejected the stored credential - the connection must be re-authorized"},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}":{"get":{"tags":["Git Providers"],"summary":"Get repository by ID","operationId":"get_repository_by_id","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Repository found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryResponse"}}}},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}/branches":{"get":{"tags":["Repositories"],"summary":"Get repository branches by repository ID","operationId":"get_branches_by_repository_id","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of branches","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BranchListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}/commits":{"get":{"tags":["Repositories"],"summary":"List recent commits for a repository branch","operationId":"list_commits_by_repository_id","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"branch","in":"query","description":"Branch name to list commits for","required":true,"schema":{"type":"string"}},{"name":"per_page","in":"query","description":"Number of commits to return (default: 20, max: 100)","required":false,"schema":{"type":["integer","null"],"format":"int32","minimum":0}}],"responses":{"200":{"description":"List of commits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommitListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}/commits/{commit_sha}":{"get":{"tags":["Repositories"],"summary":"Check if a commit exists in a repository","operationId":"check_commit_exists","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"commit_sha","in":"path","description":"Commit SHA to check","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Commit existence check result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommitExistsResponse"}}}},"400":{"description":"Invalid commit SHA"},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"429":{"description":"Commit lookup rate limit exceeded"},"500":{"description":"Internal server error"},"502":{"description":"Git provider request failed"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}/tags":{"get":{"tags":["Repositories"],"summary":"Get repository tags by repository ID","operationId":"get_tags_by_repository_id","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of tags","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"429":{"description":"Fresh tag lookup rate limit exceeded"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/restore-runs/{id}":{"get":{"tags":["Restore"],"operationId":"get_restore_run","parameters":[{"name":"id","in":"path","description":"Restore run id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Restore run progress","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestoreRunView"}}}},"404":{"description":"Restore run not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/revenue/events":{"get":{"tags":["Revenue"],"summary":"Org-wide revenue events across every project. Powers the revenue\ntransactions page. Supports filtering by project, date range, and\nevent type.","operationId":"revenue_global_events","parameters":[{"name":"project_id","in":"query","description":"Filter to a single project","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"from","in":"query","description":"Lower bound (inclusive), ISO-8601","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"Upper bound (inclusive), ISO-8601","required":false,"schema":{"type":"string"}},{"name":"event_types","in":"query","description":"Comma-separated event types (e.g. `invoice.paid,charge.succeeded`)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max rows, default 100, max 500","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GlobalRecentEventResponse"}}}}}},"security":[{"bearer_auth":[]}]}},"/revenue/metrics/global-mrr":{"get":{"tags":["Revenue"],"summary":"Org-wide MRR total, summed across every project in the install.\nPowers the single-number MRR card on the main dashboard.","operationId":"revenue_metrics_global_mrr","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlobalMrrResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/revenue/metrics/global-summary":{"get":{"tags":["Revenue"],"summary":"Org-wide revenue summary: MRR, paid cash (30d + all-time), refunds,\nactive subscriptions/customers, and transaction count. Powers the\nheader on the Revenue transactions page.","operationId":"revenue_metrics_global_summary","parameters":[{"name":"currency","in":"query","description":"ISO-4217 currency code, default USD","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlobalRevenueSummaryResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/revenue/providers":{"get":{"tags":["Revenue"],"summary":"List registered providers (what the UI needs to render the \"Connect\"\ndropdown + its wizard instructions).","operationId":"revenue_list_providers","responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderDescriptor"}}}}}},"security":[{"bearer_auth":[]}]}},"/session-replays":{"get":{"tags":["Analytics"],"summary":"Get session replays for a project","operationId":"get_project_session_replays","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Session replays retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetProjectSessionReplaysResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/sessions/{session_id}/events":{"get":{"tags":["Events"],"summary":"Get events for a specific session","operationId":"get_session_events","parameters":[{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved session events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsSessionEventsResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Session not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings":{"get":{"tags":["Settings"],"summary":"Get application settings","operationId":"get_settings","responses":{"200":{"description":"Application settings with masked sensitive fields","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppSettingsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Settings"],"summary":"Update application settings","operationId":"update_settings","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppSettings"}}},"required":true},"responses":{"200":{"description":"Settings updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsUpdateResponse"}}}},"400":{"description":"Bad request - invalid settings"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/agent-token":{"post":{"tags":["Agents"],"summary":"Save an encrypted AI provider token for use in sandbox containers.","operationId":"save_agent_token","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveAgentTokenRequest"}}},"required":true},"responses":{"200":{"description":"Token encrypted and persisted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveAgentTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Encryption or database error"}},"security":[{"bearer_auth":[]}]}},"/settings/ai-providers":{"get":{"tags":["Agents"],"summary":"List the AI provider catalog. Includes per-provider \"is a credential\nconfigured?\" so the settings UI can render configured/not-configured\nbadges without leaking the encrypted credential.","operationId":"list_ai_providers","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderCatalogResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/ai-providers/{provider_id}":{"patch":{"tags":["Agents"],"summary":"Update provider-scoped settings without touching the saved credential.\nToday that means just `default_model`; future per-provider settings\n(base URL overrides, request headers, etc.) can land here too without\nchanging the shape of `save_credential`.","operationId":"update_ai_provider","parameters":[{"name":"provider_id","in":"path","description":"AI provider ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAiProviderRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAiProviderResponse"}}}},"400":{"description":"Unknown provider"},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/ai-providers/{provider_id}/activate":{"post":{"tags":["Agents"],"summary":"Activate a provider as the platform-wide default. Refuses to activate a\nprovider that doesn't have a credential saved yet — the UI enforces the\nsame rule on the button, but we re-check server-side so a stale tab\ncan't bypass it.","operationId":"activate_ai_provider","parameters":[{"name":"provider_id","in":"path","description":"AI provider ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivateProviderResponse"}}}},"400":{"description":"Provider not configured"},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/ai-providers/{provider_id}/credential":{"post":{"tags":["Agents"],"summary":"Save (or replace) a provider's credential. The credential is encrypted\nwith `EncryptionService` and stored inside\n`agent_sandbox.providers[provider_id].credentials_encrypted`.","description":"The plaintext shape depends on the flavor's `credential_format`:\n - `ApiKey` / `OauthToken`: the key/token string.\n - `ConfigFile`: the full file body (e.g. OpenCode's `auth.json`).","operationId":"save_ai_provider_credential","parameters":[{"name":"provider_id","in":"path","description":"AI provider ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveCredentialRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveCredentialResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/disk-status":{"get":{"tags":["Settings"],"summary":"Get current disk usage for the control-plane server","description":"Returns live disk usage for the monitored path along with any disks that\nmeet or exceed the configured alert threshold. Read-only — does not send\nnotifications. Used by the dashboard to surface a low-disk-space warning.","operationId":"get_disk_status","responses":{"200":{"description":"Current disk usage and threshold alerts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiskSpaceCheckResult"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/enrollment-tokens":{"get":{"tags":["Settings"],"summary":"List currently-valid node enrollment tokens (hashes elided).","operationId":"list_enrollment_tokens","responses":{"200":{"description":"Active enrollment tokens","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnrollmentTokenListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Settings"],"summary":"Mint a short-lived, single-use node enrollment token.","operationId":"mint_enrollment_token","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MintEnrollmentTokenRequest"}}},"required":true},"responses":{"200":{"description":"Enrollment token minted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MintEnrollmentTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/enrollment-tokens/{id}":{"delete":{"tags":["Settings"],"summary":"Revoke a node enrollment token by id.","operationId":"revoke_enrollment_token","parameters":[{"name":"id","in":"path","description":"Enrollment token id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Enrollment token revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsUpdateResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Enrollment token not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/join-token":{"delete":{"tags":["Settings"],"summary":"Revoke the current join token","description":"Removes the stored join token hash, allowing any node to register\n(if no other authentication is in place).","operationId":"revoke_join_token","responses":{"200":{"description":"Join token revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsUpdateResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/join-token/generate":{"post":{"tags":["Settings"],"summary":"Generate a new join token for multi-node cluster registration","description":"Creates a random 32-byte hex token, stores the SHA-256 hash in settings,\nand returns the plaintext exactly once. If a token already exists, it is replaced.","operationId":"generate_join_token","responses":{"200":{"description":"Join token generated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateJoinTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/join-token/status":{"get":{"tags":["Settings"],"summary":"Check whether a join token is currently configured","operationId":"get_join_token_status","responses":{"200":{"description":"Join token status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JoinTokenStatusResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/mcp-servers":{"get":{"tags":["Agents"],"operationId":"list_global_mcps","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListMcpsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_global_mcp","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMcpRequest"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/mcp-servers/{slug}":{"get":{"tags":["Agents"],"operationId":"get_global_mcp","parameters":[{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_global_mcp","parameters":[{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMcpRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_global_mcp","parameters":[{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"MCP server deleted"},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]}},"/settings/mcp-servers/{slug}/config/{field}":{"get":{"tags":["Agents"],"operationId":"reveal_global_mcp_config","parameters":[{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}},{"name":"field","in":"path","description":"Sensitive field path, such as url or env.API_TOKEN","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensitiveMcpConfigValueResponse"}}}},"400":{"description":"Field is not revealable"},"401":{"description":"Unauthorized"},"403":{"description":"Missing secrets:read permission"},"404":{"description":"MCP server or field not found"},"500":{"description":"Configuration read or audit failed"}},"security":[{"bearer_auth":[]}]}},"/settings/routes/refresh":{"post":{"tags":["Settings"],"summary":"Manually refresh the proxy route table","description":"Reloads all routes from the database into the in-memory proxy cache.\nUseful as a workaround when routes are out of sync.","operationId":"refresh_route_table","responses":{"200":{"description":"Route table refreshed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteRefreshResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/sandbox-rebuild":{"post":{"tags":["Agents"],"operationId":"rebuild_sandbox_image","responses":{"200":{"description":"Server-Sent Events stream of rebuild progress; final event `{\"type\":\"done\",\"success\":bool,...}`","content":{"text/event-stream":{}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/settings/sandbox-status":{"get":{"tags":["Agents"],"operationId":"get_global_sandbox_status","responses":{"200":{"description":"Global sandbox readiness for the settings page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/settings/secrets":{"get":{"tags":["Secrets"],"operationId":"list_secrets","responses":{"200":{"description":"List of global agent secrets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSecretsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Secrets"],"operationId":"upsert_secret","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertSecretRequest"}}},"required":true},"responses":{"201":{"description":"Secret created/updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecretResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/settings/secrets/{name}":{"delete":{"tags":["Secrets"],"operationId":"delete_secret","parameters":[{"name":"name","in":"path","description":"Secret name","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Secret deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Secret not found"}},"security":[{"bearer_auth":[]}]}},"/settings/skills":{"get":{"tags":["Agents"],"operationId":"list_global_skills","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSkillsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_global_skill","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSkillRequest"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/skills/upload":{"post":{"tags":["Agents"],"summary":"Upload a skill with an archive (tar.gz) — global.","operationId":"upload_global_skill","requestBody":{"content":{"multipart/form-data":{"schema":{"type":"string"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/skills/{slug}":{"get":{"tags":["Agents"],"operationId":"get_global_skill","parameters":[{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_global_skill","parameters":[{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSkillRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_global_skill","parameters":[{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Skill deleted"},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]}},"/settings/skills/{slug}/archive":{"get":{"tags":["Agents"],"summary":"Download a skill's archive (tar.gz) — global.","operationId":"download_global_skill_archive","parameters":[{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Skill archive tar.gz","content":{"application/gzip":{}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found or has no archive"}},"security":[{"bearer_auth":[]}]}},"/settings/update-status":{"get":{"tags":["Settings"],"summary":"Report whether a newer temps release is available for this install.","operationId":"get_update_status","responses":{"200":{"description":"Release update status for this install","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/teams":{"get":{"tags":["Teams"],"operationId":"list_teams","parameters":[{"name":"page","in":"query","description":"1-indexed page","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"default 20, max 100","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Paginated teams","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Teams"],"operationId":"create_team","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTeamRequest"}}},"required":true},"responses":{"201":{"description":"Team created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamResponse"}}}},"400":{"description":"Validation error"},"403":{"description":"Insufficient permissions"},"409":{"description":"Slug already taken"}},"security":[{"bearer_auth":[]}]}},"/teams/{team_id}":{"get":{"tags":["Teams"],"operationId":"get_team","parameters":[{"name":"team_id","in":"path","description":"Team id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Team","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamResponse"}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Teams"],"operationId":"delete_team","parameters":[{"name":"team_id","in":"path","description":"Team id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Team deleted"},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Teams"],"operationId":"update_team","parameters":[{"name":"team_id","in":"path","description":"Team id","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTeamRequest"}}},"required":true},"responses":{"200":{"description":"Updated team","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamResponse"}}}},"400":{"description":"Validation error"},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]}},"/teams/{team_id}/members":{"get":{"tags":["Teams"],"operationId":"list_team_members","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Members","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TeamMemberResponse"}}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Teams"],"operationId":"add_team_member","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTeamMemberRequest"}}},"required":true},"responses":{"201":{"description":"Member added","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamMemberResponse"}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"},"409":{"description":"User already a member"}},"security":[{"bearer_auth":[]}]}},"/teams/{team_id}/members/{user_id}":{"delete":{"tags":["Teams"],"operationId":"remove_team_member","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Member removed"},"403":{"description":"Insufficient permissions"},"404":{"description":"Member not found"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Teams"],"operationId":"update_team_member_role","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMemberRoleRequest"}}},"required":true},"responses":{"200":{"description":"Updated membership","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamMemberResponse"}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Member not found"}},"security":[{"bearer_auth":[]}]}},"/teams/{team_id}/projects":{"get":{"tags":["Teams"],"operationId":"list_team_projects","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Projects this team has access to","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectAccessResponse"}}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]}},"/templates":{"get":{"tags":["Templates"],"summary":"List all available templates","description":"Returns a list of all public templates, optionally filtered by tag or featured status.","operationId":"list_project_templates","parameters":[{"name":"tag","in":"query","description":"Filter templates by tag","required":false,"schema":{"type":"string"}},{"name":"featured","in":"query","description":"Only return featured templates","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of templates","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListTemplatesResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/templates/tags":{"get":{"tags":["Templates"],"summary":"List all available template tags","description":"Returns a list of all unique tags used by public templates.","operationId":"list_project_template_tags","responses":{"200":{"description":"List of tags","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListTagsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/templates/{slug}":{"get":{"tags":["Templates"],"summary":"Get a specific template by slug","description":"Returns detailed information about a single template.","operationId":"get_project_template","parameters":[{"name":"slug","in":"path","description":"Template slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Template details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Template not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/user/me":{"get":{"tags":["Authentication"],"operationId":"get_current_user","responses":{"200":{"description":"Successfully retrieved user information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/users":{"get":{"tags":["Users"],"operationId":"list_users","parameters":[{"name":"include_deleted","in":"query","description":"Include deleted users in the response","required":true,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List all users with their roles","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}}},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Users"],"summary":"Create a new user with roles","operationId":"create_user","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserRequest"}}},"required":true},"responses":{"201":{"description":"User created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}},"400":{"description":"Invalid input"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me":{"patch":{"tags":["Users"],"summary":"Update current user's information","operationId":"update_self","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSelfRequest"}}},"required":true},"responses":{"200":{"description":"User updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me/mfa":{"delete":{"tags":["Users"],"operationId":"disable_mfa","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DisableMfaRequest"}}},"required":true},"responses":{"204":{"description":"MFA disabled"},"400":{"description":"Invalid verification code"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me/mfa/setup":{"post":{"tags":["Users"],"operationId":"setup_mfa","responses":{"200":{"description":"MFA setup data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaSetupResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me/mfa/verify":{"post":{"tags":["Users"],"operationId":"verify_and_enable_mfa","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyMfaRequest"}}},"required":true},"responses":{"204":{"description":"MFA verified and enabled"},"400":{"description":"Invalid code"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me/password":{"post":{"tags":["Users"],"operationId":"change_password_self","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangePasswordRequest"}}},"required":true},"responses":{"204":{"description":"Password updated"},"400":{"description":"Validation error (weak password, same as current, MFA missing)"},"401":{"description":"Current password incorrect or MFA code invalid"},"403":{"description":"Account has no password set (SSO only)"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/{user_id}":{"delete":{"tags":["Users"],"summary":"Delete a user","operationId":"delete_user","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"User deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Cannot delete yourself or non-admin attempt"},"404":{"description":"User not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Users"],"summary":"Update user information (admin only)","operationId":"update_user","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserRequest"}}},"required":true},"responses":{"200":{"description":"User updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Non-admin attempt"},"404":{"description":"User not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/{user_id}/restore":{"post":{"tags":["Users"],"operationId":"restore_user","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"User restored successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}},"400":{"description":"User is not deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Non-admin attempt"},"404":{"description":"User not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/{user_id}/roles":{"post":{"tags":["Users"],"operationId":"assign_role","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignRoleRequest"}}},"required":true},"responses":{"200":{"description":"Role assigned successfully"},"400":{"description":"Invalid role type"},"401":{"description":"Unauthorized"},"403":{"description":"Admin role required or self-modification forbidden"},"404":{"description":"User or role not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/{user_id}/roles/{role_type}":{"delete":{"tags":["Users"],"operationId":"remove_role","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"role_type","in":"path","description":"Role type to remove","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Role removed successfully"},"400":{"description":"Invalid role type"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Cannot modify own roles or non-admin attempt"},"404":{"description":"User or role not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes":{"get":{"tags":["Sandboxes"],"operationId":"list_sandboxes","parameters":[{"name":"page","in":"query","description":"Page (1-indexed)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default 20, max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List sandboxes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSandboxesResponse"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Sandboxes"],"operationId":"create_sandbox","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSandboxBody"}}},"required":true},"responses":{"201":{"description":"Sandbox created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/rootfs":{"get":{"tags":["Sandboxes"],"summary":"Inspect rootfs storage: the Firecracker digest-keyed cache (with which\nsandboxes reference each entry) and per-VM disks. Empty on Docker-only\nhosts. Admin/read scope — this exposes host storage layout.","operationId":"rootfs_report","responses":{"200":{"description":"Rootfs storage report"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/rootfs/gc":{"post":{"tags":["Sandboxes"],"summary":"Reclaim rootfs cache entries not backing any live sandbox. Idempotent;\nsafe to call any time (live VMs hold their own per-VM disks).","operationId":"rootfs_gc","responses":{"200":{"description":"Reclaimed cache entries"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}":{"get":{"tags":["Sandboxes"],"operationId":"get_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sandbox details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"404":{"description":"Not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/cmd":{"post":{"tags":["Sandboxes"],"summary":"Run a command inside the sandbox (`@vercel/sandbox`-compatible).","description":"`wait=false` (default) returns `{ command: {..., exitCode: null} }`\nimmediately once the background task is spawned.\n\n`wait=true` streams `application/x-ndjson`: the first line is the\nrunning envelope, the second is the finished envelope with `exitCode`.","operationId":"cmd","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdBody"}}},"required":true},"responses":{"200":{"description":"Command started (wait=false) or finished (wait=true)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdResponse"}}}},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/cmd/{cmd_id}":{"get":{"tags":["Sandboxes"],"operationId":"get_cmd","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"cmd_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Command snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdResponse"}}}},"404":{"description":"Sandbox or command not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/cmd/{cmd_id}/logs":{"get":{"tags":["Sandboxes"],"summary":"Stream a command's stdout/stderr as `application/x-ndjson`\n(`@vercel/sandbox`-compatible). Each line is either\n`{stream:\"stdout\"|\"stderr\", data:\"...\"}` or\n`{stream:\"error\", data:{code, message}}`.","operationId":"cmd_logs","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"cmd_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"NDJSON stream of log events"},"404":{"description":"Sandbox or command not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/destroy":{"post":{"tags":["Sandboxes"],"operationId":"destroy_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Sandbox destroyed (alias for `/stop` with an explicit verb)"},"404":{"description":"Not found"},"409":{"description":"Sandbox belongs to an active agent run — stop the run instead"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/domain":{"get":{"tags":["Sandboxes"],"operationId":"domain","parameters":[{"name":"port","in":"query","description":"Port inside the sandbox (1..=65535)","required":true,"schema":{"type":"integer","format":"int32","minimum":0}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Preview URL for the port","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxDomainResponse"}}}},"400":{"description":"Invalid port"},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/events":{"get":{"tags":["Sandboxes"],"summary":"The operations timeline for a sandbox (lifecycle events only — never\nshell/exec activity), newest first.","operationId":"list_events","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Operations timeline","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxEventsResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/exec":{"post":{"tags":["Sandboxes"],"operationId":"exec","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecBody"}}},"required":true},"responses":{"200":{"description":"Command finished (non-zero exit is NOT an error)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecResponse"}}}},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/exec-detached":{"post":{"tags":["Sandboxes"],"operationId":"exec_detached","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecBody"}}},"required":true},"responses":{"202":{"description":"Command accepted; poll /jobs/{job_id}","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecDetachedResponse"}}}},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/extend-timeout":{"post":{"tags":["Sandboxes"],"operationId":"extend_timeout","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExtendTimeoutBody"}}},"required":true},"responses":{"200":{"description":"Timeout extended","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/mkdir":{"post":{"tags":["Sandboxes"],"operationId":"mkdir","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MkdirBody"}}},"required":true},"responses":{"204":{"description":"Directory created (or already existed)"},"400":{"description":"Validation error"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/read":{"get":{"tags":["Sandboxes"],"operationId":"read_file","parameters":[{"name":"path","in":"query","description":"Absolute file path inside the sandbox","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"File contents (base64)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReadFileResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Sandbox or file not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/stat":{"get":{"tags":["Sandboxes"],"operationId":"stat_path","parameters":[{"name":"path","in":"query","description":"Absolute path inside the sandbox","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Stat info (exists=false when missing — not an error)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatResponse"}}}},"400":{"description":"Validation error"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/write":{"post":{"tags":["Sandboxes"],"summary":"Write a file into the sandbox. Accepts two body shapes — the SDK\npicks one based on `Content-Type`:","description":"- **`application/json`** (temps-native): `{path, contents_b64, mode}`\n — one file, base64-encoded.\n- **`application/gzip`** (`@vercel/sandbox`): a gzipped tarball of\n one-or-more entries, with the target extract dir carried in the\n `x-cwd` header. The SDK's `writeFile` and `writeFiles` both post\n here; they differ only in how many entries the tarball contains.\n\nWhy merge them on one route: the SDK is hardcoded to\n`POST /fs/write`, so splitting tar uploads onto a separate path would\nforce us to break SDK compat. Instead we dispatch on Content-Type,\npreserve JSON for native callers, and add tar for SDK callers.","operationId":"write_file","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WriteFileBody"}}},"required":true},"responses":{"204":{"description":"File(s) written"},"400":{"description":"Validation error or invalid base64"},"404":{"description":"Sandbox not found"},"415":{"description":"Unsupported Content-Type (expected application/json or application/gzip)"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/write-batch":{"post":{"tags":["Sandboxes"],"summary":"Batch-write multiple files in a single request. Mirrors\n`@vercel/sandbox` `writeFiles()`. Semantics are fail-fast: if any\nfile errors, previously-written entries are left in place and the\nerror describes which file broke.","operationId":"write_files","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WriteFilesBody"}}},"required":true},"responses":{"200":{"description":"All files written","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WriteFilesResponse"}}}},"400":{"description":"Validation error or invalid base64"},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/jobs":{"get":{"tags":["Sandboxes"],"operationId":"list_jobs","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Detached jobs for this sandbox","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListJobsResponse"}}}},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/jobs/{job_id}":{"get":{"tags":["Sandboxes"],"operationId":"job_status","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"job_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Job status snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobStatusResponse"}}}},"404":{"description":"Sandbox or job not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/jobs/{job_id}/kill":{"post":{"tags":["Sandboxes"],"summary":"Terminate a detached job. Aborts the server-side tracking task and\nsends SIGTERM (or SIGKILL if `force=true`) to any matching processes\ninside the sandbox container. Returns 204 on success; 404 if the\nsandbox or job is unknown.","operationId":"kill_job","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"job_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KillJobBody"}}},"required":true},"responses":{"204":{"description":"Job killed"},"404":{"description":"Sandbox or job not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/jobs/{job_id}/logs":{"get":{"tags":["Sandboxes"],"summary":"SSE endpoint streaming each stdout/stderr line from a detached job\nas it's produced. Mirrors the `Command.logs()` async iterator shape\non `@vercel/sandbox` — events carry `{ stream, data }`.","description":"Late subscribers only see events produced after they connect. The\nJobState snapshot (`GET /jobs/{job_id}`) covers the history.\n\nA \"done\" sentinel event fires when the broadcast channel closes\n(the exec task has exited and dropped the sender), signalling\ncallers they can stop reading.","operationId":"job_logs","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"job_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"SSE stream of log events"},"404":{"description":"Sandbox or job not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/pause":{"post":{"tags":["Sandboxes"],"operationId":"pause_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sandbox paused (container stopped, state preserved)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Sandbox is in an incompatible state (e.g. already destroyed)"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/preview-link":{"post":{"tags":["Sandboxes"],"summary":"Mint a shareable link to a sandbox preview.","description":"`GET /domain` returns the bare preview URL, which is useless to anyone who\ndoes not already hold the sandbox's preview password — so sharing a\nprotected preview meant sharing that password, which is the same secret for\nevery recipient and can only be withdrawn by rotating it for all of them.\n\nThis returns the same URL carrying a short-lived, sandbox-scoped grant. The\nrecipient's browser exchanges it for the ordinary preview cookie and lands\non `path`. The grant never reaches the sandbox, so preview application code\ncannot read it and re-share it.\n\nAnyone holding the returned URL can view the preview until it expires;\nthere is no per-link revocation short of rotating the preview password.","operationId":"sandbox_create_preview_link","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewShareLinkBody"}}},"required":true},"responses":{"200":{"description":"Shareable preview link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewShareLinkResponse"}}}},"400":{"description":"Invalid port"},"404":{"description":"Sandbox not found"},"409":{"description":"Sandbox has no preview password"},"500":{"description":"Preview grant minting failed"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/preview-password":{"put":{"tags":["Sandboxes"],"operationId":"set_preview_password","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPreviewPasswordBody"}}},"required":true},"responses":{"200":{"description":"Preview password set or rotated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPreviewPasswordResponse"}}}},"400":{"description":"Password too short or too long"},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Sandboxes"],"operationId":"clear_preview_password","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Preview password removed (sandbox is now URL-only protected)"},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/resize":{"post":{"tags":["Sandboxes"],"summary":"Grow a Firecracker sandbox's root disk. Offline resize — the VM reboots\n(filesystem/data persist) rather than resizing fully live.","operationId":"resize_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResizeSandboxBody"}}},"required":true},"responses":{"200":{"description":"Resized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"400":{"description":"Invalid size or unsupported backend"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/restart":{"post":{"tags":["Sandboxes"],"operationId":"restart_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sandbox container restarted in place","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Sandbox is stopped (use /resume) or already destroyed"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/resume":{"post":{"tags":["Sandboxes"],"operationId":"resume_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sandbox resumed; expires_at refreshed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Sandbox is not in a resumable state"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/source":{"post":{"tags":["Sandboxes"],"operationId":"source_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceBody"}}},"required":true},"responses":{"200":{"description":"Source content seeded into the sandbox work dir","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"400":{"description":"Validation error (embedded creds, conflicting fields, etc.)"},"404":{"description":"Sandbox not found"},"409":{"description":"Sandbox is not running"},"500":{"description":"Source seed failed inside sandbox"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/stop":{"post":{"tags":["Sandboxes"],"operationId":"stop_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Sandbox stopped and destroyed"},"404":{"description":"Not found"},"409":{"description":"Sandbox belongs to an active agent run — stop the run instead"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/{cmd_id}/kill":{"post":{"tags":["Sandboxes"],"summary":"Kill a running command (`@vercel/sandbox`-compatible). The SDK\ncalls `POST /v1/sandboxes/{id}/{cmdId}/kill` — note the path has the\ncommand ID directly under the sandbox, NOT under `/jobs/` or `/cmd/`.","operationId":"cmd_kill","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"cmd_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdKillBody"}}}},"responses":{"200":{"description":"Command killed; returns final snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdResponse"}}}},"404":{"description":"Sandbox or command not found"}},"security":[{"bearer_auth":[]}]}},"/visitors/{visitor_id}/session-replays":{"get":{"tags":["Analytics"],"summary":"Get session replays for a visitor","operationId":"get_visitor_sessions","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Session replays retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetVisitorSessionsResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/visitors/{visitor_id}/session-replays/{session_id}":{"get":{"tags":["Analytics"],"summary":"Get session replay data with visitor info (without events)","operationId":"get_session_replay","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Session replay retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetSessionReplayResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Analytics"],"summary":"Delete a session replay","operationId":"delete_session_replay","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Session replay deleted successfully"},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/visitors/{visitor_id}/session-replays/{session_id}/duration":{"put":{"tags":["Analytics"],"summary":"Update session duration","operationId":"update_session_duration","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSessionDurationRequest"}}},"required":true},"responses":{"200":{"description":"Session duration updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSessionDurationResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/visitors/{visitor_id}/session-replays/{session_id}/events":{"get":{"tags":["Analytics"],"summary":"Get session replay events (with session and visitor metadata)","operationId":"get_session_replay_events","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Session replay with events retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionReplayWithEventsDto"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Analytics"],"summary":"Add events to an existing session","operationId":"add_events","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddEventsRequest"}}},"required":true},"responses":{"200":{"description":"Events added successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddEventsResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/vulnerability-scans/{scan_id}":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_scan","parameters":[{"name":"scan_id","in":"path","description":"Scan ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Scan details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Scan not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Vulnerability Scans"],"operationId":"delete_scan","parameters":[{"name":"scan_id","in":"path","description":"Scan ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Scan deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Scan not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/vulnerability-scans/{scan_id}/vulnerabilities":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_scan_vulnerabilities","parameters":[{"name":"scan_id","in":"path","description":"Scan ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"severity","in":"query","description":"Filter by severity (CRITICAL, HIGH, MEDIUM, LOW)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of vulnerabilities","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/VulnerabilityResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Scan not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/webhook-event-types":{"get":{"tags":["Webhooks"],"summary":"List available event types","operationId":"list_event_types","responses":{"200":{"description":"List of available event types","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventTypeResponse"}}}}}}}},"/weekly-digest/trigger":{"post":{"tags":["Notification Preferences"],"summary":"Trigger weekly digest generation manually","operationId":"trigger_weekly_digest","responses":{"200":{"description":"Weekly digest triggered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerDigestResponse"}}}},"500":{"description":"Failed to generate digest"}},"security":[{"bearer_auth":[]}]}},"/x/plugins":{"get":{"tags":["External Plugins"],"summary":"List all running external plugins and their manifests.","description":"Requires only a valid session/token (no specific permission) since the\nmanifest drives sidebar navigation rendering for every authenticated\nuser, not just admins.","operationId":"list_external_plugins","responses":{"200":{"description":"List of all running external plugins","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PluginManifest"}}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/x/plugins/reload":{"post":{"tags":["External Plugins"],"summary":"Reload all external plugins.","description":"Stops all running plugin processes, re-scans the plugins directory,\nstarts any discovered binaries, and hot-swaps the proxy router so new\nand removed plugins take effect immediately without a server restart.\n\nRequires `SystemAdmin` permission.","operationId":"reload_plugins","responses":{"200":{"description":"Plugins reloaded successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReloadResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/{project_id}/envelope/":{"post":{"tags":["sentry-ingestor"],"summary":"Ingest a Sentry envelope (binary payload)","operationId":"ingest_sentry_envelope","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"Sentry envelope as binary data","content":{"application/octet-stream":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Envelope ingested"},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"413":{"description":"Request body too large (exceeds 2 MiB)"}}}},"/{project_id}/store/":{"post":{"tags":["sentry-ingestor"],"summary":"Ingest a Sentry event (JSON payload)","operationId":"ingest_sentry_event","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryEventRequest"}}},"required":true},"responses":{"200":{"description":"Event ingested","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryEventResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"413":{"description":"Request body too large (exceeds 2 MiB)"}}}},"audit/logs":{"get":{"tags":["Audit Logs"],"summary":"List audit logs with optional filtering","operationId":"list_audit_logs","parameters":[{"name":"operation_type","in":"query","description":"Filter logs by operation type (omit for all)","required":false,"schema":{"type":"string"},"example":"user.login"},{"name":"user_id","in":"query","description":"Filter logs by user ID (omit for all users)","required":false,"schema":{"type":"integer","format":"int32"},"example":1},{"name":"from","in":"query","description":"Start timestamp (milliseconds since epoch)","required":false,"schema":{"type":"string","format":"date-time"},"example":1},{"name":"to","in":"query","description":"End timestamp (milliseconds since epoch)","required":false,"schema":{"type":"string","format":"date-time"},"example":1},{"name":"limit","in":"query","description":"Maximum number of logs to return","required":false,"schema":{"type":"integer","format":"int32"},"example":100},{"name":"offset","in":"query","description":"Number of logs to skip","required":false,"schema":{"type":"integer","format":"int32"},"example":0}],"responses":{"200":{"description":"List of audit logs","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AuditLogResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"api_key":[]}]}},"audit/logs/{id}":{"get":{"tags":["Audit Logs"],"summary":"Get a specific audit log entry by ID","operationId":"get_audit_log","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Audit log details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuditLogResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Audit log not found"},"500":{"description":"Internal server error"}},"security":[{"api_key":[]}]}}},"components":{"schemas":{"AcmeOrderResponse":{"type":"object","required":["id","order_url","domain_id","email","status","identifiers","created_at","updated_at"],"properties":{"authorizations":{},"certificate_url":{"type":["string","null"]},"challenge_validation":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ChallengeValidationStatus","description":"Live challenge validation status fetched from Let's Encrypt"}]},"created_at":{"type":"integer","format":"int64"},"domain_id":{"type":"integer","format":"int32"},"email":{"type":"string"},"error":{"type":["string","null"]},"error_type":{"type":["string","null"]},"expires_at":{"type":["integer","null"],"format":"int64"},"finalize_url":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"identifiers":{},"order_url":{"type":"string"},"status":{"type":"string"},"updated_at":{"type":"integer","format":"int64"}}},"ActivateProviderResponse":{"type":"object","required":["default_provider"],"properties":{"default_provider":{"type":"string"}}},"ActiveVisitor":{"type":"object","required":["session_id","session_start","last_activity","page_count","event_count","duration_seconds","is_active"],"properties":{"current_page":{"type":["string","null"]},"duration_seconds":{"type":"integer","format":"int64"},"event_count":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"last_activity":{"type":"string"},"page_count":{"type":"integer","format":"int32"},"session_id":{"type":"string"},"session_start":{"type":"string"},"visitor_id":{"type":["string","null"]}}},"ActiveVisitorsQuery":{"type":"object","properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"}}},"ActiveVisitorsResponse":{"type":"object","required":["active_visitors","window_minutes"],"properties":{"active_visitors":{"type":"integer","format":"int64"},"window_minutes":{"type":"integer","format":"int32"}}},"ActivityDay":{"type":"object","description":"Daily activity count for a single day","required":["date","count","level"],"properties":{"count":{"type":"integer","format":"int64","description":"Number of deployments on this day"},"date":{"type":"string","description":"Date in YYYY-MM-DD format","example":"2024-06-15"},"level":{"type":"integer","format":"int32","description":"Intensity level (0-4) for visualization\n0: No activity, 1: Low (1-2), 2: Medium (3-5), 3: High (6-10), 4: Very High (11+)","example":2}}},"ActivityEvent":{"type":"object","description":"A single activity event for the real-time activity feed","required":["id","timestamp","event_type","page_path","is_crawler"],"properties":{"browser":{"type":["string","null"],"description":"Browser"},"city":{"type":["string","null"],"description":"Visitor's city (from ip_geolocations)"},"country":{"type":["string","null"],"description":"Visitor's country (from ip_geolocations)"},"country_code":{"type":["string","null"],"description":"Visitor's country code (from ip_geolocations)"},"device_type":{"type":["string","null"],"description":"Device type"},"event_name":{"type":["string","null"],"description":"Event name (for custom events)"},"event_type":{"type":"string","description":"Event type: \"page_view\", \"custom\", etc."},"id":{"type":"integer","format":"int64","description":"Event ID"},"is_crawler":{"type":"boolean","description":"Whether this event was from a crawler"},"latitude":{"type":["number","null"],"format":"double","description":"Latitude"},"longitude":{"type":["number","null"],"format":"double","description":"Longitude"},"operating_system":{"type":["string","null"],"description":"Operating system"},"page_path":{"type":"string","description":"Page path where the event happened"},"page_title":{"type":["string","null"],"description":"Page title"},"referrer":{"type":["string","null"],"description":"Referrer"},"timestamp":{"type":"string","format":"date-time","description":"When the event occurred"},"visitor_id":{"type":["integer","null"],"format":"int32","description":"Visitor numeric ID"}}},"ActivityGraphQuery":{"type":"object","description":"Query parameters for activity graph endpoint","properties":{"days":{"type":"integer","format":"int32","description":"Number of days to include (default: 365 for last year)"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment ID to filter activity"},"project_id":{"type":["integer","null"],"format":"int32","description":"Optional project ID to filter activity"}}},"ActivityGraphResponse":{"type":"object","description":"Response for activity graph showing daily deployment activity","required":["days","total_count","start_date","end_date"],"properties":{"days":{"type":"array","items":{"$ref":"#/components/schemas/ActivityDay"},"description":"Array of daily activity counts"},"end_date":{"type":"string","description":"Date range end (YYYY-MM-DD)","example":"2024-12-31"},"start_date":{"type":"string","description":"Date range start (YYYY-MM-DD)","example":"2024-01-01"},"total_count":{"type":"integer","format":"int64","description":"Total count of activities across all days"}}},"AddClusterMemberRequest":{"type":"object","description":"Request body for adding a single member to a running cluster.","required":["role"],"properties":{"node_id":{"type":["integer","null"],"format":"int32","description":"Target worker node ID. Omit or null to run on the control plane."},"role":{"type":"string","description":"Member role. Currently only `replica` is accepted at runtime —\nmonitor is a singleton, primary is elected by pg_auto_failover.","example":"replica"}}},"AddContextRequest":{"type":"object","required":["message"],"properties":{"message":{"type":"string"}}},"AddEnvironmentDomainRequest":{"type":"object","required":["domain","is_primary"],"properties":{"domain":{"type":"string"},"is_primary":{"type":"boolean"}}},"AddEventsRequest":{"type":"object","required":["events"],"properties":{"events":{"type":"string"}}},"AddEventsResponse":{"type":"object","required":["event_count","message"],"properties":{"event_count":{"type":"integer","minimum":0},"message":{"type":"string"}}},"AddManagedDomainApiRequest":{"type":"object","description":"Request to add a managed domain","required":["domain"],"properties":{"auto_manage":{"type":"boolean"},"domain":{"type":"string","example":"example.com"},"generated_hostname_mode":{"type":["string","null"],"description":"Generated hostname layout: `\"standard\"` (default) or `\"flat\"`."},"sync_generated_records":{"type":"boolean","description":"Opt in to reconciling generated hostnames into this domain's DNS zone."}}},"AdminGateResponse":{"type":"object","required":["allowed_ips","allowed_hosts","trust_forwarded_for","source","editable"],"properties":{"allowed_hosts":{"type":"array","items":{"type":"string"},"description":"`Host` header values allowed. Empty = any host."},"allowed_ips":{"type":"array","items":{"type":"string"},"description":"IPs / CIDRs allowed to reach the admin listener. Empty = any source."},"editable":{"type":"boolean","description":"True when the config is writable through this API. False when env\nvars are dictating the active config."},"source":{"$ref":"#/components/schemas/AdminGateSource","description":"Where the active config came from."},"trust_forwarded_for":{"type":"boolean","description":"When true, the gate trusts `X-Forwarded-For` from loopback peers."}}},"AdminGateSource":{"type":"string","description":"Where the active gate configuration came from. Env-supplied configs are\nfrozen at the process level — the UI shows them read-only and refuses to\npersist DB writes. DB-supplied configs are editable at runtime.","enum":["default","db","env"]},"AgentConfigResponse":{"type":"object","description":"Response DTO for a single agent — masks the encrypted API key.","required":["id","project_id","slug","name","source","enabled","trigger_config","ai_provider","api_key_set","max_turns","timeout_seconds","daily_budget_cents","cooldown_minutes","branch_prefix","deliverable","created_at","updated_at"],"properties":{"ai_model":{"type":["string","null"],"description":"Preferred model for the CLI (e.g. \"sonnet\", \"gpt-5-codex\"). `None` means default."},"ai_provider":{"type":"string"},"ai_provider_key_id":{"type":["integer","null"],"format":"int32"},"api_key_set":{"type":"boolean","description":"`true` if an API key is set; `false` otherwise."},"branch_prefix":{"type":"string"},"config_repo_branch":{"type":["string","null"],"description":"Branch of the config repo to use."},"config_repo_url":{"type":["string","null"],"description":"Private config repo containing .claude/ directory (skills, MCP, plugins)."},"cooldown_minutes":{"type":"integer","format":"int32"},"created_at":{"type":"string"},"daily_budget_cents":{"type":"integer","format":"int32"},"deliverable":{"type":"string"},"description":{"type":["string","null"]},"enabled":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"max_turns":{"type":"integer","format":"int32"},"mcp_servers_config":{"description":"MCP servers config (Claude Code settings.json mcpServers format).\nCredential-bearing legacy inline values are write-only and appear as\n`***`. Omit this field on update to preserve their stored values."},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"prompt":{"type":["string","null"]},"sandbox_enabled":{"type":["boolean","null"],"description":"None = use global sandbox setting, true = force on, false = force off"},"skills_config":{"description":"Skills config as JSON array."},"slug":{"type":"string"},"source":{"type":"string"},"timeout_seconds":{"type":"integer","format":"int32"},"tools_config":{"description":"Tools config as JSON array. Legacy custom-tool webhook URLs and headers\nare write-only and appear as `***`. Omit this field on update to\npreserve their stored values."},"trigger_config":{},"updated_at":{"type":"string"},"webhook_token":{"type":["string","null"],"description":"Secret token for the `X-Webhook-Token` header. Shown once when created,\nmasked with `***` prefix in subsequent reads."},"webhook_url":{"type":["string","null"],"description":"Public webhook URL for triggering this agent externally.\nOnly set when `on: { webhook: true }` is configured.\nUsage: `POST {webhook_url}` with header `X-Webhook-Token: {webhook_token}`"}}},"AgentRunLogResponse":{"type":"object","required":["id","run_id","level","message","created_at"],"properties":{"created_at":{"type":"string"},"id":{"type":"integer","format":"int64"},"level":{"type":"string"},"message":{"type":"string"},"metadata":{},"run_id":{"type":"integer","format":"int32"}}},"AgentRunResponse":{"type":"object","required":["id","project_id","source","trigger_type","status","tokens_input","tokens_output","estimated_cost_cents","files_changed","created_at","sandbox_enabled"],"properties":{"agent_name":{"type":["string","null"],"description":"Name of the agent that created this run, if available."},"agent_slug":{"type":["string","null"],"description":"Slug of the agent that created this run, if available."},"ai_model":{"type":["string","null"]},"ai_output":{"type":["string","null"]},"ai_provider":{"type":["string","null"],"description":"AI provider slug that executed this run (e.g. claude_cli, codex_cli, opencode)."},"ai_reasoning":{"type":["string","null"]},"ai_session_id":{"type":["string","null"],"description":"Claude CLI session UUID for resuming conversations via `--resume`."},"analysis":{"type":["string","null"],"description":"Report / analysis text produced by the agent (used for report/notification deliverables)."},"branch_name":{"type":["string","null"]},"commit_sha":{"type":["string","null"]},"completed_at":{"type":["string","null"]},"config_id":{"type":["integer","null"],"format":"int32","description":"Optional. NULL for ephemeral CLI runs (`source = \"cli_ephemeral\"`) and\nhistorical autofixer runs that pre-date the agent_id column."},"created_at":{"type":"string"},"ephemeral_yaml":{"type":["string","null"],"description":"Full WorkflowYamlConfig as YAML text. Populated only when\n`source = \"cli_ephemeral\"`. Used by the web UI to show a \"View YAML\"\nmodal so the user can see exactly what the executor ran."},"error_message":{"type":["string","null"]},"estimated_cost_cents":{"type":"integer","format":"int32"},"files_changed":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"phase":{"type":["string","null"],"description":"Autofixer phase: \"analyzing\", \"analyzed\", \"fixing\", \"fix_ready\", \"no_fix\",\n\"pr_created\", or NULL for non-autofixer runs."},"pr_number":{"type":["integer","null"],"format":"int32"},"pr_url":{"type":["string","null"]},"preview_url":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"prompt_text":{"type":["string","null"],"description":"Final assembled prompt the AI CLI actually saw (trigger context block +\nYAML prompt, with error-group fields interpolated). Captured once per\nrun. `None` for pre-migration rows."},"run_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AutofixRunConfig","description":"Per-run AI options the user chose when starting an autofixer run\n(provider, model, max_turns, branch). NULL for generic agent runs\nand historical rows. Used to prefill the retry dialog."}]},"sandbox_enabled":{"type":"boolean","description":"Legacy field — all runs now execute in a sandbox. Kept for\nbackwards-compatible JSON shape; always `true`."},"source":{"type":"string","description":"`committed` (the run's config lives in `project_agents`) or\n`cli_ephemeral` (the config was uploaded via the CLI for a one-off\ndry run; see `ephemeral_yaml`)."},"started_at":{"type":["string","null"]},"status":{"type":"string"},"tokens_input":{"type":"integer","format":"int32"},"tokens_output":{"type":"integer","format":"int32"},"trigger_source_id":{"type":["integer","null"],"format":"int32"},"trigger_source_type":{"type":["string","null"]},"trigger_type":{"type":"string"},"user_context":{"type":["string","null"],"description":"User-provided context for this run (e.g. webhook payload, manual instructions)."}}},"AgentRunWithLogsResponse":{"type":"object","required":["run","logs"],"properties":{"logs":{"type":"array","items":{"$ref":"#/components/schemas/AgentRunLogResponse"}},"run":{"$ref":"#/components/schemas/AgentRunResponse"}}},"AgentSandboxSettings":{"type":"object","description":"Global agent sandbox settings. Controls whether agent runs are isolated\ninside Docker containers by default. Individual agents can override this.","properties":{"api_key_encrypted":{"type":["string","null"],"description":"DEPRECATED: use `providers[default_provider].credentials_encrypted` instead.","default":null},"auth_type":{"type":"string","description":"DEPRECATED: use `providers[default_provider].auth_type` instead.","default":"subscription"},"cpu_limit":{"type":"number","format":"double","description":"CPU limit in cores for sandbox containers","default":4.0,"example":4.0},"custom_image":{"type":"string","description":"Custom Docker image (only used when runtime is \"custom\").\nMust have git and claude CLI installed.","default":"","example":""},"default_provider":{"type":"string","description":"Default AI provider for agents: \"claude_cli\", \"opencode\", or \"codex_cli\".\nWorkspaces always use this provider — no per-session override.","default":"claude_cli","example":"claude_cli"},"enabled":{"type":"boolean","description":"Sandbox is always enabled — the executor refuses to run any agent\noutside a sandboxed container. Field is retained so existing settings\nrows still deserialize, but it is ignored at runtime.","default":true},"memory_limit_mb":{"type":"integer","format":"int64","description":"Memory limit in MB for sandbox containers","default":8192,"example":8192,"minimum":0},"network_mode":{"type":"string","description":"Network access level: \"full\" (unrestricted), \"restricted\" (Temps network only), \"none\" (no network)","default":"full","example":"full"},"providers":{"type":"object","description":"Per-provider auth + config. Keyed by provider id (e.g. `claude_cli`,\n`codex_cli`, `opencode`). Adding a new provider only requires a new\ncatalog entry on the Rust side — the JSON column stays migration-free.","default":{},"additionalProperties":{"$ref":"#/components/schemas/ProviderConfig"},"propertyNames":{"type":"string"}},"runtime":{"type":"string","description":"Runtime preset: \"node\", \"bun\", \"python\", \"rust\", \"go\", \"full\", or \"custom\"","default":"node","example":"node"},"sandbox_backend":{"type":["string","null"],"description":"Default isolation backend for sandboxes: \"docker\" (default) or\n\"firecracker\" (ADR-029; requires `temps firecracker setup`). Only\nconsulted when the Firecracker backend probes available — otherwise\nDocker is used regardless.","default":null,"example":"docker"}}},"AgentSandboxSettingsMasked":{"type":"object","description":"Agent sandbox settings with masked per-provider credentials.\nEach provider entry reports only whether a credential is saved, not\nthe encrypted blob itself. Non-sensitive fields (auth_type, default_model,\nextra) are passed through so the UI can render provider-specific state.","required":["default_provider","providers","api_key_saved","auth_type","enabled","runtime","custom_image","cpu_limit","memory_limit_mb","network_mode","sandbox_backend"],"properties":{"api_key_saved":{"type":"boolean"},"auth_type":{"type":"string"},"cpu_limit":{"type":"number","format":"double"},"custom_image":{"type":"string"},"default_provider":{"type":"string"},"enabled":{"type":"boolean"},"memory_limit_mb":{"type":"integer","format":"int64","minimum":0},"network_mode":{"type":"string"},"providers":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/ProviderConfigMasked"},"propertyNames":{"type":"string"}},"runtime":{"type":"string"},"sandbox_backend":{"type":"string"}}},"AggregatedBucketItem":{"type":"object","required":["timestamp","count"],"properties":{"count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"}}},"AggregatedBucketsQuery":{"type":"object","description":"Query parameters for aggregated metrics by time bucket","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events, sessions, or visitors"},"bucket_size":{"type":"string","description":"Time bucket size: \"1 hour\", \"1 day\", \"1 week\", etc. (default: \"1 hour\")"},"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment filter"},"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment filter"},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"AggregatedBucketsResponse":{"type":"object","required":["bucket_size","aggregation_level","items","total"],"properties":{"aggregation_level":{"type":"string"},"bucket_size":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AggregatedBucketItem"}},"total":{"type":"integer","format":"int64"}}},"AggregationLevel":{"type":"string","enum":["events","sessions","visitors"]},"AggregationTemporality":{"type":"string","description":"The aggregation temporality of a Sum/Histogram/ExponentialHistogram metric.\n\nMirrors OTel's `AggregationTemporality` proto enum: whether reported values\nare cumulative since the start of the series (Cumulative) or only the delta\nsince the previous report (Delta).","enum":["unspecified","delta","cumulative"]},"AiAgentBreakdownResponse":{"type":"object","description":"Response wrapping the AI agent breakdown rows.","required":["items","start_time","end_time"],"properties":{"end_time":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiAgentBreakdownRow"}},"start_time":{"type":"string"}}},"AiAgentBreakdownRow":{"type":"object","description":"One row in the AI-agent analytics breakdown. `agent` is the canonical\ncrawler name (e.g. `GPTBot`, `Claude-User`), `provider` is the vendor used\nfor grouping + logos. The UI mirrors the browsers card and ranks by\n`request_count`.","required":["provider","agent","purpose","request_count","unique_ips"],"properties":{"agent":{"type":"string"},"last_seen":{"type":["string","null"],"description":"Last-seen timestamp in RFC3339 format, or `None` if no rows matched.","example":"2026-05-29T12:00:00Z"},"provider":{"type":"string"},"purpose":{"type":"string"},"request_count":{"type":"integer","format":"int64"},"unique_ips":{"type":"integer","format":"int64"}}},"AiAgentDescriptor":{"type":"object","description":"Static descriptor for one entry in the known-AI-agents taxonomy.","required":["provider","agent","purpose"],"properties":{"agent":{"type":"string"},"provider":{"type":"string"},"purpose":{"type":"string"}}},"AiAgentPageRow":{"type":"object","description":"One row in the pages-by-agent breakdown. Returned by\n[`ProxyLogService::get_ai_agent_pages`] for a single named agent.\n`unique_ips` counts distinct client IPs that hit this path via that agent\n(same definition as the per-agent unique-IPs in [`AiAgentBreakdownRow`]).","required":["path","request_count","unique_ips"],"properties":{"last_seen":{"type":["string","null"],"description":"Last-seen timestamp in RFC3339 format, or `None` if no rows matched.","example":"2026-05-29T12:00:00Z"},"path":{"type":"string"},"request_count":{"type":"integer","format":"int64"},"unique_ips":{"type":"integer","format":"int64"}}},"AiAgentPagesResponse":{"type":"object","description":"Response wrapping the per-agent pages breakdown rows.","required":["agent","items","start_time","end_time"],"properties":{"agent":{"type":"string","description":"The agent name this breakdown is scoped to."},"end_time":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiAgentPageRow"}},"start_time":{"type":"string"}}},"AiAgentTimelineResponse":{"type":"object","description":"Response wrapping the AI agent timeline rows.","required":["items","start_time","end_time","bucket","group_by"],"properties":{"bucket":{"type":"string","description":"Bucket interval used for the buckets (so the UI can label the x-axis).","example":"1 hour"},"end_time":{"type":"string"},"group_by":{"type":"string","description":"Echoes the grouping dimension actually applied.","example":"provider"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiAgentTimelineRow"}},"start_time":{"type":"string"}}},"AiAgentTimelineRow":{"type":"object","description":"One point in the AI-agent timeline: the request count for a single\n(`bucket`, `key`) pair, where `key` is a provider or agent name depending on\nthe requested grouping. The UI pivots these into one stacked series per\n`key` across the shared bucket x-axis.","required":["bucket","key","request_count"],"properties":{"bucket":{"type":"string","description":"Bucket start in RFC3339 format.","example":"2026-05-29T12:00:00Z"},"key":{"type":"string","description":"Provider or agent name this count belongs to.","example":"OpenAI"},"request_count":{"type":"integer","format":"int64"}}},"AiChatLimitsSettings":{"type":"object","description":"Bounds on one AI chat turn.\n\nA turn is bounded by TIME rather than by a number of steps. A step count\nsays nothing about cost or about how long someone has been watching a\nspinner, and it cuts short exactly the long, productive turns the chat\nexists for. The user can already see each tool call and press Stop; the\ndeadline is what guarantees an *unattended* turn still ends.\n\nThe right value is a property of the model, which is why it is configurable\nrather than compiled in: a full alert-suggestion turn takes ~10 minutes\nagainst a slow local model and seconds against a hosted one.","properties":{"turn_timeout_secs":{"type":"integer","format":"int32","description":"How long one turn may run before it is stopped and the partial answer\nreturned, in seconds. The user is told the turn was cut short.\n\nChecked between steps, not mid-call: a model round already in flight\nfinishes, so a turn can overrun by up to one round. Against a slow\nself-hosted model that is a minute or two. Aborting mid-stream would cut\nthe answer off in the middle of a sentence and throw away work already\npaid for, which is worse than a late stop.","default":900,"example":900,"maximum":3600,"minimum":30}}},"AiConfigSettings":{"type":"object","description":"Global AI configuration settings. Controls the default config repo\ncontaining `.claude/` directory (skills, MCP servers, plugins) that\ngets overlaid into every agent sandbox.","properties":{"config_repo":{"type":"string","description":"Global config repo URL in \"owner/repo\" format (e.g. \"myorg/claude-config\").\nCloned at agent run time and overlaid into the sandbox's `.claude/` directory.","default":"","example":""},"config_repo_branch":{"type":"string","description":"Branch of the config repo to use.","default":"main","example":"main"}}},"AiPageBreakdownResponse":{"type":"object","description":"Response wrapping the AI page breakdown rows.","required":["items","start_time","end_time"],"properties":{"end_time":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiPageBreakdownRow"}},"start_time":{"type":"string"}}},"AiPageBreakdownRow":{"type":"object","description":"One row in the AI-crawled-pages breakdown. `agent_count` is the number of\n*distinct* AI agents that hit this path, so the UI can show both how heavily\nand how broadly a page is being crawled.","required":["path","request_count","agent_count"],"properties":{"agent_count":{"type":"integer","format":"int64"},"last_seen":{"type":["string","null"],"description":"Last-seen timestamp in RFC3339 format, or `None` if no rows matched.","example":"2026-05-29T12:00:00Z"},"path":{"type":"string"},"request_count":{"type":"integer","format":"int64"}}},"AiStatusBreakdownResponse":{"type":"object","description":"Response wrapping the AI status breakdown rows.","required":["items","start_time","end_time"],"properties":{"end_time":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiStatusBreakdownRow"}},"start_time":{"type":"string"}}},"AiStatusBreakdownRow":{"type":"object","description":"One row in the AI-agent HTTP status breakdown: the request count for a\nstatus class (`2xx`/`3xx`/`4xx`/`5xx`/`other`) across crawler traffic.","required":["status_class","request_count"],"properties":{"request_count":{"type":"integer","format":"int64"},"status_class":{"type":"string","description":"Status class label.","example":"2xx"}}},"AlarmListResponse":{"type":"object","description":"Paginated list of alarms.","required":["items","total","page","page_size"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AlarmResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"AlarmResponse":{"type":"object","description":"Full alarm representation returned by list/summary endpoints.","required":["id","project_id","alarm_type","severity","status","title","fired_at","created_at","updated_at"],"properties":{"acknowledged_at":{"type":["string","null"],"description":"ISO-8601 UTC timestamp when the alarm was acknowledged, if any."},"acknowledged_by":{"type":["integer","null"],"format":"int32","description":"User ID who acknowledged the alarm, if any."},"alarm_type":{"type":"string"},"container_id":{"type":["integer","null"],"format":"int32"},"created_at":{"type":"string","description":"ISO-8601 UTC timestamp when the row was created."},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"fired_at":{"type":"string","description":"ISO-8601 UTC timestamp when the alarm fired."},"id":{"type":"integer","format":"int32"},"message":{"type":["string","null"]},"metadata":{"description":"Arbitrary JSON metadata attached by the alarm source."},"project_id":{"type":"integer","format":"int32"},"resolved_at":{"type":["string","null"],"description":"ISO-8601 UTC timestamp when the alarm was resolved, if any."},"service_id":{"type":["integer","null"],"format":"int32"},"severity":{"type":"string"},"status":{"type":"string"},"title":{"type":"string"},"updated_at":{"type":"string","description":"ISO-8601 UTC timestamp when the row was last updated."}}},"AlarmSummaryResponse":{"type":"object","description":"Re-export AlarmSummary for the OpenAPI schema.","required":["total_active","firing","acknowledged","critical","warning","by_type"],"properties":{"acknowledged":{"type":"integer","format":"int32","minimum":0},"by_type":{"type":"object","additionalProperties":{"type":"integer","format":"int32","minimum":0},"propertyNames":{"type":"string"}},"critical":{"type":"integer","format":"int32","minimum":0},"firing":{"type":"integer","format":"int32","minimum":0},"total_active":{"type":"integer","format":"int32","minimum":0},"warning":{"type":"integer","format":"int32","minimum":0}}},"AlertRuleResponse":{"type":"object","required":["id","project_id","name","trigger_type","trigger_config","notification_priority","cooldown_minutes","enabled","created_at","updated_at"],"properties":{"cooldown_minutes":{"type":"integer","format":"int32"},"created_at":{"type":"string"},"enabled":{"type":"boolean"},"environment_filter":{"type":["integer","null"],"format":"int32"},"error_level_filter":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"notification_priority":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"trigger_config":{},"trigger_type":{"type":"string"},"updated_at":{"type":"string"}}},"AllocEntry":{"type":"object","description":"Wire-format allocation. `null` in the JSON when the node hasn't been\nallocated yet — workers should treat that as \"single-host mode, do\nnot bring up the overlay\".","required":["node_id","compute_cidr","bridge_address","underlay_address"],"properties":{"bridge_address":{"type":"string"},"compute_cidr":{"type":"string"},"node_id":{"type":"string","description":"Stable v5 UUID derived from the database node id."},"underlay_address":{"type":"string"}}},"AnalyticsSessionEventsResponse":{"type":"object","required":["session_id","events","total_events"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/SessionEvent"}},"session_id":{"type":"string"},"total_events":{"type":"integer","minimum":0}}},"AnnotatedSpan":{"type":"object","description":"A single span annotated with the project that originally stored it.\nUsed in `UnifiedTrace` to let the UI colour-code spans by project.","required":["project_id","project_name","span"],"properties":{"project_id":{"type":"integer","format":"int32","description":"The project that stored this span (same as `span.project_id`)."},"project_name":{"type":"string","description":"Human-readable project name for waterfall colour-coding and legend."},"span":{"$ref":"#/components/schemas/SpanRecord","description":"Original span data verbatim from storage."}}},"AnomalyAlgorithm":{"type":"string","description":"Anomaly baseline algorithm. Adding one (e.g. a new robust variant) is a\ncode-only enum addition — no migration, since it lives inside the blob.","enum":["robust","basic","agile","ewma"]},"AnomalyParams":{"type":"object","description":"Seasonal anomaly-band detector parameters (stub — not yet evaluated).","properties":{"algorithm":{"$ref":"#/components/schemas/AnomalyAlgorithm","description":"Baseline model. `robust` is the default (seasonal, stable, flags level\nshifts); `ewma`/`agile` adopt level shifts; `basic` is non-seasonal."},"baseline_lookback_days":{"type":["integer","null"],"format":"int32","description":"How far back to build the baseline. `None` = an evaluator default."},"deviations":{"type":"number","format":"double","description":"Band width in robust standard deviations (Datadog's `bounds`)."},"direction":{"$ref":"#/components/schemas/Direction","description":"Which side(s) of the band a deviation must be on to count."},"pct_anomalous":{"type":"number","format":"double","description":"Fraction (0..=1) of points in the window that must be anomalous to fire."},"seasonality":{"$ref":"#/components/schemas/Seasonality","description":"Seasonality model for the baseline."}}},"AnomalyPreviewPointResponse":{"type":"object","required":["bucket","value","lower","upper","breaching"],"properties":{"breaching":{"type":"boolean"},"bucket":{"type":"string","example":"2025-10-12T12:15:47Z"},"lower":{"type":"number","format":"double","description":"Lower edge of the expected band at this point."},"upper":{"type":"number","format":"double","description":"Upper edge of the expected band at this point."},"value":{"type":"number","format":"double"}}},"AnomalyPreviewRequest":{"type":"object","required":["project_id","metric_name","aggregation","window_secs","detection_config"],"properties":{"aggregation":{"type":"string","description":"One of `avg|sum|min|max|count|rate|p50|p90|p95|p99`."},"detection_config":{"$ref":"#/components/schemas/DetectionConfig","description":"The detector to backtest. `static` and `anomaly` are supported — the\nkinds the evaluator actually runs."},"end_time":{"type":["string","null"],"description":"RFC 3339; defaults to now.","example":"2025-10-12T12:15:47Z"},"metric_name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"start_time":{"type":["string","null"],"description":"RFC 3339; defaults to 7 days before `end_time`.","example":"2025-10-12T12:15:47Z"},"window_secs":{"type":"integer","format":"int32"}}},"AnomalyPreviewResponse":{"type":"object","required":["points","breach_count","baseline_samples","sufficient"],"properties":{"baseline_samples":{"type":"integer","format":"int64","description":"Baseline sample count (drives the `sufficient` flag)."},"breach_count":{"type":"integer","format":"int64","description":"How many points in the range would have fired."},"points":{"type":"array","items":{"$ref":"#/components/schemas/AnomalyPreviewPointResponse"}},"sufficient":{"type":"boolean","description":"Whether the baseline had enough history for a trustworthy band."}}},"ApiKeyListResponse":{"type":"object","required":["api_keys","total"],"properties":{"api_keys":{"type":"array","items":{"$ref":"#/components/schemas/ApiKeyResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"ApiKeyResponse":{"type":"object","required":["id","name","key_prefix","role_type","is_active","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00Z"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"key_prefix":{"type":"string"},"last_used_at":{"type":["string","null"],"format":"date-time","example":"2024-01-01T00:00:00Z"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"}},"role_type":{"type":"string"}}},"AppSettings":{"type":"object","description":"Application settings stored in the database\nAll fields have sensible defaults for easy onboarding","properties":{"agent_sandbox":{"oneOf":[{"$ref":"#/components/schemas/AgentSandboxSettings"}],"default":{"default_provider":"claude_cli","providers":{},"auth_type":"subscription","api_key_encrypted":null,"enabled":true,"runtime":"node","custom_image":"","cpu_limit":4.0,"memory_limit_mb":8192,"network_mode":"full","sandbox_backend":null}},"ai_chat_limits":{"oneOf":[{"$ref":"#/components/schemas/AiChatLimitsSettings","description":"Limits on a single AI chat turn. Operator-tunable because the right\nvalue depends on the model: a turn against a slow self-hosted model can\nlegitimately take ten minutes, while a hosted one finishes in seconds\nand a shorter ceiling keeps costs predictable."}],"default":{"turn_timeout_secs":900}},"ai_config":{"oneOf":[{"$ref":"#/components/schemas/AiConfigSettings"}],"default":{"config_repo":"","config_repo_branch":"main"}},"build_limits":{"oneOf":[{"$ref":"#/components/schemas/BuildLimitsSettings","description":"Build-time resource limits applied on the control plane to prevent\n`docker build` from saturating host CPU/RAM. Worker nodes are\nintentionally NOT subject to these limits (each worker is dedicated\nhardware that already has its own per-host headroom)."}],"default":{"max_concurrent":2,"cpu_limit_cores":0.0,"memory_limit_mb":0}},"cluster_dns":{"oneOf":[{"$ref":"#/components/schemas/ClusterDnsSettings","description":"Cluster-DNS resolver settings (ADR-024, experimental beta). Off by\ndefault — see `ClusterDnsSettings` for the incident background and\ntrade-offs. Must be explicitly enabled by operators who need\n`*.temps.local` service-to-service resolution inside containers."}],"default":{"enabled":false}},"console_version":{"type":["string","null"],"description":"Binary version tag (e.g. \"v0.1.0\") of the *console* process\n(`temps serve`, role=all or role=console) that last started. Written\non console startup; read by the standalone `temps proxy` to detect\nversion skew during a rolling upgrade (ADR-017 Phase 3). `None` on\ninstalls that never ran a console build carrying this field.\n\nThis is informational state written by the binary itself — NOT an\noperator-tunable setting. It is intentionally absent from\n`AppSettingsResponse` and the PATCH path so an operator cannot\naccidentally overwrite the self-recorded value.","default":null},"container_logs":{"oneOf":[{"$ref":"#/components/schemas/ContainerLogSettings"}],"default":{"max_size":"50m","max_file":3,"service_max_size":"20m","service_max_file":3}},"disk_space_alert":{"oneOf":[{"$ref":"#/components/schemas/DiskSpaceAlertSettings"}],"default":{"enabled":true,"threshold_percent":80,"check_interval_seconds":300,"monitor_path":null}},"dns_provider":{"oneOf":[{"$ref":"#/components/schemas/DnsProviderSettings"}],"default":{"provider":"manual","cloudflare_api_key":null}},"docker_registry":{"oneOf":[{"$ref":"#/components/schemas/DockerRegistrySettings"}],"default":{"enabled":false,"registry_url":null,"username":null,"password":null,"tls_verify":true,"ca_certificate":null}},"edge_target":{"type":["string","null"],"description":"Public edge target that generated DNS records point at when a managed\ndomain opts into automatic record sync. An IPv4/IPv6 address produces an\n`A`/`AAAA` record; anything else is treated as a `CNAME` target. `None`\ndisables DNS record sync regardless of per-domain opt-in.","default":null},"external_url":{"type":["string","null"],"default":null},"insecure_tls":{"type":"boolean","description":"Skip TLS certificate verification on outbound HTTP clients built by the\nserver (deployer, agent, remote service client). Strictly opt-in for\noperators running self-signed control plane / worker certs on a trusted\ninternal network. Worker→control-plane traffic that traverses the public\ninternet must keep this `false` — otherwise a MitM steals the join token.","default":false},"internal_url":{"type":["string","null"],"description":"URL that service containers use to reach the Temps API from *inside*\nthe Docker network (OTLP metrics ingest, agent callbacks, etc.). On\nDocker Desktop this defaults to `http://host.docker.internal:`;\non Linux it requires the `host.docker.internal:host-gateway` host\nmapping (which Temps adds to provisioned containers). Distinct from\n`external_url`, which is the public-facing address.","default":null},"letsencrypt":{"oneOf":[{"$ref":"#/components/schemas/LetsEncryptSettings"}],"default":{"email":null,"environment":"production"}},"monitoring":{"oneOf":[{"$ref":"#/components/schemas/MonitoringSettings","description":"Metrics observability settings. Controls the MetricsStore backend,\nscrape interval, and tiered retention windows."}],"default":{"enabled":false,"store":"timescale_db","scrape_interval_secs":30,"retention_raw_days":7,"retention_hourly_days":90,"retention_daily_years":2,"clickhouse_url":null}},"multi_node":{"oneOf":[{"$ref":"#/components/schemas/MultiNodeSettings"}],"default":{"join_token_hash":null,"private_address":null,"legacy_shared_token_enabled":true,"cluster_ca_cert_pem":null,"cluster_ca_key_encrypted":null,"require_mtls":false,"node_cpu_alert_percent":90.0,"node_memory_alert_percent":90.0,"node_disk_alert_percent":90.0}},"observability_compression":{"oneOf":[{"$ref":"#/components/schemas/ObservabilityCompressionSettings","description":"TimescaleDB compression delays for immutable observability data.\nChanges are applied at runtime by the Settings API."}],"default":{"proxy_logs_after_hours":24,"otel_spans_after_hours":24}},"observability_retention":{"oneOf":[{"$ref":"#/components/schemas/ObservabilityRetentionSettings","description":"Retention windows for raw proxy and OpenTelemetry telemetry.\nTimescaleDB policies are updated at runtime by the Settings API."}],"default":{"proxy_logs_days":30,"otel_spans_days":90,"otel_logs_days":90,"otel_metrics_days":90}},"on_demand_tls":{"oneOf":[{"$ref":"#/components/schemas/OnDemandTlsSettings"}],"default":{"enabled":false,"zone":null,"max_concurrent":3,"hourly_cap":10,"deployment_url_mode":"http"}},"preview_domain":{"type":"string","default":"localho.st"},"preview_gateway":{"oneOf":[{"$ref":"#/components/schemas/PreviewGatewaySettings"}],"default":{"image":"ghcr.io/gotempsh/temps-preview-gateway:latest","host_port":8090,"auto_upgrade":true}},"rate_limiting":{"oneOf":[{"$ref":"#/components/schemas/RateLimitSettings"}],"default":{"enabled":false,"max_requests_per_minute":60,"max_requests_per_hour":1000,"whitelist_ips":[],"blacklist_ips":[]}},"require_mfa_for_admins":{"type":"boolean","description":"When `true`, any user holding the `Admin` role must have MFA enrolled\n(`users.mfa_enabled = true`) to complete a **password** login. Users\nwithout MFA enrolled are rejected with a typed error instructing them\nto enroll before retrying. This only gates the password-login path\n(`AuthService::login`) -- SSO/OIDC logins are handled by a separate\ncode path (`OidcService::resolve_user` + `oidc_handler`) and are\nintentionally unaffected, since federating identity to a\nproperly-hardened IdP is itself an acceptable alternative to local\nTOTP MFA. Modeled as a settings row (not an env var) per CLAUDE.md so\nan operator can flip it at runtime via the Settings API without\nrestarting the binary.","default":false},"screenshots":{"oneOf":[{"$ref":"#/components/schemas/ScreenshotSettings"}],"default":{"enabled":false,"provider":"local","url":""}},"security_headers":{"oneOf":[{"$ref":"#/components/schemas/SecurityHeadersSettings"}],"default":{"enabled":false,"preset":"moderate","content_security_policy":"default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'self'","x_frame_options":"SAMEORIGIN","x_content_type_options":"nosniff","x_xss_protection":"1; mode=block","strict_transport_security":"max-age=31536000; includeSubDomains","referrer_policy":"strict-origin-when-cross-origin","permissions_policy":"geolocation=(), microphone=(), camera=()"}},"setup_complete":{"type":"boolean","description":"Set to `true` by `temps setup` (all modes) once initial configuration\nhas been applied. The web onboarding wizard reads this from the server\nand skips itself when true, preventing the \"Configure Base Domain\" wall\nfrom appearing on installs that were already configured via the CLI.","default":false}}},"AppSettingsResponse":{"type":"object","description":"Safe response for application settings that masks sensitive fields","required":["preview_domain","screenshots","letsencrypt","dns_provider","security_headers","rate_limiting","docker_registry","disk_space_alert","container_logs","agent_sandbox","ai_config","preview_gateway","multi_node","monitoring","observability_compression","observability_retention","effective_metrics_store","effective_observability_store","insecure_tls","setup_complete","require_mfa_for_admins","cluster_dns","build_limits","ai_chat_limits"],"properties":{"agent_sandbox":{"$ref":"#/components/schemas/AgentSandboxSettingsMasked"},"ai_chat_limits":{"$ref":"#/components/schemas/AiChatLimitsSettings","description":"Per-turn limits for the AI chat. No sensitive content."},"ai_config":{"$ref":"#/components/schemas/AiConfigSettings"},"build_limits":{"$ref":"#/components/schemas/BuildLimitsSettings","description":"Build-time resource limits (control-plane only). No sensitive content,\npassed through as-is."},"cluster_dns":{"$ref":"#/components/schemas/ClusterDnsSettings","description":"Cluster-DNS resolver settings (ADR-024, experimental beta). No masking\nneeded — `enabled` is a plain bool with no sensitive content. Passed\nthrough as-is so the settings UI can read and toggle the flag."},"container_logs":{"$ref":"#/components/schemas/ContainerLogSettings"},"disk_space_alert":{"$ref":"#/components/schemas/DiskSpaceAlertSettings"},"dns_provider":{"$ref":"#/components/schemas/DnsProviderSettingsMasked"},"docker_registry":{"$ref":"#/components/schemas/DockerRegistrySettingsMasked"},"edge_target":{"type":["string","null"],"description":"Public edge target that synced DNS records point at (IP → A/AAAA, else CNAME)."},"effective_metrics_store":{"$ref":"#/components/schemas/MetricsStoreKind","description":"The storage backend the runtime is **actually** using for metrics,\nafter reconciling the `monitoring.store` toggle with the server's\n`TEMPS_CLICKHOUSE_*` configuration. When `monitoring.store` is\n`click_house` but those env vars are not fully set, the runtime falls\nback to TimescaleDB — in that case this reports `timescale_db` even\nthough `monitoring.store` says `click_house`. The UI shows this as the\neffective backend and warns when it diverges from the configured store."},"effective_observability_store":{"$ref":"#/components/schemas/MetricsStoreKind","description":"Storage backend actually used for proxy logs, OTel spans, and OTel\nmetrics. OTel logs remain TimescaleDB-backed. Unlike resource metrics,\nthese domains switch to ClickHouse whenever the server-level ClickHouse\nconnection is configured; they do not use the monitoring store toggle."},"external_url":{"type":["string","null"]},"insecure_tls":{"type":"boolean"},"internal_url":{"type":["string","null"]},"letsencrypt":{"$ref":"#/components/schemas/LetsEncryptSettings"},"monitored_services_count":{"type":["integer","null"],"format":"int64","description":"Number of enabled, running services the MetricsScraper currently\nincludes. Used for the lightweight storage estimate in the UI.","minimum":0},"monitoring":{"$ref":"#/components/schemas/MonitoringSettingsMasked"},"multi_node":{"$ref":"#/components/schemas/MultiNodeSettingsMasked"},"observability_compression":{"$ref":"#/components/schemas/ObservabilityCompressionSettings","description":"TimescaleDB compression delays for immutable proxy logs and OTel spans."},"observability_retention":{"$ref":"#/components/schemas/ObservabilityRetentionSettings","description":"Retention windows for raw proxy logs and OpenTelemetry data."},"preview_domain":{"type":"string"},"preview_gateway":{"$ref":"#/components/schemas/PreviewGatewaySettingsMasked"},"rate_limiting":{"$ref":"#/components/schemas/RateLimitSettings"},"require_mfa_for_admins":{"type":"boolean","description":"When enabled, Admin-role accounts without MFA enrolled are rejected\nat password login (bherila/temps#32). SSO/OIDC logins are unaffected."},"screenshots":{"$ref":"#/components/schemas/ScreenshotSettings"},"security_headers":{"$ref":"#/components/schemas/SecurityHeadersSettings"},"setup_complete":{"type":"boolean","description":"Whether `temps setup` has been run at least once. The web onboarding\nwizard checks this field on load and skips itself when true."}}},"ApplyHostnameModeRequest":{"type":"object","description":"Request to apply a hostname mode (recompute + optional DNS sync).","required":["mode"],"properties":{"mode":{"type":"string","description":"Target mode to apply: `\"standard\"` or `\"flat\"`."},"sync_dns":{"type":"boolean","description":"Also reconcile the provider's DNS zone for the affected hostnames."}}},"ArchiveFlagResponse":{"type":"object","required":["key"],"properties":{"archived_at":{"type":["string","null"]},"key":{"type":"string"}}},"ArchiveMode":{"type":"string","enum":["off","on","always","unknown"]},"AssignRoleRequest":{"type":"object","required":["user_id","role_type"],"properties":{"role_type":{"type":"string"},"user_id":{"type":"integer","format":"int32"}}},"AttachScheduleServicesRequest":{"type":"object","description":"Body for `POST /api/backups/schedules/{id}/services` — attach external\nservices to a backup schedule. Idempotent.","required":["service_ids"],"properties":{"service_ids":{"type":"array","items":{"type":"integer","format":"int32"},"description":"External service ids to attach. Duplicates are de-duplicated server-side."}}},"AttachScheduleServicesResponse":{"type":"object","description":"Response for `POST /api/backups/schedules/{id}/services`.","required":["inserted","total_attached"],"properties":{"inserted":{"type":"integer","format":"int64","description":"Number of rows actually inserted (excludes rows skipped by\n`ON CONFLICT DO NOTHING`).","minimum":0},"total_attached":{"type":"integer","description":"Total number of services now attached to the schedule.","minimum":0}}},"AuditLogIpInfo":{"type":"object","description":"IP address information in audit log","required":["ip"],"properties":{"city":{"type":["string","null"],"description":"City name","example":"San Francisco"},"country":{"type":["string","null"],"description":"Country code","example":"US"},"ip":{"type":"string","description":"IP address","example":"192.168.1.1"},"latitude":{"type":["number","null"],"format":"double","description":"Latitude","example":37.7749},"longitude":{"type":["number","null"],"format":"double","description":"Longitude","example":122.4194}}},"AuditLogResponse":{"type":"object","description":"Response type for audit log entries","required":["id","operation_type","audit_date"],"properties":{"audit_date":{"type":"integer","format":"int64","description":"When the action occurred","example":11932193},"data":{"description":"Additional context about the action"},"id":{"type":"integer","format":"int32","description":"Unique identifier for the audit log entry"},"ip_address":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AuditLogIpInfo","description":"IP address details"}]},"operation_type":{"type":"string","description":"The type of action that was performed","example":"USER_LOGIN"},"user":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AuditLogUserInfo","description":"User details who performed the action"}]},"user_id":{"type":["integer","null"],"format":"int32","description":"The user who performed the action (`null` when that account has\nsince been deleted; `data` retains the original actor context)"}}},"AuditLogUserInfo":{"type":"object","description":"User information in audit log","required":["id","name","email"],"properties":{"email":{"type":"string","description":"User's email","example":"john.doe@example.com"},"id":{"type":"integer","format":"int32","description":"User ID"},"name":{"type":"string","description":"User's name","example":"John Doe"}}},"AuthFlavorDto":{"type":"object","description":"One auth flavor surfaced to the UI. Mirrors `AuthFlavor` in the catalog\nbut without the seed-path / env-var fields the frontend doesn't need\n(those are server-side only — exposing them just bloats the response).","required":["id","label","description","format"],"properties":{"description":{"type":"string"},"env_var":{"type":["string","null"],"description":"For `api_key` format: the env var name that will be set inside the\nsandbox. Useful for showing the user \"we'll set OPENAI_API_KEY\" so\nthey know what their key controls."},"format":{"type":"string","description":"`api_key`, `oauth_token`, or `config_file` — drives which input UI\nthe settings page renders (single-line vs. multi-line textarea)."},"id":{"type":"string"},"label":{"type":"string"}}},"AuthResponse":{"type":"object","required":["success","message","mfa_required"],"properties":{"message":{"type":"string"},"mfa_required":{"type":"boolean"},"success":{"type":"boolean"},"user_id":{"type":["integer","null"],"format":"int32"}}},"AuthStatusResponse":{"type":"object","required":["status"],"properties":{"cli_token":{"type":["string","null"]},"status":{"type":"string"}}},"AuthTokenResponse":{"type":"object","required":["access_token","refresh_token","expires_at"],"properties":{"access_token":{"type":"string"},"expires_at":{"type":"integer","format":"int64"},"refresh_token":{"type":"string"}}},"AutoWatchParams":{"type":"object","description":"Auto-watch (Watchdog-style) detector parameters (stub — not evaluated).","properties":{"direction":{"$ref":"#/components/schemas/Direction","description":"The engine self-tunes the band; the user supplies only the direction."}}},"AutofixRunConfig":{"type":"object","description":"User-chosen per-run options, persisted as JSON in `agent_runs.run_config`.\nEvery field is optional — unset fields fall back to the provider defaults\nin settings, then to built-in defaults.","properties":{"branch":{"type":["string","null"],"description":"Branch to clone instead of the project's main branch.","default":null},"max_turns":{"type":["integer","null"],"format":"int32","description":"Per-run turn cap applied to every phase of this run. Only enforced\nfor CLIs with a turn flag (Claude Code); Codex/OpenCode run to\ncompletion. `None` uses the provider's per-phase defaults.","default":null},"model":{"type":["string","null"],"description":"Model id for the chosen provider. `None` uses the provider's saved\ndefault model, or the CLI's own default.","default":null},"provider":{"type":["string","null"],"description":"AI provider id (\"claude_cli\", \"codex_cli\", \"opencode\"). `None` uses\nthe platform default provider from agent sandbox settings.","default":null}}},"AutofixerRunResponse":{"type":"object","required":["id","project_id","status","tokens_input","tokens_output","files_changed","created_at"],"properties":{"ai_model":{"type":["string","null"]},"ai_output":{"type":["string","null"]},"ai_provider":{"type":["string","null"],"description":"AI provider slug this run executes with (e.g. claude_cli, codex_cli)."},"analysis":{"type":["string","null"]},"branch_name":{"type":["string","null"]},"completed_at":{"type":["string","null"]},"created_at":{"type":"string"},"error_message":{"type":["string","null"]},"files_changed":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"phase":{"type":["string","null"]},"pr_number":{"type":["integer","null"],"format":"int32"},"pr_url":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"run_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AutofixRunConfig","description":"Per-run options the run was started with; used to prefill the\nretry / start-over dialog."}]},"started_at":{"type":["string","null"]},"status":{"type":"string"},"tokens_input":{"type":"integer","format":"int32"},"tokens_output":{"type":"integer","format":"int32"},"trigger_source_id":{"type":["integer","null"],"format":"int32"},"user_context":{"type":["string","null"]}}},"AutofixerRunWithLogsResponse":{"type":"object","required":["run","logs"],"properties":{"logs":{"type":"array","items":{"$ref":"#/components/schemas/AgentRunLogResponse"}},"run":{"$ref":"#/components/schemas/AutofixerRunResponse"}}},"AvailableContainerInfo":{"type":"object","description":"Available Docker container that can be imported as a service","required":["container_id","container_name","image","version","service_type","is_running"],"properties":{"container_id":{"type":"string","description":"Container ID or name","example":"abc123def456"},"container_name":{"type":"string","description":"Container display name","example":"my-postgres"},"exposed_ports":{"type":"array","items":{"type":"integer","format":"int32","minimum":0},"description":"Exposed ports (e.g., [5432] for PostgreSQL, [6379] for Redis)"},"image":{"type":"string","description":"Docker image name (e.g., \"gotempsh/postgres-walg:18-bookworm\")","example":"gotempsh/postgres-walg:18-bookworm"},"is_running":{"type":"boolean","description":"Whether the container is currently running","example":true},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute","description":"Service type this container represents"},"version":{"type":"string","description":"Extracted version from image","example":"18"}}},"AvailablePermissions":{"type":"object","description":"Response containing all available permissions for frontend validation","required":["permissions","roles"],"properties":{"permissions":{"type":"array","items":{"$ref":"#/components/schemas/PermissionInfo"},"description":"All available permissions in the system"},"roles":{"type":"array","items":{"$ref":"#/components/schemas/RoleInfo"},"description":"All available roles"}}},"BackupAlertListResponse":{"type":"object","description":"Response body for the list-backup-alerts endpoint.","required":["alerts"],"properties":{"alerts":{"type":"array","items":{"$ref":"#/components/schemas/BackupAlertResponse"},"description":"All currently open (unresolved) alerts, newest first."}}},"BackupAlertResponse":{"type":"object","description":"A single open backup alert surfaced in the UI banner.\n\nAlerts are auto-opened by the watcher and auto-resolved when the triggering\ncondition clears. No manual dismiss is required or supported.\n\nThe optional `schedule_s3_source_id` field is included so the UI can\ndeep-link an `overdue_schedule` alert to the S3 source detail page that\nhosts the schedule. `stalled_job` alerts no longer carry a deep-link\ntarget — the alert message text contains the backup id for display.","required":["id","kind","severity","message","opened_at"],"properties":{"id":{"type":"integer","format":"int64","description":"Database id of the alert row."},"kind":{"type":"string","description":"`\"overdue_schedule\"` or `\"stalled_job\"`."},"message":{"type":"string","description":"Human-readable description of the alert condition."},"opened_at":{"type":"string","description":"RFC 3339 timestamp when the alert was opened.","example":"2026-05-15T10:00:00Z"},"schedule_id":{"type":["integer","null"],"format":"int32","description":"FK to `backup_schedules.id`. Set for `overdue_schedule` alerts."},"schedule_name":{"type":["string","null"],"description":"Human-readable name of the linked schedule, if applicable."},"schedule_s3_source_id":{"type":["integer","null"],"format":"int32","description":"FK to `backup_schedules.s3_source_id`. The UI uses this to deep-link\nthe alert to the S3 source detail page that hosts the schedule.\nSet for `overdue_schedule` alerts."},"severity":{"type":"string","description":"`\"warning\"` or `\"critical\"`."}}},"BackupResponse":{"type":"object","description":"Response type for backup","required":["id","name","backup_id","backup_type","state","started_at","s3_source_id","s3_location","metadata","compression_type","created_by","tags"],"properties":{"attempts":{"type":["integer","null"],"format":"int32","description":"How many times this job has been claimed and run. `null` for legacy\nbackups with no `backup_jobs` row."},"backup_id":{"type":"string"},"backup_type":{"type":"string"},"checksum":{"type":["string","null"]},"completed_at":{"type":["integer","null"],"format":"int64"},"compression_type":{"type":"string"},"created_by":{"type":"integer","format":"int32"},"current_step":{"type":["string","null"],"description":"Name of the engine step currently executing (e.g., `\"walg_push\"`).\n`null` when no `backup_jobs` row exists for this backup (legacy rows\npre-dating ADR-014), or when the job has not yet completed its first step."},"error_message":{"type":["string","null"]},"expires_at":{"type":["integer","null"],"format":"int64"},"external_service":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ExternalServiceSummary","description":"External service that owns this backup (Redis, Postgres, etc.).\n`null` for control-plane backups (the Temps server's own database)."}]},"file_count":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"live_size_bytes":{"type":["integer","null"],"format":"int64","description":"Best-effort partial size while a backup is still running, computed\nby listing the S3 prefix. Null when the backup is finished\n(`size_bytes` is authoritative in that case)."},"max_attempts":{"type":["integer","null"],"format":"int32","description":"Maximum attempts before the job is permanently failed. `null` for\nlegacy backups."},"max_runtime_secs":{"type":["integer","null"],"format":"int64","description":"Resolved wall-clock timeout for this backup job (seconds). `null` for\nlegacy backups. Derived from the three-tier resolution order:\ncaller override → schedule override → engine default."},"metadata":{},"name":{"type":"string"},"s3_location":{"type":"string"},"s3_source_id":{"type":"integer","format":"int32"},"schedule_id":{"type":["integer","null"],"format":"int32"},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Final size of the backup once completed. Null while running."},"started_at":{"type":"integer","format":"int64"},"state":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}}}},"BackupScheduleResponse":{"type":"object","description":"Response type for backup schedule","required":["id","name","backup_type","retention_period","s3_source_id","schedule_expression","enabled","created_at","updated_at","tags","target_all_services","include_control_plane"],"properties":{"backup_type":{"type":"string"},"created_at":{"type":"integer","format":"int64"},"description":{"type":["string","null"]},"enabled":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"include_control_plane":{"type":"boolean","description":"When `true`, every run also produces a `control_plane` backup\n(Temps's own Postgres). When `false`, only the external service\nfan-out happens."},"last_run":{"type":["integer","null"],"format":"int64"},"max_runtime_secs":{"type":["integer","null"],"format":"int64","description":"Per-schedule wall-clock timeout override for backup jobs (seconds).\n`null` means the engine-family default is used. See\n`temps_backup_core::timeouts::default_max_runtime_secs`."},"name":{"type":"string"},"next_run":{"type":["integer","null"],"format":"int64"},"retention_period":{"type":"integer","format":"int32"},"s3_source_id":{"type":"integer","format":"int32"},"schedule_expression":{"type":"string","example":"0 0 * * *"},"tags":{"type":"array","items":{"type":"string"}},"target_all_services":{"type":"boolean","description":"When `true`, the schedule auto-includes every external service on\nthe host (and any future ones). When `false`, the schedule only\ntargets services attached via `backup_schedule_services`."},"updated_at":{"type":"integer","format":"int64"}}},"BitbucketAuthInput":{"oneOf":[{"type":"object","description":"Personal / Workspace / Repository Access Token.","required":["token","type"],"properties":{"token":{"type":"string","description":"The Bitbucket access token value."},"type":{"type":"string","enum":["access_token"]}}},{"type":"object","description":"HTTP Basic / App Password authentication.","required":["username","password","type"],"properties":{"password":{"type":"string","description":"App password generated in Bitbucket security settings."},"type":{"type":"string","enum":["app_password"]},"username":{"type":"string","description":"Bitbucket account username."}}}],"description":"Authentication input for a Bitbucket Cloud provider. Use `access_token` for\na Repository or Workspace Access Token (PAT), or `username` + `app_password`\nfor App Password (HTTP Basic) authentication."},"BlobResponse":{"type":"object","description":"Response after uploading a blob","required":["url","pathname","contentType","size","uploadedAt"],"properties":{"contentType":{"type":"string","description":"Content type of the blob","example":"image/png"},"pathname":{"type":"string","description":"Original pathname","example":"images/avatar-abc123.png"},"size":{"type":"integer","format":"int64","description":"Size in bytes","example":12345},"uploadedAt":{"type":"string","format":"date-time","description":"Upload timestamp","example":"2025-01-03T12:00:00Z"},"url":{"type":"string","description":"URL path to access the blob","example":"/api/blob/123/images/avatar-abc123.png"}}},"BlobStatusResponse":{"type":"object","description":"Response for Blob service status","required":["enabled","healthy"],"properties":{"docker_image":{"type":["string","null"],"description":"Docker image being used","example":"ghcr.io/rustfs/rustfs:0.5.0"},"enabled":{"type":"boolean","description":"Whether the Blob service is enabled","example":true},"healthy":{"type":"boolean","description":"Whether the service is healthy","example":true},"version":{"type":["string","null"],"description":"Current version (if running)","example":"0.5.0"}}},"BranchInfo":{"type":"object","required":["name","commit_sha","protected"],"properties":{"commit_sha":{"type":"string"},"name":{"type":"string"},"protected":{"type":"boolean"}}},"BranchListResponse":{"type":"object","required":["branches"],"properties":{"branches":{"type":"array","items":{"$ref":"#/components/schemas/BranchInfo"}}}},"BrowserCount":{"type":"object","required":["browser","count","percentage"],"properties":{"browser":{"type":"string"},"count":{"type":"integer","format":"int64"},"percentage":{"type":"number","format":"double"}}},"BrowsersQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"BuildConfiguration":{"type":"object","description":"Build configuration (for building images from source)","required":["context","args"],"properties":{"args":{"type":"object","description":"Build arguments","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"context":{"type":"string","description":"Build context (Dockerfile path or buildpack)"},"dockerfile":{"type":["string","null"],"description":"Dockerfile path (relative to context)"},"target":{"type":["string","null"],"description":"Target stage (for multi-stage builds)"}}},"BuildLimitsSettings":{"type":"object","description":"Control-plane build resource limits.\n\nCaps how many builds run concurrently AND how much CPU/memory each build\nis allowed to consume. A single global semaphore in the deployer crate\ngates every `DockerRuntime::build_image` call to `max_concurrent`. When\nthe semaphore is full, additional builds queue and wait — they do not\nfail. Per-build CPU/memory caps are forwarded to Docker via\n`BuildImageOptions { memory, cpuquota, cpuperiod }`.\n\n`cpu_limit_cores = 0.0` or `memory_limit_mb = 0` means \"no explicit cap\"\n— fall back to the legacy 50%-of-host heuristic for backwards\ncompatibility with operators who never visit the settings page.","properties":{"cpu_limit_cores":{"type":"number","format":"float","description":"CPU cores allowed per build (float, e.g. 2.0 = 2 cores, 0.5 = half\na core). 0 means \"use the legacy 50%-of-host default\".","default":0.0,"example":2.0,"minimum":0},"max_concurrent":{"type":"integer","format":"int32","description":"Maximum number of `docker build` operations allowed to run at the\nsame time on the control plane. Additional builds queue. Min 1.","default":2,"example":2,"minimum":1},"memory_limit_mb":{"type":"integer","format":"int32","description":"Memory allowed per build, in megabytes. 0 means \"use the legacy\n50%-of-host default\". Docker enforces this as a hard cap — builds\nthat exceed it OOM-kill.","default":0,"example":2048,"minimum":0}}},"CancelBackupResponse":{"type":"object","description":"Response body for cancel endpoints.","required":["cancelled"],"properties":{"cancelled":{"type":"integer","format":"int64","description":"Number of rows that were actually flipped to `failed`. `0` is a valid\nsuccess and means the backup was already terminal — the call is\nidempotent.","minimum":0}}},"CertStatusResponse":{"type":"object","description":"Current on-demand cert status for a single hostname (ADR-018 §5). Backs\n`GET /domains/by-host/{hostname}/cert-status`.","required":["hostname"],"properties":{"backoff_until":{"type":["integer","null"],"format":"int64","description":"On-demand negative-cache deadline (epoch millis), when in backoff."},"hostname":{"type":"string","description":"SNI hostname."},"last_attempt":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/OnDemandCertAttemptResponse","description":"The most recent on-demand issuance attempt for this hostname, if any."}]},"status":{"type":["string","null"],"description":"Current cert lifecycle status from the `domains` row, when one exists."}}},"ChallengeConfig":{"type":"object","description":"Challenge configuration (future feature)\nFor CAPTCHA, JS challenges, proof-of-work, etc.","required":["challengeType","difficulty"],"properties":{"challengeType":{"type":"string","description":"Challenge type: \"captcha\", \"js_challenge\", \"proof_of_work\""},"difficulty":{"type":"integer","format":"int32","description":"Challenge difficulty level (1-10)","minimum":0},"protectedPaths":{"type":"array","items":{"type":"string"},"description":"Paths that require challenges"}}},"ChallengeError":{"type":"object","required":["type","detail","status"],"properties":{"detail":{"type":"string","description":"Human-readable error description"},"status":{"type":"integer","format":"int32","description":"HTTP status code"},"type":{"type":"string","description":"Error type (e.g., \"urn:ietf:params:acme:error:unauthorized\")"}}},"ChallengeValidationStatus":{"type":"object","required":["type","url","status","token"],"properties":{"error":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ChallengeError","description":"Error details if validation failed"}]},"status":{"type":"string","description":"Challenge status (e.g., \"pending\", \"valid\", \"invalid\")"},"token":{"type":"string","description":"Challenge token"},"type":{"type":"string","description":"Challenge type (e.g., \"dns-01\", \"http-01\")"},"url":{"type":"string","description":"Challenge validation URL"},"validated":{"type":["string","null"],"description":"When the challenge was validated (if successful)"}}},"ChangePasswordRequest":{"type":"object","required":["current_password","new_password"],"properties":{"current_password":{"type":"string","example":"current_password_value"},"mfa_code":{"type":["string","null"],"description":"TOTP code (or recovery code). Required iff the user has MFA enabled.","example":"123456"},"new_password":{"type":"string","example":"new_password_value"},"revoke_other_sessions":{"type":"boolean","description":"When true, every session OTHER than the one making this request is\nrevoked. Defaults to false; the UI surfaces this as a checkbox."}}},"ChangeProjectSourceRequest":{"type":"object","description":"Change a project's source type to a Git-less type (docker_image /\nstatic_files / manual). Switching TO `git` is done via the Git settings\nendpoint (which also supplies the repository + provider connection).","required":["source_type"],"properties":{"source_type":{"$ref":"#/components/schemas/SourceType"}}},"ChatCompletionChoice":{"type":"object","required":["index","message"],"properties":{"finish_reason":{"type":["string","null"]},"index":{"type":"integer","format":"int32"},"message":{"$ref":"#/components/schemas/ChatMessage"}}},"ChatCompletionRequest":{"allOf":[{"type":["object","null"],"description":"Tolerates extra SDK fields (stream_options, logprobs, etc.)","additionalProperties":{},"propertyNames":{"type":"string"}},{"type":"object","required":["model","messages"],"properties":{"frequency_penalty":{"type":["number","null"],"format":"double"},"max_tokens":{"type":["integer","null"],"format":"int64"},"messages":{"type":"array","items":{"$ref":"#/components/schemas/ChatMessage"}},"model":{"type":"string"},"n":{"type":["integer","null"],"format":"int32"},"presence_penalty":{"type":["number","null"],"format":"double"},"response_format":{},"seed":{"type":["integer","null"],"format":"int64"},"stop":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/StopSequence"}]},"stream":{"type":"boolean"},"temperature":{"type":["number","null"],"format":"double"},"tool_choice":{},"tools":{"type":["array","null"],"items":{}},"top_p":{"type":["number","null"],"format":"double"},"user":{"type":["string","null"]}}}],"description":"OpenAI-compatible chat completion request.\nUses `deny_unknown_fields = false` (serde default) so that SDK-specific\nfields like `stream_options`, `logprobs`, `top_logprobs`, `logit_bias`,\n`parallel_tool_calls`, etc. are silently accepted without breaking."},"ChatCompletionResponse":{"type":"object","required":["id","object","created","model","choices"],"properties":{"choices":{"type":"array","items":{"$ref":"#/components/schemas/ChatCompletionChoice"}},"created":{"type":"integer","format":"int64"},"id":{"type":"string"},"model":{"type":"string"},"object":{"type":"string"},"usage":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/UsageInfo"}]}}},"ChatMessage":{"type":"object","required":["role"],"properties":{"content":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MessageContent"}]},"name":{"type":["string","null"]},"role":{"type":"string"},"tool_call_id":{"type":["string","null"]},"tool_calls":{"type":["array","null"],"items":{}}}},"ChatReadinessResponse":{"type":"object","description":"What still has to be true before an AI chat can run a turn in this project.\n\nThe three gates are independent and fail for different reasons with different\nfixes, so they are reported separately rather than collapsed into one boolean:\nan instance admin configures a provider (instance-wide), while the two toggles\nare per-project. Collapsing them would leave the user with \"AI unavailable\"\nand no idea which of three places to go.","required":["ai_configured","chat_enabled","write_actions_enabled"],"properties":{"ai_configured":{"type":"boolean","description":"An AI provider is configured on this instance. Fixed in\nSettings → AI Providers; instance-wide, not per project."},"chat_enabled":{"type":"boolean","description":"The per-project read-only chat toggle is on (the default)."},"write_actions_enabled":{"type":"boolean","description":"The per-project write-actions opt-in is on. Required for any flow where\nthe assistant *proposes* changes; irrelevant for read-only questions."}}},"ChildBackupEntryResponse":{"type":"object","description":"A single child backup entry in the `GET /backups/{id}/children` response.\n\nEach entry corresponds to one `external_service_backups` row joined with\n`external_services`, providing service metadata without a second request.","required":["id","service_id","service_name","service_type","state","backup_type","started_at","s3_location","compression_type"],"properties":{"backup_type":{"type":"string","description":"Backup variant (e.g. \"full\", \"incremental\")."},"compression_type":{"type":"string","description":"Compression algorithm used (e.g. \"gzip\", \"lz4\")."},"error_message":{"type":["string","null"],"description":"Engine-reported error message when `state = \"failed\"`."},"finished_at":{"type":["string","null"],"description":"When the child backup finished, if known.","example":"2025-01-15T14:35:00.456Z"},"id":{"type":"integer","format":"int32","description":"Row ID from `external_service_backups`."},"s3_location":{"type":"string","description":"Object key or `s3://` URL where the backup data lives."},"service_id":{"type":"integer","format":"int32","description":"FK to `external_services.id`."},"service_name":{"type":"string","description":"Human-readable name of the external service (e.g. \"redis-prod\")."},"service_type":{"type":"string","description":"Service type string (e.g. \"postgres\", \"redis\", \"mongodb\", \"s3\").","example":"postgres"},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size of the child backup in bytes, if available."},"started_at":{"type":"string","description":"When the child backup started (RFC 3339).","example":"2025-01-15T14:30:00.123Z"},"state":{"type":"string","description":"Current state: \"pending\" | \"running\" | \"completed\" | \"failed\"."}}},"ChildBackupListResponse":{"type":"object","description":"Response body for `GET /backups/{id}/children`.\n\nReturns an empty `children` list (not 404) when the parent backup has no\nchild records (e.g. control-plane backups).","required":["children"],"properties":{"children":{"type":"array","items":{"$ref":"#/components/schemas/ChildBackupEntryResponse"},"description":"Zero or more child backup entries ordered by `external_service_backups.id` ASC."}}},"CleanupExpiredBackupsRequest":{"type":"object","properties":{"expected_backup_ids":{"type":["array","null"],"items":{"type":"string"},"description":"Exact candidates returned by the dry run. Execution fails if the\nretention selection has changed since preview."}}},"CliDeviceApproveRequest":{"type":"object","required":["user_code"],"properties":{"user_code":{"type":"string"}}},"CliDeviceApproveResponse":{"type":"object","required":["user_code","status"],"properties":{"status":{"type":"string"},"user_code":{"type":"string"}}},"CliDeviceLookupResponse":{"type":"object","required":["user_code","status","expires_at"],"properties":{"client_name":{"type":["string","null"]},"expires_at":{"type":"string","format":"date-time"},"requested_ip":{"type":["string","null"]},"status":{"type":"string","description":"`pending` | `approved` | `denied` | `expired`."},"user_code":{"type":"string"}}},"CliDevicePollRequest":{"type":"object","required":["device_code"],"properties":{"device_code":{"type":"string"}}},"CliDevicePollResponse":{"oneOf":[{"type":"object","description":"Still waiting on the user to approve in the browser.","required":["status"],"properties":{"status":{"type":"string","enum":["authorization_pending"]}}},{"type":"object","description":"CLI is polling faster than the server-suggested interval.","required":["status"],"properties":{"status":{"type":"string","enum":["slow_down"]}}},{"type":"object","description":"User denied the request in the browser.","required":["status"],"properties":{"status":{"type":"string","enum":["access_denied"]}}},{"type":"object","description":"The session has expired without approval.","required":["status"],"properties":{"status":{"type":"string","enum":["expired_token"]}}},{"type":"object","description":"The session was approved; this is the only response that carries\nthe API key. The key is returned exactly once and then cleared\nfrom the session row.","required":["user_id","email","role","api_key","key_prefix","status"],"properties":{"api_key":{"type":"string"},"email":{"type":"string"},"expires_at":{"type":["string","null"],"format":"date-time"},"key_prefix":{"type":"string"},"role":{"type":"string"},"status":{"type":"string","enum":["approved"]},"user_id":{"type":"integer","format":"int32"}}}]},"CliDeviceStartRequest":{"type":"object","properties":{"client_name":{"type":["string","null"],"description":"Friendly hostname / client identifier shown in the browser approval\nscreen. Sanitized before display.","example":"dviejo-mac.local"}}},"CliDeviceStartResponse":{"type":"object","required":["device_code","user_code","verification_uri","verification_uri_complete","expires_in","interval"],"properties":{"device_code":{"type":"string","description":"Opaque secret the CLI polls with. Never display to a human."},"expires_in":{"type":"integer","format":"int64","description":"Seconds until the device_code expires."},"interval":{"type":"integer","format":"int64","description":"Suggested polling interval, in seconds."},"user_code":{"type":"string","description":"Short human-readable code the user types into the browser.","example":"ABCD-1234"},"verification_uri":{"type":"string","description":"Base verification URL — the CLI may display this when the\npre-filled URL is too long to be useful.","example":"https://temps.example.com/cli-login"},"verification_uri_complete":{"type":"string","description":"`verification_uri` with `user_code` pre-filled. Open this directly.","example":"https://temps.example.com/cli-login/ABCD-1234"}}},"CliLoginRequest":{"type":"object","required":["username","password"],"properties":{"password":{"type":"string"},"username":{"type":"string"}}},"CloudProvider":{"type":"string","description":"Cloud provider detected from node metadata","enum":["aws","gcp","azure","hetzner","digitalocean","other"]},"CloudflareConfig":{"type":"object","description":"Configuration for a Cloudflare Email Sending notification provider.\n\nNotifications are delivered through Cloudflare's transactional Email Sending\nAPI. Only the account, token, sender and recipients are configured here —\nsubject and body are derived from each notification.","required":["account_id","api_token","from_address","to_addresses"],"properties":{"account_id":{"type":"string","description":"Cloudflare account id that owns the Email Sending configuration.","example":"023e105f4ecef8ad9ca31a8372d0c353"},"api_token":{"type":"string","description":"Cloudflare API token with the Email Sending permission. Encrypted at\nrest and masked in normal API responses."},"from_address":{"type":"string","description":"Verified sender address (must belong to a domain enabled for Cloudflare\nEmail Sending).","example":"welcome@infracf.example.com"},"from_name":{"type":["string","null"],"description":"Optional human-friendly sender name shown in the recipient's inbox."},"to_addresses":{"type":"array","items":{"type":"string"},"description":"Recipients that should receive the notification."}}},"ClusterCapacity":{"type":"object","description":"Total cluster capacity (sum of node allocatable resources)","required":["node_count","cpu_millis","memory_mb"],"properties":{"cpu_millis":{"type":"integer","format":"int64","description":"Total allocatable CPU in millicores"},"memory_mb":{"type":"integer","format":"int64","description":"Total allocatable memory in MB"},"node_count":{"type":"integer","description":"Number of nodes","minimum":0}}},"ClusterDnsSettings":{"type":"object","description":"Cluster-DNS resolver settings (ADR-024, experimental beta).\n\nWhen `enabled`, the Temps control plane starts a Hickory DNS resolver and\ninjects it as the first nameserver into every deployed container via\n`HostConfig.Dns` — giving containers the ability to resolve `*.temps.local`\nFQDNs for service-to-service communication. Worker nodes pick this flag up\nfrom the `/api/internal/nodes/{id}/network/peers` wire response and gate\ntheir own per-node resolver the same way.\n\n**Default: `false` (disabled).**\n\nWhy disabled by default: a production incident showed that when the injected\nHickory resolver was slow or transiently unresponsive for a non-`*.temps.local`\n(external) hostname, glibc's resolver cycled through all three nameservers\n(`172.20.0.1`, `1.1.1.1`, `8.8.8.8`) at ~5 s timeout × 2 attempts each,\ncausing 22–27 s delays for outbound TCP connections. Disabling the injection\nrestores Docker's embedded DNS as the sole resolver, eliminating that failure\nmode. Operators running single/multi-node installs that depend on\n`*.temps.local` resolution must explicitly opt in by setting `enabled: true`.\n\n`bool` defaults to `false` in Rust and JSON (`#[serde(default)]`), so the\nsafe-off behaviour is automatic for new installs and legacy settings rows.","properties":{"enabled":{"type":"boolean","description":"Master switch. When `false` (default), no custom DNS is injected into\ncontainers — they use Docker's embedded DNS which forwards to the host's\nown `resolv.conf`. When `true`, the control-plane Hickory resolver is\nstarted and its bridge IP is injected as the first nameserver so\n`*.temps.local` FQDNs resolve inside containers.","default":false,"example":false}}},"ClusterHealthReportResponse":{"type":"object","description":"Response body for `GET /external-services/{id}/cluster-health`.","required":["checked_at","monitor_response_ms","members"],"properties":{"checked_at":{"type":"string","description":"ISO-8601 wall-clock when the report was generated.","example":"2025-10-12T12:15:47.609192Z"},"members":{"type":"array","items":{"$ref":"#/components/schemas/ClusterMemberHealthResponse"}},"monitor_error":{"type":["string","null"],"description":"Set when the monitor itself was unreachable. UI shows a banner."},"monitor_response_ms":{"type":"integer","format":"int64","description":"Round-trip to query the monitor (ms)."}}},"ClusterMemberHealthResponse":{"type":"object","description":"One row in the cluster Members table — see `GET /external-services/{id}/cluster-health`.","required":["nodename","nodehost","nodeport","reported_state","goal_state","health","seconds_since_report","candidate_priority","replication_quorum"],"properties":{"candidate_priority":{"type":"integer","format":"int32"},"goal_state":{"type":"string","description":"What the monitor *wants* the node to be. Differs from\n`reported_state` mid-transition (failover, demotion, etc.)."},"health":{"type":"integer","format":"int32","description":"pg_auto_failover liveness signal: `1` healthy, `0` unknown\n(no recent report), `-1` unhealthy."},"nodehost":{"type":"string"},"nodename":{"type":"string"},"nodeport":{"type":"integer","format":"int32"},"replay_lag_ms":{"type":["integer","null"],"format":"int64","description":"`replay_lag` from `pg_stat_replication`, in milliseconds."},"replication_quorum":{"type":"boolean"},"reported_state":{"type":"string","description":"What the node *last told the monitor* it was. Stale during outages."},"seconds_since_report":{"type":"integer","format":"int64","description":"Wall-clock seconds since the node last reported in."},"sync_state":{"type":["string","null"],"description":"`sync` / `quorum` / `async` for secondaries; `null` for the primary."}}},"ClusterMemberRequest":{"type":"object","description":"Request spec for a single cluster member.","required":["role"],"properties":{"node_id":{"type":["integer","null"],"format":"int32","description":"Target worker node ID. Omit or null to run on the control plane."},"role":{"type":"string","description":"Service-type-specific role (e.g., \"monitor\", \"primary\", \"replica\")","example":"primary"}}},"CmdBody":{"type":"object","required":["command"],"properties":{"args":{"type":"array","items":{"type":"string"},"description":"Arguments to pass to the binary. Defaults to empty."},"command":{"type":"string","description":"Binary name (argv[0]) — e.g. `\"ls\"`, `\"node\"`. The SDK sends this\nseparately from `args`."},"cwd":{"type":["string","null"],"description":"Working directory override."},"env":{"type":"object","description":"Extra env vars.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"sudo":{"type":"boolean","description":"When true, the SDK runs the command privileged. We ignore it today\n— the underlying provider always runs as the sandbox's own user."},"wait":{"type":"boolean","description":"When true, the response is an `application/x-ndjson` stream where\nthe first line is the running-command envelope and the second line\nis the finished-command envelope with `exitCode`."}}},"CmdInner":{"type":"object","description":"Inner `command` object — matches the SDK's zod validator exactly.\n`exitCode` is `null` until the command terminates; `startedAt` is Unix\nepoch milliseconds.","required":["id","name","args","cwd","sandboxId","startedAt"],"properties":{"args":{"type":"array","items":{"type":"string"}},"cwd":{"type":"string"},"exitCode":{"type":["integer","null"],"format":"int32"},"id":{"type":"string"},"name":{"type":"string"},"sandboxId":{"type":"string"},"startedAt":{"type":"integer","format":"int64"}}},"CmdKillBody":{"type":"object","description":"SDK-shaped kill body. The SDK sends `{signal: AbortSignal}` but only\nuses the signal for HTTP request abortion client-side; there's no\nsignal name on the wire.","properties":{"force":{"type":"boolean","description":"Optional: when true, SIGKILL instead of SIGTERM."}}},"CmdResponse":{"type":"object","description":"`@vercel/sandbox` envelope: `{ command: {...} }`.","required":["command"],"properties":{"command":{"$ref":"#/components/schemas/CmdInner"}}},"CommitExistsResponse":{"type":"object","required":["exists"],"properties":{"commit":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/CommitInfo","description":"Commit metadata when the requested SHA exists."}]},"commit_sha":{"type":["string","null"]},"exists":{"type":"boolean"}}},"CommitInfo":{"type":"object","required":["sha","message","author","author_email","date"],"properties":{"author":{"type":"string","description":"Author name"},"author_email":{"type":"string","description":"Author email"},"date":{"type":"string","format":"date-time","description":"Commit date in ISO 8601 format","example":"2025-10-12T12:15:47.609192Z"},"message":{"type":"string","description":"Commit message"},"sha":{"type":"string","description":"Commit SHA hash"}}},"CommitListResponse":{"type":"object","required":["commits"],"properties":{"commits":{"type":"array","items":{"$ref":"#/components/schemas/CommitInfo"}}}},"Comparator":{"type":"string","description":"Comparator for static/forecast threshold detectors. Serializes to the\nkeyword forms `gt|gte|lt|lte` (NOT the SQL operators used by\n`temps-monitoring::compare`).","enum":["gt","gte","lt","lte"]},"ComposePublicPort":{"type":"object","description":"A port that should be exposed publicly through the proxy for a compose service.","required":["service","port"],"properties":{"port":{"type":"integer","format":"int32","description":"Container port to expose (e.g. 8123)","minimum":0},"service":{"type":"string","description":"Compose service name (e.g. \"web\", \"clickhouse\")"}}},"ConnectionListQuery":{"type":"object","properties":{"direction":{"type":["string","null"]},"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0},"sort":{"type":["string","null"]}}},"ConnectionListResponse":{"type":"object","required":["connections","total_count","page","per_page"],"properties":{"connections":{"type":"array","items":{"$ref":"#/components/schemas/ConnectionResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"per_page":{"type":"integer","format":"int64","minimum":0},"total_count":{"type":"integer","minimum":0}}},"ConnectionResponse":{"type":"object","required":["id","provider_id","account_name","account_type","is_active","is_expired","syncing","synced_repository_count","health_status","consecutive_health_failures","created_at","updated_at"],"properties":{"account_name":{"type":"string"},"account_type":{"type":"string"},"consecutive_health_failures":{"type":"integer","format":"int32"},"created_at":{"type":"string","format":"date-time"},"health_message":{"type":["string","null"],"description":"Human-readable reason when health_status is \"unhealthy\"; null otherwise."},"health_status":{"type":"string","description":"Current health status: \"healthy\", \"unhealthy\", or \"unknown\"."},"id":{"type":"integer","format":"int32"},"installation_id":{"type":["string","null"]},"is_active":{"type":"boolean"},"is_expired":{"type":"boolean"},"last_health_check_at":{"type":["string","null"],"format":"date-time"},"last_synced_at":{"type":["string","null"],"format":"date-time"},"provider_id":{"type":"integer","format":"int32"},"synced_repository_count":{"type":"integer","format":"int32","description":"Running count of repositories persisted by the current (or most\nrecent) sync. Resets to 0 when a new sync begins; useful for showing\nlive progress on large syncs."},"syncing":{"type":"boolean"},"updated_at":{"type":"string","format":"date-time"},"user_id":{"type":["integer","null"],"format":"int32"}}},"ConnectionTestResult":{"type":"object","description":"Connection test result","required":["success","message"],"properties":{"message":{"type":"string"},"success":{"type":"boolean"}}},"ConsoleEventPayload":{"type":"object","description":"Payload for server-side event ingestion via the console API.\n\nThe app backend reads the encrypted `_temps_visitor_id` and `_temps_sid`\ncookie values from the user's request and forwards them here.\nTemps decrypts them server-side to resolve visitor/session identity.","required":["event_name","environment_id","deployment_id"],"properties":{"deployment_id":{"type":"integer","format":"int32","description":"Deployment ID to attribute the event to"},"environment_id":{"type":"integer","format":"int32","description":"Environment ID to attribute the event to"},"event_data":{"description":"Arbitrary JSON event data"},"event_name":{"type":"string","description":"Event name (e.g. \"purchase\", \"signup\", custom event names)"},"request_path":{"type":"string","description":"Page path context (defaults to \"/\")"},"request_query":{"type":"string","description":"Query string context"},"session_id":{"type":["string","null"],"description":"Encrypted `_temps_sid` cookie value from the user's browser"},"visitor_id":{"type":["string","null"],"description":"Encrypted `_temps_visitor_id` cookie value from the user's browser"}}},"ContainerActionResponse":{"type":"object","description":"Response indicating success of container state change","required":["container_id","container_name","action","status","message"],"properties":{"action":{"type":"string"},"container_id":{"type":"string"},"container_name":{"type":"string"},"message":{"type":"string"},"status":{"type":"string"}}},"ContainerDetailResponse":{"type":"object","description":"Detailed container information with environment variables and metrics","required":["id","container_id","container_name","image_name","status","deployment_id","created_at","deployed_at","container_port","environment_variables"],"properties":{"container_id":{"type":"string"},"container_name":{"type":"string"},"container_port":{"type":"integer","format":"int32","description":"Port inside the container"},"cpu_limit_cores":{"type":["number","null"],"format":"double","description":"CPU limit in whole cores (e.g. 1.0). None when no limit is configured."},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"deployed_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"deployment_id":{"type":"integer","format":"int32"},"environment_variables":{"type":"array","items":{"$ref":"#/components/schemas/EnvVarResponse"},"description":"Environment variables (sensitive values masked)"},"error_message":{"type":["string","null"],"description":"Free-form error string from Docker's container state on exit."},"exit_code":{"type":["integer","null"],"format":"int32","description":"Process exit code reported by Docker. None while still running."},"exit_reason":{"type":["string","null"],"description":"Human-readable reason the container exited."},"finished_at":{"type":["string","null"],"description":"When the container exited (Docker's FinishedAt). None while running.","example":"2025-10-12T12:16:47.609192Z"},"host_port":{"type":["integer","null"],"format":"int32","description":"Port on the host machine"},"id":{"type":"integer","format":"int32"},"image_name":{"type":"string"},"oom_killed":{"type":["boolean","null"],"description":"True when Docker's OOM killer terminated the container."},"ready_at":{"type":["string","null"],"example":"2025-10-12T12:16:47.609192Z"},"resource_limits":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ResourceLimitsResponse","description":"Resource limits"}]},"restart_count":{"type":["integer","null"],"format":"int64","description":"Container restart count from Docker"},"service_name":{"type":["string","null"],"description":"Compose service name (e.g. \"web\", \"redis\"). None for single-container deployments."},"service_url":{"type":["string","null"],"description":"Per-service URL for compose deployments"},"started_at":{"type":["string","null"],"description":"When the container's main process most recently started.","example":"2025-10-12T12:15:50.000000Z"},"status":{"type":"string"}}},"ContainerEnvironmentVariableValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"ContainerInfoResponse":{"type":"object","required":["container_id","container_name","image_name","status","created_at"],"properties":{"container_id":{"type":"string"},"container_name":{"type":"string"},"cpu_limit_cores":{"type":["number","null"],"format":"double","description":"CPU limit in whole cores (e.g. 1.0). None when no limit is configured."},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"error_message":{"type":["string","null"],"description":"Free-form error string from Docker's container state on exit."},"exit_code":{"type":["integer","null"],"format":"int32","description":"Process exit code reported by Docker. None while still running."},"exit_reason":{"type":["string","null"],"description":"Human-readable reason the container exited (e.g. \"OOMKilled\",\n\"Killed by SIGKILL (exit code 137)\", \"Exit code 1\"). None while running."},"finished_at":{"type":["string","null"],"description":"When the container exited (Docker's FinishedAt). None while running.","example":"2025-10-12T12:16:47.609192Z"},"image_name":{"type":"string"},"node_name":{"type":["string","null"],"description":"Node name where this container is running. None for local (single-node) deployments."},"oom_killed":{"type":["boolean","null"],"description":"True when Docker's OOM killer terminated the container."},"restart_count":{"type":["integer","null"],"format":"int64","description":"Container restart count from Docker. The UI shows a chip when this is\n> 0 so a crash loop is visible without opening detail."},"service_name":{"type":["string","null"],"description":"Compose service name (e.g. \"web\", \"redis\"). None for single-container deployments."},"service_url":{"type":["string","null"],"description":"Per-service URL for compose deployments (e.g. \"https://web-myapp.localho.st\")"},"started_at":{"type":["string","null"],"description":"When the container's main process most recently started. The UI uses\nthis for the uptime label so the count resets when a container is\nrestarted in place. None for containers that never started.","example":"2025-10-12T12:15:50.000000Z"},"status":{"type":"string"}}},"ContainerInventoryItem":{"type":"object","description":"A container reported by the agent during heartbeat reconciliation.","required":["container_id","container_name"],"properties":{"container_id":{"type":"string","description":"Docker container ID"},"container_name":{"type":"string","description":"Docker container name"}}},"ContainerListResponse":{"type":"object","required":["containers","total"],"properties":{"containers":{"type":"array","items":{"$ref":"#/components/schemas/ContainerInfoResponse"}},"total":{"type":"integer","minimum":0}}},"ContainerLogSettings":{"type":"object","description":"Docker container log rotation settings\nControls the `--log-opt max-size` and `--log-opt max-file` for containers","properties":{"max_file":{"type":"integer","format":"int32","description":"Maximum number of rotated log files to keep (e.g., 3 means up to 3 x max_size total)","default":3,"example":3,"minimum":0},"max_size":{"type":"string","description":"Maximum size of each log file (e.g., \"50m\", \"100m\", \"1g\")\nDocker default is unlimited; we default to \"50m\" to prevent disk exhaustion","default":"50m","example":"50m"},"service_max_file":{"type":"integer","format":"int32","description":"Maximum rotated log files for external service containers","default":3,"example":3,"minimum":0},"service_max_size":{"type":"string","description":"Maximum size for external service container logs (postgres, redis, etc.)\nDefaults to \"20m\" since services are typically less verbose than app containers","default":"20m","example":"20m"}}},"ContainerLogsQuery":{"type":"object","properties":{"container_name":{"type":["string","null"],"description":"Optional container name to get logs from (if deployment has multiple containers)"},"end_date":{"type":["integer","null"],"format":"int64"},"follow":{"type":"boolean","description":"Follow log output in real-time (default: true for backward compatibility)"},"start_date":{"type":["integer","null"],"format":"int64"},"tail":{"type":["string","null"]},"timestamps":{"type":"boolean","description":"Include timestamps in log output (default: false)"}}},"ContainerMetricHistoryPoint":{"type":"object","description":"One bucketed data point of a container resource metric time series.","required":["time","value"],"properties":{"time":{"type":"string","description":"Bucket timestamp (ISO 8601 with `Z` suffix).","example":"2025-10-12T12:15:00+00:00"},"value":{"type":"number","format":"double","description":"Averaged metric value for the bucket."}}},"ContainerMetricsHistoryQuery":{"type":"object","description":"Query parameters for the container metrics history endpoint.","required":["metric"],"properties":{"metric":{"type":"string","description":"Dotted metric name, e.g. `container.cpu_percent` or\n`container.memory_used_bytes`."},"range":{"type":"string","description":"Time window: `1h`, `6h`, `24h`, or `7d` (defaults to `1h`)."}}},"ContainerMetricsResponse":{"type":"object","description":"Container resource metrics (CPU, memory usage)","required":["container_id","container_name","cpu_percent","memory_bytes","network_rx_bytes","network_tx_bytes","timestamp"],"properties":{"container_id":{"type":"string"},"container_name":{"type":"string"},"cpu_limit_cores":{"type":["number","null"],"format":"double","description":"CPU limit in whole cores (e.g. 1.0). None = no limit."},"cpu_percent":{"type":"number","format":"double","description":"CPU usage as a multi-core percentage (Docker convention: 200 = 2 cores\nfully pinned). Divide by 100 to get cores used."},"memory_bytes":{"type":"integer","format":"int64","description":"Memory usage in bytes","minimum":0},"memory_limit_bytes":{"type":["integer","null"],"format":"int64","description":"Memory limit in bytes (if set)","minimum":0},"memory_percent":{"type":["number","null"],"format":"double","description":"Memory usage percentage (0-100) if limit is set"},"network_rx_bytes":{"type":"integer","format":"int64","description":"Network bytes received","minimum":0},"network_tx_bytes":{"type":"integer","format":"int64","description":"Network bytes transmitted","minimum":0},"timestamp":{"type":"string","description":"Timestamp of metrics collection","example":"2025-10-12T12:15:47.609192Z"}}},"ContainerResponse":{"type":"object","required":["name","container_type","can_contain_containers","can_contain_entities","metadata"],"properties":{"can_contain_containers":{"type":"boolean","description":"Can this container hold other containers?","example":true},"can_contain_entities":{"type":"boolean","description":"Can this container hold entities (tables, collections, etc.)?","example":false},"child_container_type":{"type":["string","null"],"description":"Type of child containers (if can_contain_containers is true)","example":"schema"},"container_type":{"type":"string","description":"Container type (database, schema, keyspace, bucket, etc.)","example":"database"},"entity_count_hint":{"type":["string","null"],"description":"Hint for UI on expected entity count (small = sidebar, large = pagination)","example":"large"},"entity_type_label":{"type":["string","null"],"description":"Label for entity type (if can_contain_entities is true)","example":"table"},"metadata":{"description":"Additional metadata"},"name":{"type":"string","description":"Container name","example":"mydb"}}},"ContainerRuntimeInfo":{"type":"object","description":"Snapshot of a container's lifecycle state from `docker inspect`.\n`restart_count` and `oom_killed` are the load-bearing fields when\ndiagnosing crash loops — the kernel OOM killer never reaches the\napplication's logs, so seeing `oom_killed=true` is the only signal\nthat a memory limit was the cause.","required":["role","container_name","resource_limits"],"properties":{"container_id":{"type":["string","null"],"description":"Container Docker id, when present. None = container does not exist\n(was never created or was removed externally)."},"container_name":{"type":"string","description":"Stable name of the Docker container (e.g. `postgres-mydb`)."},"exit_code":{"type":["integer","null"],"format":"int64","description":"Last container exit code, when known. Non-zero = unclean stop."},"finished_at":{"type":["string","null"],"description":"ISO-8601 timestamp of the most recent termination, when known."},"image":{"type":["string","null"],"description":"Currently-effective Docker image (e.g. `gotempsh/postgres-walg:18-bookworm`)."},"oom_killed":{"type":["boolean","null"],"description":"True when the container's last termination was caused by the\nkernel OOM killer. Set if the user enabled hard memory limits\nand the working set exceeded them."},"resource_limits":{"$ref":"#/components/schemas/ServiceResourceLimits","description":"Currently-applied resource limits read off the container's\n`HostConfig`. Compare this against the user-configured limits to\ndetect drift (an old container that never picked up new caps)."},"restart_count":{"type":["integer","null"],"format":"int64","description":"Total restarts since the container was created. Useful for\ndetecting crash loops — a steady stream means something is killing\nthe container repeatedly (frequently OOM)."},"role":{"type":"string","description":"`service_members.role` for cluster members; \"standalone\" otherwise."},"started_at":{"type":["string","null"],"description":"ISO-8601 timestamp of when the container last started. None when\nit has never started (i.e. created but never run)."},"status":{"type":["string","null"],"description":"Bollard container state (\"running\", \"exited\", \"dead\", etc.). None\nwhen the container does not exist."}}},"ContainerStatsSample":{"type":"object","description":"Live resource usage sample for a single container.\n\n`cpu_percent` is computed by Docker's standard formula:\n ((cpu_delta / system_delta) * online_cpus) * 100\n`memory_percent` is `(memory_usage / memory_limit) * 100` — when no\nmemory limit is set the limit reported by Docker is the host's total\nRAM, so a 5% reading means \"5% of host RAM\", not \"5% of allocated\".","required":["role","container_name"],"properties":{"container_name":{"type":"string"},"cpu_percent":{"type":["number","null"],"format":"double","description":"CPU usage as a percentage. `None` when the container is not running\n(Docker returns no usable counters)."},"memory_limit_bytes":{"type":["integer","null"],"format":"int64","description":"Memory limit in bytes (host RAM if no limit set).","minimum":0},"memory_percent":{"type":["number","null"],"format":"double","description":"Memory usage as a percentage of `memory_limit_bytes`."},"memory_usage_bytes":{"type":["integer","null"],"format":"int64","description":"Resident memory usage in bytes.","minimum":0},"online_cpus":{"type":["integer","null"],"format":"int32","description":"Number of cores Docker observed at sample time. Used by the UI\nto label \"x/y cores\" instead of just a percent.","minimum":0},"role":{"type":"string"}}},"ContentPart":{"type":"object","required":["type"],"properties":{"image_url":{},"text":{"type":["string","null"]},"type":{"type":"string"}}},"ContextLine":{"type":"object","description":"A line in context response","required":["timestamp","level","message","line_offset","is_match"],"properties":{"fields":{},"is_match":{"type":"boolean","description":"Whether this line matched the original search"},"level":{"$ref":"#/components/schemas/LogLevel"},"line_offset":{"type":"integer","format":"int32"},"message":{"type":"string"},"timestamp":{"type":"string"}}},"ContextLogsRequest":{"type":"object","required":["chunk_id","line_offset"],"properties":{"chunk_id":{"type":"string"},"line_offset":{"type":"integer","format":"int32"},"lines":{"type":["integer","null"],"format":"int32","description":"Number of context lines before and after (default: 25)","minimum":0}}},"ContextLogsResponse":{"type":"object","required":["lines","target_index"],"properties":{"lines":{"type":"array","items":{"$ref":"#/components/schemas/ContextLine"}},"target_index":{"type":"integer","minimum":0}}},"ConversationDetailResponse":{"allOf":[{"$ref":"#/components/schemas/ConversationResponse"},{"type":"object","required":["messages"],"properties":{"messages":{"type":"array","items":{"$ref":"#/components/schemas/MessageResponse"},"description":"Turns oldest-first. The `system` seed message is omitted (internal)."}}}]},"ConversationResponse":{"type":"object","required":["public_id","context_type","context_id","status","created_at","last_activity_at"],"properties":{"context_id":{"type":"string"},"context_type":{"type":"string"},"created_at":{"type":"string"},"last_activity_at":{"type":"string"},"public_id":{"type":"string"},"status":{"type":"string"},"title":{"type":["string","null"]}}},"ConversationSummary":{"type":"object","description":"A conversation summary grouping related AI invocations.","required":["conversation_id","message_count","total_input_tokens","total_output_tokens","total_tokens","total_cost_microcents","avg_latency_ms","models_used","first_at","last_at"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"conversation_id":{"type":"string"},"first_at":{"type":"string"},"last_at":{"type":"string"},"message_count":{"type":"integer","format":"int64"},"models_used":{"type":"array","items":{"type":"string"}},"total_cost_microcents":{"type":"integer","format":"int64"},"total_input_tokens":{"type":"integer","format":"int64"},"total_output_tokens":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"ConversationsQueryParams":{"type":"object","properties":{"from":{"type":["string","null"],"description":"ISO 8601 start time (defaults to 24h ago)"},"limit":{"type":["integer","null"],"format":"int64","description":"Max results (defaults to 50, max 100)","minimum":0},"model":{"type":["string","null"],"description":"Filter by model name"},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"to":{"type":["string","null"],"description":"ISO 8601 end time (defaults to now)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"CopyBlobRequest":{"type":"object","description":"Request to copy a blob","required":["fromUrl","toPathname"],"properties":{"fromUrl":{"type":"string","description":"Source blob URL or pathname","example":"/api/blob/10/images/avatar.png"},"projectId":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1},"toPathname":{"type":"string","description":"Destination pathname","example":"images/avatar-copy.png"}}},"CostAnalysis":{"type":"object","description":"Full cluster cost + rightsizing analysis attached to an import plan.","required":["nodes","capacity","requested","usage_source","overprovisioning","recommendation","notes"],"properties":{"actual_usage":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ResourceFootprint","description":"Measured usage from the metrics API (`metrics.k8s.io`).\n`None` when metrics-server is not installed."}]},"capacity":{"$ref":"#/components/schemas/ClusterCapacity","description":"Total cluster capacity (sum of node allocatable resources)"},"control_plane_monthly_usd":{"type":["number","null"],"format":"double","description":"Managed control-plane fee included in `current_monthly_usd` (EKS/GKE\ncharge ~$73/mo per cluster). `None` when not applicable/unknown."},"current_monthly_usd":{"type":["number","null"],"format":"double","description":"Estimated total infrastructure cost per month in USD (compute nodes +\ncontrol-plane fee). `None` when no node could be priced."},"nodes":{"type":"array","items":{"$ref":"#/components/schemas/NodeCostInfo"},"description":"Per-node inventory with price estimates where the instance type is known"},"notes":{"type":"array","items":{"type":"string"},"description":"Honesty notes: what could not be measured, which numbers are\nestimates, and any assumptions made. Always shown to the user."},"overprovisioning":{"$ref":"#/components/schemas/OverprovisioningAssessment","description":"Requests-vs-capacity-vs-usage assessment"},"provider":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/CloudProvider","description":"Detected cloud provider (from node `providerID` prefixes)"}]},"recommendation":{"$ref":"#/components/schemas/TargetRecommendation","description":"The temps/Hetzner target sizing and savings estimate"},"requested":{"$ref":"#/components/schemas/ResourceFootprint","description":"Sum of pod resource *requests* across running pods — what the\nscheduler has reserved, i.e. what the cluster is sized for."},"usage_source":{"$ref":"#/components/schemas/UsageSource","description":"How the usage numbers were obtained (drives UI wording)"}}},"CreateAlertRuleRequest":{"type":"object","required":["name","trigger_type"],"properties":{"cooldown_minutes":{"type":"integer","format":"int32","description":"Minimum minutes between notifications for same rule+group"},"enabled":{"type":"boolean"},"environment_filter":{"type":["integer","null"],"format":"int32","description":"Optional environment ID to filter alerts"},"error_level_filter":{"type":["string","null"],"description":"Optional error type/level filter"},"name":{"type":"string"},"notification_priority":{"type":"string","description":"Notification priority: Low, Normal, High, Critical"},"trigger_config":{"description":"Trigger-specific configuration (e.g., {\"count\": 100, \"window_minutes\": 60} for frequency)"},"trigger_type":{"type":"string","description":"Trigger type: new_issue, regression, frequency, new_user, user_count, status_change"}}},"CreateApiKeyRequest":{"type":"object","required":["name","role_type"],"properties":{"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"},"example":["projects:read","deployments:read"]},"role_type":{"type":"string","example":"admin"}}},"CreateApiKeyResponse":{"type":"object","required":["id","name","key_prefix","role_type","api_key","created_at"],"properties":{"api_key":{"type":"string"},"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00Z"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"id":{"type":"integer","format":"int32"},"key_prefix":{"type":"string"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"}},"role_type":{"type":"string"}}},"CreateBackupScheduleRequest":{"type":"object","required":["name","backup_type","retention_period","schedule_expression","enabled","tags"],"properties":{"backup_type":{"type":"string"},"description":{"type":["string","null"]},"enabled":{"type":"boolean"},"include_control_plane":{"type":["boolean","null"],"description":"When `true` (default), every run also produces a `control_plane`\nbackup of Temps's own database. Operators who use Temps purely as\na backup orchestrator for external DBs can set this to `false` to\nkeep the run history focused on those services."},"max_runtime_secs":{"type":["integer","null"],"format":"int64","description":"Optional wall-clock timeout override for jobs created by this schedule\n(seconds). When set, overrides the engine-family default. `null` means\n\"use engine default.\" The per-job `max_runtime_secs` in\n`EnqueueJobParams` can still override this for ad-hoc triggers."},"name":{"type":"string"},"retention_period":{"type":"integer","format":"int32"},"s3_source_id":{"type":["integer","null"],"format":"int32","description":"Optional S3 source. If omitted, the current default S3 source is used."},"schedule_expression":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"target_all_services":{"type":["boolean","null"],"description":"When `true` (default), the schedule backs up every external service\non the host — including databases created in the future. When\n`false`, the schedule backs up only the services explicitly attached\nvia `POST /backups/schedules/{id}/services`. Omit to use the default."}}},"CreateBitbucketRequest":{"type":"object","required":["name","auth"],"properties":{"auth":{"$ref":"#/components/schemas/BitbucketAuthInput","description":"Authentication credentials — either an access token or an app password."},"name":{"type":"string","description":"Display name for this provider."}}},"CreateCloudflareProviderRequest":{"type":"object","required":["name","config"],"properties":{"config":{"$ref":"#/components/schemas/CloudflareConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":"string"}}},"CreateConversationRequest":{"type":"object","required":["context_type","context_id"],"properties":{"context_id":{"type":"string","description":"The entity id (ints stringified)."},"context_type":{"type":"string","description":"e.g. `\"deployment\"`."}}},"CreateDSNRequest":{"type":"object","properties":{"base_url":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"name":{"type":["string","null"]}}},"CreateDashboardRequest":{"type":"object","required":["project_id","name","layout"],"properties":{"layout":{"$ref":"#/components/schemas/DashboardLayout"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"}}},"CreateDeploymentTokenRequest":{"type":"object","required":["name"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment ID - if set, token is scoped to a specific deployment"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment ID - if not set, token applies to all environments"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"},"description":"List of permissions (e.g., [\"visitors:enrich\", \"emails:send\"])\nIf not provided, defaults to full access","example":["visitors:enrich","emails:send"]}}},"CreateDeploymentTokenResponse":{"type":"object","required":["id","project_id","name","token_prefix","token","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00Z"},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"}},"project_id":{"type":"integer","format":"int32"},"token":{"type":"string","description":"The full token value - only returned on creation"},"token_prefix":{"type":"string"}}},"CreateDnsProviderRequest":{"type":"object","description":"Request to create a new DNS provider","required":["name","provider_type","credentials"],"properties":{"credentials":{"$ref":"#/components/schemas/DnsProviderCredentials","description":"Provider credentials"},"description":{"type":["string","null"],"description":"Optional description"},"name":{"type":"string","description":"User-friendly name","example":"My Cloudflare"},"provider_type":{"$ref":"#/components/schemas/DnsProviderType","description":"Provider type"}}},"CreateDomainRequest":{"type":"object","required":["domain"],"properties":{"challenge_type":{"type":"string","description":"Challenge type for Let's Encrypt validation. Options: \"http-01\" (default) or \"dns-01\""},"domain":{"type":"string"}}},"CreateEmailDomainRequest":{"type":"object","required":["provider_id","domain"],"properties":{"domain":{"type":"string","description":"Domain name (e.g., \"updates.example.com\")","example":"updates.example.com"},"provider_id":{"type":"integer","format":"int32","description":"Provider ID to use for this domain"}}},"CreateEmailProviderRequest":{"type":"object","required":["name","provider_type","region"],"properties":{"name":{"type":"string","description":"User-friendly name for the provider","example":"My AWS SES"},"provider_type":{"$ref":"#/components/schemas/EmailProviderTypeRoute","description":"Provider type"},"region":{"type":"string","description":"Cloud region. For SMTP this is informational only — the host/port carry the real routing.","example":"us-east-1"},"scaleway_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ScalewayCredentialsRequest","description":"Scaleway credentials (required if provider_type is scaleway)"}]},"ses_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SesCredentialsRequest","description":"AWS SES credentials (required if provider_type is ses)"}]},"smtp_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SmtpCredentialsRequest","description":"Generic SMTP credentials (required if provider_type is smtp). Use when\nyou only have SMTP creds and want to import an already-set-up domain."}]},"sns_topic_arn":{"type":["string","null"],"description":"Exact SNS topic allowed to deliver SES events for this provider."}}},"CreateEnvironmentRequest":{"type":"object","required":["name","branch"],"properties":{"branch":{"type":"string"},"name":{"type":"string"},"set_as_preview":{"type":"boolean","description":"If true, set this environment as the preview environment for the project"}}},"CreateEnvironmentVariableRequest":{"type":"object","required":["key","value","environment_ids"],"properties":{"environment_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"include_in_preview":{"type":"boolean","description":"Include this environment variable in preview environments (default: true)"},"is_secret":{"type":"boolean","description":"When true the variable is treated as write-only: never returned in\nplaintext from the API, masked in the UI, and updates that omit the\nvalue preserve the existing ciphertext. The flag is one-way — secret\nvars cannot be demoted back to regular vars."},"key":{"type":"string"},"value":{"type":"string"}}},"CreateExternalServiceRequest":{"type":"object","required":["name","service_type","parameters"],"properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/ClusterMemberRequest"},"description":"Cluster member specifications. Required when topology is \"cluster\"."},"name":{"type":"string"},"node_id":{"type":["integer","null"],"format":"int32","description":"Target node ID for the service. Omit or null to run on the control plane."},"parameters":{"type":"object","additionalProperties":{},"propertyNames":{"type":"string"}},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute"},"topology":{"type":"string","description":"Service topology: \"standalone\" (default) or \"cluster\" (HA multi-member).","example":"standalone"},"version":{"type":["string","null"]}}},"CreateFlagRequest":{"type":"object","required":["key","value_type","default_value"],"properties":{"client_visible":{"type":"boolean","description":"Whether the flag may be exposed on the unauthenticated same-origin\nevaluation endpoint. Defaults to `false`: flags are server-only unless\nexplicitly opted in, because targeting rules can encode business logic."},"default_value":{"description":"Served whenever evaluation cannot do better. Must match `value_type`.\n\nLeft unannotated so utoipa emits a free-form schema: a bool flag's\ndefault is `false`, not an object, and `value_type = Object` would tell\nevery generated client otherwise."},"description":{"type":["string","null"]},"key":{"type":"string","description":"Stable key used in application code. Immutable after create.","example":"checkout.v2"},"value_type":{"$ref":"#/components/schemas/FlagValueType","description":"Fixed at create: retyping would invalidate every stored value and every\ncall site."}}},"CreateFunnelRequest":{"type":"object","required":["name","steps"],"properties":{"description":{"type":["string","null"]},"name":{"type":"string"},"steps":{"type":"array","items":{"$ref":"#/components/schemas/CreateFunnelStep"}}}},"CreateFunnelResponse":{"type":"object","required":["funnel_id","message"],"properties":{"funnel_id":{"type":"integer","format":"int32"},"message":{"type":"string"}}},"CreateFunnelStep":{"type":"object","required":["event_name"],"properties":{"event_filter":{"type":"array","items":{"$ref":"#/components/schemas/SmartFilter"}},"event_name":{"type":"string"}}},"CreateGenericRequest":{"type":"object","required":["name","clone_url"],"properties":{"base_url":{"type":["string","null"],"description":"Optional base URL of the git host for display purposes (no API is called)."},"clone_url":{"type":"string","description":"HTTPS clone URL for the repository, e.g. `https://git.example.com/org/repo.git`."},"name":{"type":"string","description":"Display name for this provider."},"token":{"type":["string","null"],"description":"Access token or password. Omit (or set to `null`) for public repositories."},"token_username":{"type":["string","null"],"description":"HTTP Basic username used with the token. Defaults to `x-access-token` when\nabsent or empty. Ignored for public (unauthenticated) repositories."}}},"CreateGitHubPATRequest":{"type":"object","required":["name","token"],"properties":{"name":{"type":"string"},"token":{"type":"string"}}},"CreateGitLabOAuthRequest":{"type":"object","required":["name","client_id","client_secret","redirect_uri"],"properties":{"base_url":{"type":["string","null"]},"client_id":{"type":"string"},"client_secret":{"type":"string"},"name":{"type":"string"},"redirect_uri":{"type":"string"}}},"CreateGitLabPATRequest":{"type":"object","required":["name","token"],"properties":{"base_url":{"type":["string","null"]},"name":{"type":"string"},"token":{"type":"string"}}},"CreateGiteaPATRequest":{"type":"object","required":["name","token","base_url"],"properties":{"base_url":{"type":"string","description":"HTTPS base URL of the Gitea instance, e.g. `https://git.example.com`."},"name":{"type":"string","description":"Display name for this provider."},"token":{"type":"string","description":"Personal access token issued by the Gitea instance."}}},"CreateIncidentRequest":{"type":"object","required":["title","severity"],"properties":{"description":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"monitor_id":{"type":["integer","null"],"format":"int32"},"severity":{"type":"string"},"title":{"type":"string"}}},"CreateIntegrationBody":{"type":"object","required":["provider","signing_secret"],"properties":{"provider":{"type":"string","description":"Registered provider name, e.g. \"stripe\"."},"signing_secret":{"type":"string","description":"Signing secret from the provider's dashboard."}}},"CreateIpAccessControlRequest":{"type":"object","description":"Request to create an IP access control rule","required":["ip_address","action"],"properties":{"action":{"type":"string","description":"Action to take: \"block\" or \"allow\"","example":"block"},"ip_address":{"type":"string","description":"IP address in CIDR notation (e.g., \"192.168.1.1\" or \"10.0.0.0/24\")","example":"192.168.1.100"},"reason":{"type":["string","null"],"description":"Optional reason for the action","example":"Malicious activity detected"}}},"CreateMcpRequest":{"type":"object","required":["slug","name","config"],"properties":{"config":{"type":"object"},"description":{"type":["string","null"]},"name":{"type":"string"},"slug":{"type":"string"}}},"CreateMetricAlertRequest":{"type":"object","required":["project_id","name","metric_name","aggregation","detection_config","window_secs","for_duration_secs","severity","enabled"],"properties":{"aggregation":{"type":"string","description":"One of `avg|sum|min|max|count|rate|p50|p90|p95|p99`."},"detection_config":{"$ref":"#/components/schemas/DetectionConfig","description":"The detector: a discriminated union keyed by `kind`. Today only\n`{ \"kind\": \"static\", \"comparator\": \"gt\", \"threshold\": 500 }` is evaluable."},"dynamic_alerts":{"type":"boolean","description":"When true (and `group_by` is set) fire one independent alarm per breaching\nseries. Static detectors only. Default false."},"enabled":{"type":"boolean"},"for_duration_secs":{"type":"integer","format":"int32"},"group_by":{"type":"array","items":{"type":"string"},"description":"Label keys to break the metric down by, e.g. `[\"endpoint\",\"region\"]`. Empty\n(the default) = one aggregate stream. Max 2 keys; keys must match\n`[a-zA-Z0-9_.:-]`."},"grouped_notification_threshold":{"type":"integer","format":"int32","description":"When more than this many series transition to firing in the same tick, only\nthe first gets the expensive chart/AI enrichment. Range 1–1000, default 5."},"label_filters":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"AND-combined label equality filters: `[[\"key\",\"value\"],…]`. Empty = no\nfiltering (the default). Max 10 pairs; keys must match `[a-zA-Z0-9_.:-]`;\nvalues capped at 500 characters."},"max_series":{"type":"integer","format":"int32","description":"Cardinality cap for dynamic alerting: at most this many series (top by\n`|value|`). Range 1–100, default 20."},"metric_name":{"type":"string"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"severity":{"type":"string","description":"One of `info|warning|critical`."},"window_secs":{"type":"integer","format":"int32"}}},"CreateMonitorRequest":{"type":"object","required":["name","monitor_type","environment_id"],"properties":{"check_interval_seconds":{"type":["integer","null"],"format":"int32"},"check_path":{"type":["string","null"]},"environment_id":{"type":"integer","format":"int32"},"monitor_type":{"type":"string"},"name":{"type":"string"}}},"CreateNotificationEmailProviderRequest":{"type":"object","required":["name","config"],"properties":{"config":{"$ref":"#/components/schemas/EmailConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":"string"}}},"CreateOidcProviderRequest":{"type":"object","required":["name","issuer_url","client_id","client_secret"],"properties":{"client_id":{"type":"string"},"client_secret":{"type":"string"},"default_role":{"type":"string"},"enabled":{"type":"boolean"},"group_claim":{"type":"string"},"issuer_url":{"type":"string"},"jit_provisioning":{"type":"boolean"},"name":{"type":"string"},"role_claim":{"type":"string"},"scopes":{"type":"string"},"template":{"type":"string"},"trust_idp_email":{"type":"boolean","description":"Defaults false. Set to true only for IdPs where an admin\ncontrols user provisioning (corporate Okta, Azure AD) and\nself-signup of arbitrary emails is not possible — see the\n`trust_idp_email` field on `oidc_providers::Model` for the\nsecurity tradeoff this enables."}}},"CreateOidcRoleMappingRequest":{"type":"object","required":["priority","idp_group","role"],"properties":{"idp_group":{"type":"string"},"priority":{"type":"integer","format":"int32"},"role":{"type":"string"}}},"CreatePlanRequest":{"type":"object","description":"Request to create an import plan","required":["source","workload_id"],"properties":{"credentials":{"$ref":"#/components/schemas/ImportCredentials","description":"Platform credentials (required for cloud platforms like Vercel, Railway)"},"repository_id":{"type":["integer","null"],"format":"int32","description":"Optional repository ID to associate with the import\nIf provided, preset will be detected from the repository"},"source":{"$ref":"#/components/schemas/ImportSource","description":"Source to import from"},"workload_id":{"$ref":"#/components/schemas/WorkloadId","description":"Workload ID to import"}}},"CreatePlanResponse":{"type":"object","description":"Response with created plan","required":["session_id","plan","validation","can_execute"],"properties":{"can_execute":{"type":"boolean","description":"Whether the plan can be executed"},"plan":{"$ref":"#/components/schemas/ImportPlan","description":"Generated import plan"},"session_id":{"type":"string","description":"Session ID for tracking"},"validation":{"$ref":"#/components/schemas/ValidationReport","description":"Validation report"}}},"CreatePrResponse":{"type":"object","required":["run","pr_url","pr_number","branch_name"],"properties":{"branch_name":{"type":"string"},"pr_number":{"type":"integer","format":"int32"},"pr_url":{"type":"string"},"run":{"$ref":"#/components/schemas/AutofixerRunResponse"}}},"CreateProjectAccessRequest":{"type":"object","required":["team_id","role"],"properties":{"role":{"$ref":"#/components/schemas/TeamRole"},"team_id":{"type":"integer","format":"int32"}}},"CreateProjectFromTemplateRequest":{"type":"object","description":"Request to create a project from a template\n\nSupports two deploy modes:\n * **Fork mode** — when `git_provider_connection_id` is set, the template\n repo is cloned into a new repository under the user's Git account and the\n project tracks that fork (git-push deploys, automatic deploy on push).\n * **One-click public-repo mode** — when `git_provider_connection_id` is\n omitted, the project deploys directly from the template's public source\n repository (no fork, no Git account required). This is the activation\n path: a brand-new user with no Git provider connected can still deploy a\n demo in one click. `repository_name` / `repository_owner` are ignored in\n this mode, and automatic-deploy-on-push is unavailable (there is no fork\n to receive webhooks).","required":["template_slug","project_name"],"properties":{"automatic_deploy":{"type":"boolean","description":"Enable automatic deployment on push (defaults to true). Only honoured in\nfork mode; public-repo deploys cannot receive push webhooks."},"environment_variables":{"type":"array","items":{"$ref":"#/components/schemas/EnvVarInput"},"description":"Environment variables to set (key-value pairs)"},"git_provider_connection_id":{"type":["integer","null"],"format":"int32","description":"Git provider connection ID. When omitted, the project deploys directly\nfrom the template's public source repository instead of forking it."},"private":{"type":"boolean","description":"Whether to make the repository private (defaults to true)"},"project_name":{"type":"string","description":"Name for the new project"},"repository_name":{"type":["string","null"],"description":"Name for the new repository to create. Required in fork mode; ignored in\none-click public-repo mode."},"repository_owner":{"type":["string","null"],"description":"Owner/organization for the new repository (defaults to authenticated user)"},"storage_service_ids":{"type":"array","items":{"type":"integer","format":"int32"},"description":"External storage service IDs to attach to the project"},"template_slug":{"type":"string","description":"Template slug to use as the base"}}},"CreateProjectFromTemplateResponse":{"type":"object","description":"Response after creating a project from template","required":["project_id","project_slug","project_name","repository_url","template_slug","message"],"properties":{"message":{"type":"string","description":"Message with additional info"},"project_id":{"type":"integer","format":"int32","description":"ID of the created project"},"project_name":{"type":"string","description":"Name of the created project"},"project_slug":{"type":"string","description":"Slug of the created project"},"repository_url":{"type":"string","description":"URL of the created repository"},"template_slug":{"type":"string","description":"Template that was used"}}},"CreateProjectRequest":{"type":"object","required":["name","directory","main_branch","preset","storage_service_ids"],"properties":{"automatic_deploy":{"type":["boolean","null"]},"build_command":{"type":["string","null"]},"custom_domain":{"type":["string","null"]},"directory":{"type":"string"},"environment_variables":{"type":["array","null"],"items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]}},"exposed_port":{"type":["integer","null"],"format":"int32","description":"Port exposed by the container (fallback when image has no EXPOSE directive)\n\nPriority order for port resolution:\n1. Image EXPOSE directive (auto-detected from built image)\n2. Environment-level exposed_port (overrides this value per environment)\n3. This project-level exposed_port (fallback)\n4. Default: 3000\n\nOnly set this if your image doesn't use EXPOSE directive.","example":8080},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"git_url":{"type":["string","null"]},"install_command":{"type":["string","null"]},"is_on_demand":{"type":["boolean","null"]},"is_public_repo":{"type":["boolean","null"]},"is_web_app":{"type":["boolean","null"]},"main_branch":{"type":"string"},"name":{"type":"string"},"output_dir":{"type":["string","null"]},"performance_metrics_enabled":{"type":"boolean"},"preset":{"type":"string"},"preset_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PresetConfigSchema","description":"Preset-specific configuration\n\nDifferent presets accept different configuration options:\n- **Dockerfile preset**: Accepts `DockerfilePresetConfig` with `dockerfile_path` and `build_context`\n- **Nixpacks preset**: Accepts ordered `providers` (for example `[\"...\", \"python\"]`)\n and optional inline `nixpacksConfig` TOML\n- **Static presets** (Vite, Next.js, etc.): Accept `StaticPresetConfig` with build commands and output dir\n\nExample for Dockerfile preset:\n```json\n{\n \"dockerfilePath\": \"docker/Dockerfile\",\n \"buildContext\": \"./api\"\n}\n```"}]},"project_type":{"type":["string","null"]},"repo_name":{"type":["string","null"]},"repo_owner":{"type":["string","null"]},"source_type":{"$ref":"#/components/schemas/SourceType","description":"Source type for deployments\n\nDetermines how the project is deployed:\n- **git** (default): Traditional Git-based deployments - source code is pulled, built, and deployed\n- **docker_image**: Deploy pre-built Docker images from external registries (DockerHub, GHCR, etc.)\n- **static_files**: Deploy pre-built static files uploaded as tar.gz or zip bundles\n\nFor `docker_image` and `static_files` source types, `repo_name` and `repo_owner` are optional."},"storage_service_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"use_default_wildcard":{"type":["boolean","null"]}}},"CreateProjectSecretRequest":{"type":"object","description":"Request to create a new project secret.\n\nProject secrets are mounted into the container as files under\n`/run/secrets/` (mode 0400, tmpfs) instead of as environment variables.\nValues are always encrypted at rest and never returned in plaintext from\nthe API after create. Distinct from agent secrets (global `/settings/secrets`).","required":["key","value"],"properties":{"environment_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"include_in_preview":{"type":"boolean","description":"Include this secret in preview environments."},"key":{"type":"string","description":"Identifier for the secret. Becomes the filename at `/run/secrets/`.\nMust start with a letter or underscore and contain only A-Z, a-z, 0-9, _."},"value":{"type":"string","description":"Plaintext value, <= 1 MiB."}}},"CreateProviderKeyRequest":{"type":"object","required":["provider","display_name","api_key"],"properties":{"api_key":{"type":"string"},"base_url":{"type":["string","null"]},"default_model":{"type":["string","null"],"description":"Optional model id to pin for this provider (e.g. \"gpt-4o-mini\")."},"display_name":{"type":"string"},"provider":{"type":"string"}}},"CreateProviderRequest":{"type":"object","required":["name","provider_type","config"],"properties":{"config":{},"enabled":{"type":["boolean","null"]},"name":{"type":"string"},"provider_type":{"type":"string"}}},"CreateRouteRequest":{"type":"object","required":["domain","host","port"],"properties":{"domain":{"type":"string"},"host":{"type":"string"},"port":{"type":"integer","format":"int32"},"route_type":{"type":["string","null"],"description":"Route type: \"http\" (default) matches on HTTP Host header,\n\"tls\" matches on TLS SNI hostname for TCP passthrough"}}},"CreateS3SourceRequest":{"type":"object","required":["name","bucket_name","bucket_path","access_key_id","secret_key","region"],"properties":{"access_key_id":{"type":"string"},"bucket_name":{"type":"string"},"bucket_path":{"type":"string"},"endpoint":{"type":["string","null"],"description":"Optional endpoint URL for S3-compatible services like MinIO","example":"http://minio.example.com:9000"},"force_path_style":{"type":["boolean","null"],"description":"Whether to use path-style addressing (default: true)","example":true},"is_default":{"type":["boolean","null"],"description":"When true, make this the default source (will swap out any existing default).\nThe very first S3 source is always created as default regardless of this flag.","example":false},"name":{"type":"string"},"region":{"type":"string"},"secret_key":{"type":"string"}}},"CreateSandboxBody":{"type":"object","properties":{"_runtime":{"type":["string","null"]},"backend":{"type":["string","null"],"description":"Isolation backend: `\"docker\"` (default) or `\"firecracker\"` (ADR-029,\nhardware-virtualized microVM — requires a host provisioned with\n`temps firecracker setup`). Omit for the platform default; existing\nclients are unaffected. Requesting an unavailable backend fails with\n400 rather than silently downgrading isolation."},"cpu_limit":{"type":["number","null"],"format":"double"},"disk_size_mb":{"type":["integer","null"],"format":"int64","description":"Root disk size in MB (Firecracker only; Docker ignores it). Omit for\nthe platform default (1 GiB).","minimum":0},"env":{"type":"object","description":"Extra env vars baked into the container on create.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"image":{"type":["string","null"],"description":"Docker image override. `null` uses the platform default."},"memory_limit_mb":{"type":["integer","null"],"format":"int64","minimum":0},"name":{"type":["string","null"]},"networkPolicy":{},"pids_limit":{"type":["integer","null"],"format":"int64"},"ports":{"type":"array","items":{"type":"integer","format":"int32","minimum":0},"description":"Ports the sandbox will listen on. Each port becomes a `routes[]`\nentry in the create/get response so `@vercel/sandbox`'s\n`sandbox.domain(port)` can resolve it client-side without an\nextra round-trip."},"preview_password":{"type":["string","null"],"description":"Optional preview-URL password. When set, every preview URL served\nfor this sandbox is gated behind a login form. 8–256 characters.\nOmit to leave preview URLs open (the sandbox ID remains the only\ngate). The plaintext is never returned; only the last-4 hint is\nsurfaced in `SandboxResponse.preview_password_hint`."},"projectId":{"type":["string","null"]},"resources":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ResourcesBody","description":"`@vercel/sandbox`'s nested resources object. When present, its\n`memory` / `vcpus` populate `memory_limit_mb` / `cpu_limit` if those\nweren't sent directly."}]},"source":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SourceBody","description":"Optional initial content to seed into the work dir. Clones a\nrepo or extracts a tarball after the sandbox is created."}]},"timeout":{"type":["integer","null"],"format":"int64","description":"Idle timeout as sent by `@vercel/sandbox` (milliseconds). Converted\nto seconds when `timeout_secs` is absent.","minimum":0},"timeout_secs":{"type":["integer","null"],"format":"int64","description":"Idle timeout in seconds (temps-native). Clamped to `[60, 86400]`.","minimum":0}}},"CreateSkillRequest":{"type":"object","required":["slug","name","content"],"properties":{"content":{"type":"string"},"description":{"type":["string","null"]},"name":{"type":"string"},"slug":{"type":"string"}}},"CreateSlackProviderRequest":{"type":"object","required":["name","config"],"properties":{"config":{"$ref":"#/components/schemas/SlackConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":"string"}}},"CreateTeamMemberRequest":{"type":"object","required":["user_id","role"],"properties":{"role":{"$ref":"#/components/schemas/TeamRole"},"user_id":{"type":"integer","format":"int32"}}},"CreateTeamRequest":{"type":"object","required":["name","slug"],"properties":{"description":{"type":["string","null"]},"name":{"type":"string"},"slug":{"type":"string"}}},"CreateUserRequest":{"type":"object","required":["username","roles"],"properties":{"email":{"type":["string","null"]},"password":{"type":["string","null"]},"roles":{"type":"array","items":{"type":"string"}},"username":{"type":"string"}}},"CreateWebhookProviderRequest":{"type":"object","required":["name","config"],"properties":{"config":{"$ref":"#/components/schemas/WebhookConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":"string"}}},"CreateWebhookRequestBody":{"type":"object","required":["url","events"],"properties":{"enabled":{"type":["boolean","null"],"description":"Whether the webhook is enabled","default":true},"events":{"type":"array","items":{"type":"string"},"description":"Event types to subscribe to","example":["deployment.created","deployment.succeeded"]},"secret":{"type":["string","null"],"description":"Secret for HMAC signature verification (optional)"},"url":{"type":"string","description":"Target URL for webhook delivery","example":"https://example.com/webhook"}}},"CreatedResource":{"type":"object","description":"Resource created during import (for rollback / audit)","required":["resource_type","resource_id","resource_name"],"properties":{"resource_id":{"type":"integer","format":"int32","description":"Resource ID"},"resource_name":{"type":"string","description":"Resource name"},"resource_type":{"type":"string","description":"Resource type (project, environment, deployment, service, domain, etc.)"}}},"CronExecutionInfo":{"type":"object","required":["id","cron_id","executed_at","url","status_code","headers","response_time_ms"],"properties":{"cron_id":{"type":"integer","format":"int32"},"error_message":{"type":["string","null"]},"executed_at":{"type":"string"},"headers":{"type":"string"},"id":{"type":"integer","format":"int32"},"response_time_ms":{"type":"integer","format":"int32"},"status_code":{"type":"integer","format":"int32"},"url":{"type":"string"}}},"CronInfo":{"type":"object","required":["id","project_id","environment_id","path","schedule","created_at","updated_at"],"properties":{"created_at":{"type":"string"},"deleted_at":{"type":["string","null"]},"environment_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"next_run":{"type":["string","null"]},"path":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"schedule":{"type":"string"},"updated_at":{"type":"string"}}},"CrossProjectSiblingRef":{"type":"object","description":"A sibling project that shares the same `trace_id`, returned by the\nPhase 1 cross-project banner endpoint.","required":["project_id","project_name","project_slug","first_seen"],"properties":{"first_seen":{"type":"string","format":"date-time","description":"ISO 8601 timestamp (UTC, `Z` suffix) of first span ingest for this\n`(trace_id, project_id)` pair."},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"project_slug":{"type":"string","description":"URL slug used to link into the sibling project's single-project trace view."}}},"CrossProjectTraceResponse":{"type":"object","description":"Response body for `GET /otel/traces/cross-project/{trace_id}`.\n\nAn empty `siblings` vec is the normal single-project case — never 404.","required":["trace_id","siblings"],"properties":{"siblings":{"type":"array","items":{"$ref":"#/components/schemas/CrossProjectSiblingRef"},"description":"Projects other than the caller's that hold spans for this trace,\nordered by `first_seen ASC`."},"trace_id":{"type":"string","description":"The trace_id that was queried (echoed back for client convenience)."}}},"CurrentStatusResponse":{"type":"object","required":["monitor_id","current_status","uptime_percentage"],"properties":{"avg_response_time_ms":{"type":["number","null"],"format":"double"},"current_status":{"type":"string"},"last_check_at":{"type":["string","null"],"format":"date-time"},"monitor_id":{"type":"integer","format":"int32"},"uptime_percentage":{"type":"number","format":"double"}}},"CustomDomainRequest":{"type":"object","required":["domain","environment_id"],"properties":{"branch":{"type":["string","null"]},"domain":{"type":"string"},"environment_id":{"type":"integer","format":"int32"},"redirect_to":{"type":["string","null"]},"service_name":{"type":["string","null"],"description":"Docker Compose service name this domain routes to (only for docker-compose projects)"},"status_code":{"type":["integer","null"],"format":"int32"}}},"CustomDomainResponse":{"type":"object","required":["id","project_id","domain","status","created_at","updated_at"],"properties":{"branch":{"type":["string","null"]},"created_at":{"type":"integer","format":"int64"},"domain":{"type":"string"},"domain_id":{"type":["integer","null"],"format":"int32"},"environment":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DomainEnvironmentResponse"}]},"expiration_time":{"type":["integer","null"],"format":"int64"},"id":{"type":"integer","format":"int32"},"last_renewed":{"type":["integer","null"],"format":"int64"},"message":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"redirect_to":{"type":["string","null"]},"service_name":{"type":["string","null"],"description":"Docker Compose service name this domain routes to"},"status":{"type":"string"},"status_code":{"type":["integer","null"],"format":"int32"},"updated_at":{"type":"integer","format":"int64"}}},"CustomerMovementResponse":{"type":"object","required":["bucket","new_customers","churned_customers"],"properties":{"bucket":{"type":"string","format":"date-time"},"churned_customers":{"type":"integer","format":"int64"},"new_customers":{"type":"integer","format":"int64"}}},"DashboardLayout":{"type":"object","description":"The typed layout persisted (as JSONB) in `metric_dashboards.layout`.","required":["sections"],"properties":{"sections":{"type":"array","items":{"$ref":"#/components/schemas/DashboardSection"},"description":"Ordered sections that make up the dashboard."}}},"DashboardProjectsAnalyticsQuery":{"type":"object","description":"Query parameters for batch dashboard analytics","required":["project_ids","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"project_ids":{"type":"string","description":"Comma-separated list of project IDs"},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"DashboardProjectsAnalyticsResponse":{"type":"object","description":"Batch response for dashboard project analytics","required":["projects"],"properties":{"projects":{"type":"object","description":"Map of project_id -> analytics data","additionalProperties":{"$ref":"#/components/schemas/ProjectDashboardAnalytics"},"propertyNames":{"type":"string"}}}},"DashboardSection":{"type":"object","description":"A titled group of tiles within a dashboard.","required":["id","title","tiles"],"properties":{"id":{"type":"string","description":"Stable client-generated section id."},"tiles":{"type":"array","items":{"$ref":"#/components/schemas/DashboardTile"},"description":"Tiles rendered within this section."},"title":{"type":"string","description":"Section heading."}}},"DashboardTile":{"type":"object","description":"A single metric tile within a dashboard section.","required":["id","metric_name","aggregation"],"properties":{"aggregation":{"type":"string","description":"Aggregation applied per bucket: one of\n`avg|sum|min|max|count|rate|p50|p90|p95|p99`."},"group_by":{"type":"array","items":{"type":"string"},"description":"Label keys to break the metric down by (group-by / multi-series view).\nEmpty = single aggregated series (current behavior). Max 2 keys — more\ndimensions are unreadable in a chart (ADR-026 Phase 2). Each key must\nmatch `[a-zA-Z0-9_.:-]`. Wired directly to `MetricQuery.group_by` by\nthe tile query path (separate frontend task)."},"id":{"type":"string","description":"Stable client-generated tile id (used as a React key / for reordering)."},"label_filters":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"AND-combined label equality filters: `[[\"key\",\"value\"],…]`. Empty = no\nfiltering. Max 10 pairs; keys must match `[a-zA-Z0-9_.:-]`; values\ncapped at 500 characters. Not yet wired into the tile query path\n(Phase 1 ADR-026 — field round-trips and validates; query wiring is\na separate frontend task)."},"metric_name":{"type":"string","description":"The metric name to chart (e.g. `http.server.duration`)."},"title":{"type":["string","null"],"description":"Optional display title; falls back to the metric name in the UI."}}},"DataImplication":{"type":"object","description":"A specific data implication the user needs to understand","required":["severity","message"],"properties":{"message":{"type":"string","description":"Human-readable description of what could happen"},"recommended_action":{"type":["string","null"],"description":"What the user should do about it (if anything)"},"severity":{"$ref":"#/components/schemas/DataImplicationSeverity","description":"Severity of this implication"}}},"DataImplicationSeverity":{"type":"string","description":"Severity of a data implication","enum":["info","warning","data-not-migrated","potential-data-loss"]},"DatabaseMetricsResponse":{"type":"object","description":"Response for the per-database metrics breakdown.","required":["databases"],"properties":{"databases":{"type":"array","items":{"$ref":"#/components/schemas/DatabaseMetricsRow"},"description":"One entry per database, sorted by the first metric descending\n(largest first) so the biggest database leads the table."}}},"DatabaseMetricsRow":{"type":"object","description":"Per-database metric values for a Postgres service.\n\nA Postgres instance can host many databases (some unrelated to this\nservice). The collector records per-`datname` series; this groups the\nlatest value of each requested metric by database so the UI can render a\n\"Databases\" breakdown table instead of one collapsed number.","required":["database","metrics"],"properties":{"database":{"type":"string","description":"Database name (`datname`)."},"metrics":{"type":"object","description":"Latest value of each requested metric for this database\n(e.g. `{\"pg.database_size_bytes\": 7943871, \"pg.cache_hit_ratio\": 0.99}`).","additionalProperties":{"type":"number","format":"double"},"propertyNames":{"type":"string"}}}},"DelRequest":{"type":"object","description":"Request to delete keys","required":["keys"],"properties":{"keys":{"type":"array","items":{"type":"string"},"description":"The key(s) to delete","example":["user:123","user:456"]},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"DelResponse":{"type":"object","description":"Response for delete operation","required":["deleted"],"properties":{"deleted":{"type":"integer","format":"int64","description":"Number of keys deleted","example":2}}},"DeleteBlobRequest":{"type":"object","description":"Request to delete blobs","required":["pathnames"],"properties":{"pathnames":{"type":"array","items":{"type":"string"},"description":"Pathnames to delete (relative to project)","example":["images/avatar.png","documents/file.pdf"]},"projectId":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"DeleteBlobResponse":{"type":"object","description":"Response after deleting blobs","required":["deleted"],"properties":{"deleted":{"type":"integer","format":"int64","description":"Number of blobs deleted","example":2}}},"DeleteResponse":{"type":"object","required":["deleted"],"properties":{"deleted":{"type":"integer","format":"int64","minimum":0}}},"DeployFromImageRequest":{"type":"object","properties":{"external_image_id":{"type":["integer","null"],"format":"int32","description":"External image ID (if already registered). If provided without image_ref,\nthe image reference will be fetched from the registered external image."},"health_check_path":{"type":["string","null"],"description":"Optional HTTP health-check path override (e.g. \"/api/healthz\").\nImage deploys can't read `.temps.yaml`, so this sets the path the deployer\nprobes after the container starts and the path the environment's uptime\nmonitor checks. Must start with '/'. When omitted, defaults to \"/\".","example":"/api/healthz"},"image_ref":{"type":["string","null"],"description":"Docker image reference (e.g., \"ghcr.io/org/app:v1.0\")\nRequired if external_image_id is not provided","example":"ghcr.io/myorg/myapp:v1.0"},"metadata":{"description":"Optional deployment metadata"}}},"DeployFromImageUploadQuery":{"type":"object","description":"Query parameters for deploying from an uploaded image tarball","properties":{"health_check_path":{"type":["string","null"],"description":"Optional HTTP health-check path override (e.g. \"/api/healthz\").\nMust start with '/'. When omitted, defaults to \"/\".","example":"/api/healthz"},"tag":{"type":["string","null"],"description":"Tag to apply to the imported image (e.g., \"myapp:v1.0\")\nIf not provided, a unique tag will be generated","example":"myapp:v1.0"}}},"DeployFromStaticRequest":{"type":"object","required":["static_bundle_id"],"properties":{"health_check_path":{"type":["string","null"],"description":"Optional HTTP health-check path override (e.g. \"/api/healthz\").\nStatic deploys can't read `.temps.yaml`, so this sets the path the deployer\nprobes after the container starts and the path the environment's uptime\nmonitor checks. Must start with '/'. When omitted, defaults to \"/\".","example":"/api/healthz"},"metadata":{"description":"Optional deployment metadata"},"static_bundle_id":{"type":"integer","format":"int32","description":"Static bundle ID (required)"}}},"DeploymentConfig":{"type":"object","description":"Deployment configuration shared between projects and environments\n\nThis configuration can be set at the project level (as defaults) and\noverridden at the environment level for specific deployments.\n\nNote: Environment variables are managed separately and are not part of this config.","properties":{"antiAffinity":{"type":"boolean","description":"Anti-affinity: spread replicas across different nodes.\n\nWhen enabled, the scheduler avoids placing two replicas of the same\nenvironment on the same node. If there are fewer eligible nodes than\nreplicas, remaining replicas wrap around (best-effort spreading).\n\nDefaults to `true` — replicas spread by default."},"automaticDeploy":{"type":["boolean","null"],"description":"Enable automatic deployments on git push.\n`None` = inherit from project config; `Some(true/false)` = explicit override.\nStored as JSONB so absent key → `None` (inherit), never silently defaults to false."},"containerExecEnabled":{"type":"boolean","description":"Enable container exec/shell access (disabled by default for security)"},"cpuLimit":{"type":["integer","null"],"format":"int32","description":"CPU limit in microcores, where 1_000_000 = 1 full CPU core\n(e.g., 2_000_000 = 2 CPUs). NOT millicores. `None` = uncapped."},"cpuRequest":{"type":["integer","null"],"format":"int32","description":"CPU request in microcores, where 1_000_000 = 1 full CPU core\n(e.g., 100_000 = 0.1 CPU, 500_000 = 0.5 CPU, 2_000_000 = 2 CPUs).\nNOT millicores — the deployer formats this as `{n}u` and converts\n`n / 1_000_000` cores into Docker nano_cpus."},"crossArchitectureBuilds":{"type":["boolean","null"],"description":"Build one image per architecture the eligible nodes run.\n\n`None`/`false` (the default) builds exactly once, on the control\nplane's native platform — byte-for-byte the behaviour of a\nsingle-architecture cluster. When enabled and the nodes this\ndeployment could land on span more than one architecture, the build\njob produces one image per architecture; the non-native ones go\nthrough the daemon's `platform` option, which requires QEMU binfmt\nhandlers registered on the control plane.\n\n**Opt-in on purpose.** Cross-architecture builds are emulated and\nsubstantially slower, and deriving them from cluster topology would\nmean a single node joining silently changes build behaviour for every\ndeployment in the cluster. It also keeps the decision on operator\nconfig rather than on a value each node reports about itself.\n\n`Option` so an environment inherits the project's setting\n(`None`) or overrides it, matching `automatic_deploy`."},"exposedPort":{"type":["integer","null"],"format":"int32","description":"Port exposed by the container\nIf not specified, will be auto-detected from Docker image or default to 3000"},"idleTimeoutSeconds":{"type":"integer","format":"int32","description":"Seconds of inactivity before containers are stopped in on-demand mode.\nOnly used when `on_demand` is true. Min: 60, Max: 86400 (24h).\nDefault: 300 (5 minutes)."},"memoryLimit":{"type":["integer","null"],"format":"int32","description":"Memory limit in megabytes. Three-state semantics:\n- `None` → inherit the parent layer (env inherits project, project\n inherits the seeded default); used by the settings UI's \"Use default\".\n- `Some(0)` → explicit **uncapped**: stop inheriting and run with no\n memory limit. This is the deliberate escape hatch for dedicated\n workloads, distinct from `None`.\n- `Some(n)` → hard cap of `n` MB.\n\n`merge`/resolution keep `Some(0)` as a present value (it wins precedence\nover a parent cap), and the deployer collapses it to \"no limit\" before\ntalking to Docker."},"memoryRequest":{"type":["integer","null"],"format":"int32","description":"Memory request in megabytes (e.g., 128 = 128MB)"},"onDemand":{"type":"boolean","description":"Enable on-demand mode (scale-to-zero).\nWhen enabled, containers are stopped after `idle_timeout_seconds` of no traffic\nand automatically started when a new request arrives."},"performanceMetricsEnabled":{"type":"boolean","description":"Enable performance metrics collection (speed insights)"},"replicas":{"type":"integer","format":"int32","description":"Number of replicas/instances to run\nDefaults to 1 replica"},"security":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SecurityConfig","description":"Security configuration (headers, rate limiting, attack mode, etc.)\nThese settings inherit and override from parent level (Environment > Project > Global)"}]},"sessionRecordingEnabled":{"type":"boolean","description":"Enable session recording for analytics"},"targetLabels":{"description":"Label selector for node-based scheduling. Replicas are only deployed to\nnodes whose labels match the selector.\n\nMatching rules:\n- **Same key, array value** → OR: node must match any value\n- **Different keys** → AND: node must satisfy all keys\n\nExample: `{\"region\": [\"us\", \"asia\"], \"gpu\": \"true\"}`\n→ (region=us OR region=asia) AND gpu=true\n\nApplied after `target_nodes` filtering (they stack)."},"targetNodes":{"type":["array","null"],"items":{"type":"integer","format":"int32"},"description":"Optional list of node IDs to deploy to. When set, replicas are distributed\nonly across these nodes (round-robin). When None, the scheduler distributes\nacross all active nodes (or deploys locally if no nodes exist)."},"wakeTimeoutSeconds":{"type":"integer","format":"int32","description":"Max seconds to wait for containers to start when waking from on-demand sleep.\nRequests return 503 if exceeded. Default: 30."}}},"DeploymentConfigSnapshot":{"type":"object","description":"Deployment configuration snapshot for deployments\n\nThis extends DeploymentConfig with environment variables to capture\nthe complete state of a deployment at the time it was created.","properties":{"automaticDeploy":{"type":"boolean","description":"Enable automatic deployments on git push"},"containerExecEnabled":{"type":"boolean","description":"Enable container exec/shell access"},"cpuLimit":{"type":["integer","null"],"format":"int32","description":"CPU limit in millicores"},"cpuRequest":{"type":["integer","null"],"format":"int32","description":"CPU request in millicores"},"environmentVariables":{"type":"object","description":"Environment variables used for this deployment","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"exposedPort":{"type":["integer","null"],"format":"int32","description":"Port exposed by the container"},"memoryLimit":{"type":["integer","null"],"format":"int32","description":"Memory limit in megabytes"},"memoryRequest":{"type":["integer","null"],"format":"int32","description":"Memory request in megabytes"},"performanceMetricsEnabled":{"type":"boolean","description":"Enable performance metrics collection"},"replicas":{"type":"integer","format":"int32","description":"Number of replicas"},"sessionRecordingEnabled":{"type":"boolean","description":"Enable session recording"}}},"DeploymentConfiguration":{"type":"object","description":"Deployment-level configuration","required":["image","strategy","env_vars","ports","volumes","network","resources"],"properties":{"build":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/BuildConfiguration","description":"Build configuration (if building from source)"}]},"command":{"type":["array","null"],"items":{"type":"string"},"description":"Command override"},"entrypoint":{"type":["array","null"],"items":{"type":"string"},"description":"Entrypoint override"},"env_vars":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentVariable"},"description":"Environment variables"},"git":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/GitSourcePlan","description":"Where the application's source code lives, when the source platform\nbuilds from a git repository. Execution uses this to link the temps\nproject to the same repository so the real deployment pipeline can\nclone and build it."}]},"health_check":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/HealthCheckConfiguration","description":"Health check configuration"}]},"image":{"type":"string","description":"Image to deploy"},"network":{"$ref":"#/components/schemas/NetworkConfiguration","description":"Network configuration"},"ports":{"type":"array","items":{"$ref":"#/components/schemas/PortMapping"},"description":"Port mappings"},"resources":{"$ref":"#/components/schemas/ResourceLimits","description":"Resource limits"},"strategy":{"$ref":"#/components/schemas/DeploymentStrategy","description":"Deployment strategy"},"volumes":{"type":"array","items":{"$ref":"#/components/schemas/VolumeMount"},"description":"Volume mounts"},"working_dir":{"type":["string","null"],"description":"Working directory"}}},"DeploymentContainerLogContentResponse":{"type":"object","description":"A single captured container-log dump, including its full text content.","required":["id","container_name","size_bytes","truncated","captured_at","content"],"properties":{"captured_at":{"type":"integer","format":"int64"},"container_name":{"type":"string"},"content":{"type":"string","description":"The captured plain-text log content."},"id":{"type":"integer","format":"int32"},"service_name":{"type":["string","null"]},"size_bytes":{"type":"integer","format":"int64"},"truncated":{"type":"boolean"}}},"DeploymentContainerLogResponse":{"type":"object","description":"Metadata for one captured (historical) container-log dump. Listed on the\ndeployment detail page so a user can pick which past container's logs to read.","required":["id","deployment_id","container_id","container_name","size_bytes","truncated","captured_at"],"properties":{"captured_at":{"type":"integer","format":"int64","description":"Unix epoch milliseconds of when the logs were captured (just before\nteardown). Matches the timestamp convention used by `DeploymentResponse`."},"container_id":{"type":"string"},"container_name":{"type":"string"},"deployment_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"node_id":{"type":["integer","null"],"format":"int32"},"service_name":{"type":["string","null"]},"size_bytes":{"type":"integer","format":"int64"},"truncated":{"type":"boolean"}}},"DeploymentContainerLogsListResponse":{"type":"object","description":"The list of captured container-log dumps for a deployment.","required":["logs"],"properties":{"logs":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentContainerLogResponse"}}}},"DeploymentEnvironmentResponse":{"type":"object","required":["id","name","slug","domains"],"properties":{"domains":{"type":"array","items":{"type":"string"}},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"slug":{"type":"string"}}},"DeploymentJobResponse":{"type":"object","required":["id","deployment_id","job_id","job_type","name","status","created_at","updated_at","log_id"],"properties":{"created_at":{"type":"integer","format":"int64"},"dependencies":{},"deployment_id":{"type":"integer","format":"int32"},"description":{"type":["string","null"]},"error_message":{"type":["string","null"]},"execution_order":{"type":["integer","null"],"format":"int32"},"finished_at":{"type":["integer","null"],"format":"int64"},"id":{"type":"integer","format":"int32"},"job_config":{"description":"Internal workflow configuration is intentionally redacted. It can\ncontain legacy plaintext secrets or encrypted secret envelopes."},"job_id":{"type":"string"},"job_type":{"type":"string"},"log_id":{"type":"string"},"name":{"type":"string"},"outputs":{},"started_at":{"type":["integer","null"],"format":"int64"},"status":{"type":"string"},"updated_at":{"type":"integer","format":"int64"}}},"DeploymentJobsResponse":{"type":"object","required":["jobs","total"],"properties":{"jobs":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentJobResponse"}},"total":{"type":"integer","minimum":0}}},"DeploymentListResponse":{"type":"object","required":["deployments","total","page","per_page"],"properties":{"deployments":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentResponse"}},"page":{"type":"integer","format":"int64"},"per_page":{"type":"integer","format":"int64"},"total":{"type":"integer","format":"int64"}}},"DeploymentMetadata":{"type":"object","description":"Deployment metadata - typed information about the deployment","properties":{"buildDurationMs":{"type":["integer","null"],"format":"int64","description":"Build duration in milliseconds"},"builder":{"type":["string","null"],"description":"Docker builder used (e.g., \"nixpacks\", \"dockerfile\")"},"deploymentDurationMs":{"type":["integer","null"],"format":"int64","description":"Deployment duration in milliseconds"},"deploymentSourceType":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SourceType","description":"Source type for THIS specific deployment (for Manual/flexible projects)\nThis allows Manual projects to have deployments via different methods\n(docker_image, static_files, or git) while keeping per-deployment tracking"}]},"dockerfilePath":{"type":["string","null"],"description":"Dockerfile path if using Dockerfile builder"},"externalImageId":{"type":["integer","null"],"format":"int32","description":"External image ID (reference to external_images table)"},"externalImageRef":{"type":["string","null"],"description":"External Docker image reference (for docker_image source type)\ne.g., \"ghcr.io/org/app:v1.0\" or \"docker.io/myapp:sha-abc123\""},"fileCount":{"type":["integer","null"],"format":"int32","description":"Number of files in the build output"},"gitPushEvent":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/GitPushEvent","description":"Git push event that triggered this deployment (if from webhook)"}]},"healthCheckPath":{"type":["string","null"],"description":"Explicit deploy-time HTTP health-check path override.\nImage/static deploys can't read `.temps.yaml`, so this lets the deploy\nrequest set a custom path (e.g. \"/api/healthz\"). When present it takes\npriority over any `.temps.yaml` `health.path` value. Always starts with '/'."},"imageSizeBytes":{"type":["integer","null"],"format":"int64","description":"Total size of the built image in bytes"},"imageUploadedLocally":{"type":"boolean","description":"Whether the image was uploaded directly (via docker save/load) rather than pulled from registry\nWhen true, the PullExternalImageJob is skipped since the image is already loaded locally"},"isRollback":{"type":"boolean","description":"Whether this is a rollback deployment"},"labels":{"type":"array","items":{"type":"string"},"description":"Custom labels/tags for the deployment"},"rolledBackFromId":{"type":["integer","null"],"format":"int32","description":"ID of the deployment this was rolled back from (if applicable)"},"staticBundleContentType":{"type":["string","null"],"description":"Static bundle content type (for proper extraction: application/gzip or application/zip)"},"staticBundleId":{"type":["integer","null"],"format":"int32","description":"Static bundle ID (reference to static_bundles table, for static_files source type)"},"staticBundlePath":{"type":["string","null"],"description":"Static bundle path in blob storage (for static_files source type)"},"uploadedImageId":{"type":["string","null"],"description":"Docker image ID of the locally uploaded image (sha256:...)\nUsed to verify the image exists before deployment"}}},"DeploymentResponse":{"type":"object","required":["id","project_id","environment_id","environment","status","url","created_at","is_current"],"properties":{"branch":{"type":["string","null"]},"cancelled_reason":{"type":["string","null"]},"commit_author":{"type":["string","null"]},"commit_date":{"type":["integer","null"],"format":"int64"},"commit_hash":{"type":["string","null"]},"commit_message":{"type":["string","null"]},"created_at":{"type":"integer","format":"int64"},"deployment_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DeploymentConfigSnapshot","description":"Deployment configuration snapshot (CPU, memory, replicas, environment variables, etc.)"}]},"environment":{"$ref":"#/components/schemas/DeploymentEnvironmentResponse"},"environment_id":{"type":"integer","format":"int32"},"finished_at":{"type":["integer","null"],"format":"int64"},"id":{"type":"integer","format":"int32"},"is_current":{"type":"boolean"},"metadata":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DeploymentMetadata","description":"Deployment metadata (build info, git event, etc.)"}]},"project_id":{"type":"integer","format":"int32"},"screenshot_location":{"type":["string","null"]},"started_at":{"type":["integer","null"],"format":"int64"},"status":{"type":"string"},"tag":{"type":["string","null"]},"url":{"type":"string"}}},"DeploymentStateResponse":{"type":"object","required":["id","state","message"],"properties":{"id":{"type":"integer","format":"int32"},"message":{"type":"string"},"state":{"type":"string"}}},"DeploymentStrategy":{"type":"string","description":"Deployment strategy","enum":["replace","blue-green","rolling"]},"DeploymentTokenListResponse":{"type":"object","required":["tokens","total"],"properties":{"tokens":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentTokenResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"DeploymentTokenResponse":{"type":"object","required":["id","project_id","name","token_prefix","is_active","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00Z"},"created_by":{"type":["integer","null"],"format":"int32"},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"last_used_at":{"type":["string","null"],"format":"date-time","example":"2024-01-01T00:00:00Z"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"}},"project_id":{"type":"integer","format":"int32"},"token_prefix":{"type":"string"}}},"DetectionConfig":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/StaticParams","description":"v0 (shipping): static threshold comparison of the aggregated value."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["static"]}}}],"description":"v0 (shipping): static threshold comparison of the aggregated value."},{"allOf":[{"$ref":"#/components/schemas/AnomalyParams","description":"Seasonal anomaly band (basic/agile/robust/ewma share this variant — the\nalgorithm is a field, not a new kind). Creation rejected until evaluated."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["anomaly"]}}}],"description":"Seasonal anomaly band (basic/agile/robust/ewma share this variant — the\nalgorithm is a field, not a new kind). Creation rejected until evaluated."},{"allOf":[{"$ref":"#/components/schemas/ForecastParams","description":"Predict a future threshold breach (capacity planning). Stub."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["forecast"]}}}],"description":"Predict a future threshold breach (capacity planning). Stub."},{"allOf":[{"$ref":"#/components/schemas/OutlierParams","description":"Cross-series population outlier (one host misbehaving vs its peers). Stub."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["outlier"]}}}],"description":"Cross-series population outlier (one host misbehaving vs its peers). Stub."},{"allOf":[{"$ref":"#/components/schemas/AutoWatchParams","description":"Watchdog-style self-tuning auto-watch (engine picks bounds). Stub."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["auto_watch"]}}}],"description":"Watchdog-style self-tuning auto-watch (engine picks bounds). Stub."}],"description":"The typed detector definition stored (as jsonb) in\n`metric_alert_rules.detection_config`.\n\nToday only [`DetectionConfig::Static`] is evaluable; the other variants are\nschema-present (so the SDK/UI and storage are already future-shaped) but\nrejected by [`DetectionConfig::validate`] until their evaluator lands. Each is\nthen enabled code-only, with no schema migration."},"DeviceCount":{"type":"object","required":["device_type","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"device_type":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"DigestSections":{"type":"object","description":"Sections that can be included in the weekly digest\nNote: `#[serde(default)]` allows backward compatibility when deserializing\nold data that may have `security` and `resources` fields instead of `projects`","properties":{"deployments":{"type":"boolean","default":true},"errors":{"type":"boolean","default":true},"funnels":{"type":"boolean","default":true},"performance":{"type":"boolean","default":true},"projects":{"type":"boolean","default":true}}},"Direction":{"type":"string","description":"Which side(s) of an anomaly band count as a deviation.","enum":["both","above","below"]},"DisableBlobResponse":{"type":"object","description":"Response after disabling Blob service","required":["success","message"],"properties":{"message":{"type":"string","description":"Human-readable message","example":"Blob service disabled successfully"},"success":{"type":"boolean","description":"Whether the operation succeeded","example":true}}},"DisableKvResponse":{"type":"object","description":"Response after disabling KV service","required":["success","message"],"properties":{"message":{"type":"string","description":"Status message","example":"KV service disabled successfully"},"success":{"type":"boolean","description":"Whether the service was successfully disabled"}}},"DisableMfaRequest":{"type":"object","required":["code"],"properties":{"code":{"type":"string"}}},"DiscoverRequest":{"type":"object","description":"Request to discover workloads","required":["source"],"properties":{"credentials":{"$ref":"#/components/schemas/ImportCredentials","description":"Platform credentials (required for cloud platforms like Vercel, Railway)"},"selector":{"$ref":"#/components/schemas/ImportSelector","description":"Optional selector to filter workloads"},"source":{"$ref":"#/components/schemas/ImportSource","description":"Source to discover from"}}},"DiscoverResponse":{"type":"object","description":"Response with discovered workloads","required":["workloads"],"properties":{"workloads":{"type":"array","items":{"$ref":"#/components/schemas/WorkloadDescriptor"},"description":"Discovered workloads"}}},"DiskInfo":{"type":"object","description":"Disk space information for a single disk/partition","required":["mount_point","total_bytes","used_bytes","available_bytes","usage_percent","file_system"],"properties":{"available_bytes":{"type":"integer","format":"int64","description":"Available space in bytes","minimum":0},"file_system":{"type":"string","description":"File system type (e.g., \"ext4\", \"apfs\")"},"mount_point":{"type":"string","description":"Mount point of the disk"},"total_bytes":{"type":"integer","format":"int64","description":"Total space in bytes","minimum":0},"usage_percent":{"type":"number","format":"double","description":"Usage percentage (0-100)"},"used_bytes":{"type":"integer","format":"int64","description":"Used space in bytes","minimum":0}}},"DiskSpaceAlert":{"type":"object","description":"Alert for a disk that exceeds the threshold","required":["mount_point","usage_percent","threshold_percent","available_bytes","available_human"],"properties":{"available_bytes":{"type":"integer","format":"int64","description":"Available space in bytes","minimum":0},"available_human":{"type":"string","description":"Human-readable available space"},"mount_point":{"type":"string","description":"Mount point of the disk"},"threshold_percent":{"type":"integer","format":"int32","description":"Configured threshold percentage","minimum":0},"usage_percent":{"type":"number","format":"double","description":"Current usage percentage"}}},"DiskSpaceAlertSettings":{"type":"object","description":"Disk space alert settings for monitoring disk usage","properties":{"check_interval_seconds":{"type":"integer","format":"int64","description":"Interval in seconds between disk space checks","default":300,"example":300,"minimum":60},"enabled":{"type":"boolean","description":"Whether disk space alerts are enabled","default":true},"monitor_path":{"type":["string","null"],"description":"Restrict monitoring to the disk backing this path. When unset (the\ndefault), every mounted writable volume is monitored — including\ndedicated volumes such as `/var/lib/docker`.","default":null},"threshold_percent":{"type":"integer","format":"int32","description":"Threshold percentage (0-100) at which to trigger alerts","default":80,"example":80,"maximum":100,"minimum":0}}},"DiskSpaceCheckResult":{"type":"object","description":"Result of a disk space check","required":["checked_at","enabled","threshold_percent","disks","alerts"],"properties":{"alerts":{"type":"array","items":{"$ref":"#/components/schemas/DiskSpaceAlert"},"description":"Disks that meet or exceed the threshold"},"checked_at":{"type":"string","format":"date-time","description":"Timestamp of the check (ISO 8601, UTC)","example":"2026-05-28T12:15:47.609192Z"},"disks":{"type":"array","items":{"$ref":"#/components/schemas/DiskInfo"},"description":"List of all monitored disks"},"enabled":{"type":"boolean","description":"Whether disk space monitoring is enabled in settings"},"threshold_percent":{"type":"integer","format":"int32","description":"Configured alert threshold percentage (0-100)","minimum":0}}},"DnsAckRequest":{"type":"object","required":["applied_generation"],"properties":{"applied_generation":{"type":"integer","format":"int64","description":"Highest generation the agent has actually applied locally."}}},"DnsAckResponse":{"type":"object","required":["node_id","applied_generation","server_generation"],"properties":{"applied_generation":{"type":"integer","format":"int64"},"node_id":{"type":"integer","format":"int32"},"server_generation":{"type":"integer","format":"int64"}}},"DnsChallengeRecordResult":{"type":"object","description":"Result of a single DNS TXT record creation for ACME challenge","required":["name","value","success","message"],"properties":{"message":{"type":"string","description":"Human-readable message about the operation"},"name":{"type":"string","description":"TXT record name (e.g., \"_acme-challenge.example.com\")","example":"_acme-challenge.example.com"},"success":{"type":"boolean","description":"Whether the record was created successfully"},"value":{"type":"string","description":"TXT record value (the ACME challenge token)","example":"abc123..."}}},"DnsChangesResponse":{"type":"object","required":["generation","full_snapshot","records","removed_ids"],"properties":{"full_snapshot":{"type":"boolean","description":"`true` ⇒ replace the local zone with `records`. `false` ⇒ merge\n`records` into the existing zone (and remove `removed_ids`)."},"generation":{"type":"integer","format":"int64","description":"Highest generation included in this response. Agent ACKs this back."},"records":{"type":"array","items":{"$ref":"#/components/schemas/EndpointDto"}},"removed_ids":{"type":"array","items":{"type":"integer","format":"int64"},"description":"IDs the agent should remove from its zone. Always empty in the v1\nprotocol — the resolver reconciles by name on snapshot mode. Kept\nin the wire format so a future tombstone-based protocol doesn't\nrequire a breaking change."}}},"DnsCompletionResponse":{"type":"object","required":["domain","status"],"properties":{"domain":{"type":"string"},"status":{"type":"string"}}},"DnsLookupError":{"type":"object","description":"Error response for DNS lookup failures","required":["error","domain"],"properties":{"domain":{"type":"string","description":"Domain name that failed","example":"nonexistent.com"},"error":{"type":"string","description":"Error message","example":"DNS lookup failed: domain not found"}}},"DnsLookupRequest":{"type":"object","description":"Request to lookup DNS A records for a domain","required":["domain"],"properties":{"domain":{"type":"string","description":"Domain name to lookup","example":"example.com"}}},"DnsLookupResponse":{"type":"object","description":"Response containing DNS A records","required":["domain","records","count","dns_servers"],"properties":{"count":{"type":"integer","description":"Number of records found","example":1,"minimum":0},"dns_servers":{"type":"array","items":{"type":"string"},"description":"DNS servers used for the lookup","example":["8.8.8.8","8.8.4.4"]},"domain":{"type":"string","description":"Domain name that was queried","example":"example.com"},"records":{"type":"array","items":{"type":"string"},"description":"List of A record IP addresses","example":["93.184.216.34"]}}},"DnsProviderCredentials":{"oneOf":[{"type":"object","required":["api_token","type"],"properties":{"account_id":{"type":["string","null"]},"api_token":{"type":"string","example":"your-api-token"},"type":{"type":"string","enum":["cloudflare"]}}},{"type":"object","required":["api_user","api_key","type"],"properties":{"api_key":{"type":"string","example":"your-api-key"},"api_user":{"type":"string","example":"your-username"},"client_ip":{"type":["string","null"]},"sandbox":{"type":"boolean"},"type":{"type":"string","enum":["namecheap"]}}},{"type":"object","required":["access_key_id","secret_access_key","type"],"properties":{"access_key_id":{"type":"string","example":"AKIAIOSFODNN7EXAMPLE"},"region":{"type":["string","null"],"example":"us-east-1"},"secret_access_key":{"type":"string","example":"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"},"session_token":{"type":["string","null"]},"type":{"type":"string","enum":["route53"]}}},{"type":"object","required":["api_token","type"],"properties":{"api_token":{"type":"string","example":"dop_v1_your-token"},"type":{"type":"string","enum":["digitalocean"]}}},{"type":"object","required":["service_account_email","private_key","project_id","type"],"properties":{"private_key":{"type":"string","example":"-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"},"project_id":{"type":"string","example":"my-gcp-project"},"service_account_email":{"type":"string","example":"dns-admin@myproject.iam.gserviceaccount.com"},"type":{"type":"string","enum":["gcp"]}}},{"type":"object","required":["tenant_id","client_id","client_secret","subscription_id","resource_group","type"],"properties":{"client_id":{"type":"string","example":"00000000-0000-0000-0000-000000000000"},"client_secret":{"type":"string"},"resource_group":{"type":"string","example":"my-resource-group"},"subscription_id":{"type":"string","example":"00000000-0000-0000-0000-000000000000"},"tenant_id":{"type":"string","example":"00000000-0000-0000-0000-000000000000"},"type":{"type":"string","enum":["azure"]}}},{"type":"object","description":"Pebble challtestsrv mock DNS (LOCAL DEV/TEST ONLY)","required":["management_url","type"],"properties":{"management_url":{"type":"string","example":"http://localhost:8055"},"type":{"type":"string","enum":["pebble"]}}}],"description":"DNS provider credentials (API-facing)"},"DnsProviderResponse":{"type":"object","description":"DNS provider response","required":["id","name","provider_type","credentials","is_active","flat_hostnames_supported","created_at","updated_at"],"properties":{"created_at":{"type":"string"},"credentials":{"description":"Masked credentials for display"},"description":{"type":["string","null"]},"flat_hostnames_supported":{"type":"boolean","description":"Whether this provider benefits from the flat hostname mode (e.g. Cloudflare\nUniversal SSL). The UI surfaces/recommends the Flat toggle when true."},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"last_error":{"type":["string","null"]},"last_used_at":{"type":["string","null"]},"name":{"type":"string"},"provider_type":{"type":"string"},"updated_at":{"type":"string"}}},"DnsProviderSettings":{"type":"object","properties":{"cloudflare_api_key":{"type":["string","null"],"default":null},"provider":{"type":"string","default":"manual"}}},"DnsProviderSettingsMasked":{"type":"object","description":"DNS provider settings with masked sensitive fields","required":["provider"],"properties":{"cloudflare_api_key":{"type":["string","null"]},"provider":{"type":"string"}}},"DnsProviderType":{"type":"string","description":"Supported DNS provider types","enum":["cloudflare","namecheap","route53","digitalocean","gcp","azure","manual","pebble"]},"DnsRecord":{"type":"object","description":"A DNS record","required":["zone","name","fqdn","content","ttl"],"properties":{"content":{"$ref":"#/components/schemas/DnsRecordContent","description":"Record content"},"fqdn":{"type":"string","description":"Fully qualified domain name","example":"www.example.com"},"id":{"type":["string","null"],"description":"Provider-specific record ID (if exists)","example":"abc123"},"metadata":{"type":"object","description":"Provider-specific metadata","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":"string","description":"Record name (without zone, e.g., \"www\" or \"@\" for root)","example":"www"},"proxied":{"type":"boolean","description":"Whether this record is proxied (Cloudflare-specific)"},"ttl":{"type":"integer","format":"int32","description":"Time to live in seconds","example":300,"minimum":0},"zone":{"type":"string","description":"Zone/domain this record belongs to","example":"example.com"}}},"DnsRecordChange":{"type":"object","description":"A single DNS record change the Cloudflare sync would make.","required":["action","name","record_type","value"],"properties":{"action":{"type":"string","description":"`\"create\"`, `\"update\"`, or `\"delete\"`."},"name":{"type":"string"},"record_type":{"type":"string","description":"Record type, e.g. `\"A\"` or `\"CNAME\"`."},"value":{"type":"string"}}},"DnsRecordContent":{"oneOf":[{"type":"object","description":"A record - IPv4 address (as string, e.g., \"192.0.2.1\")","required":["value","type"],"properties":{"type":{"type":"string","enum":["A"]},"value":{"type":"object","description":"A record - IPv4 address (as string, e.g., \"192.0.2.1\")","required":["address"],"properties":{"address":{"type":"string","example":"192.0.2.1"}}}}},{"type":"object","description":"AAAA record - IPv6 address (as string, e.g., \"2001:db8::1\")","required":["value","type"],"properties":{"type":{"type":"string","enum":["AAAA"]},"value":{"type":"object","description":"AAAA record - IPv6 address (as string, e.g., \"2001:db8::1\")","required":["address"],"properties":{"address":{"type":"string","example":"2001:db8::1"}}}}},{"type":"object","description":"CNAME record - canonical name","required":["value","type"],"properties":{"type":{"type":"string","enum":["CNAME"]},"value":{"type":"object","description":"CNAME record - canonical name","required":["target"],"properties":{"target":{"type":"string"}}}}},{"type":"object","description":"TXT record - text content","required":["value","type"],"properties":{"type":{"type":"string","enum":["TXT"]},"value":{"type":"object","description":"TXT record - text content","required":["content"],"properties":{"content":{"type":"string"}}}}},{"type":"object","description":"MX record - mail exchange","required":["value","type"],"properties":{"type":{"type":"string","enum":["MX"]},"value":{"type":"object","description":"MX record - mail exchange","required":["priority","target"],"properties":{"priority":{"type":"integer","format":"int32","minimum":0},"target":{"type":"string"}}}}},{"type":"object","description":"NS record - nameserver","required":["value","type"],"properties":{"type":{"type":"string","enum":["NS"]},"value":{"type":"object","description":"NS record - nameserver","required":["nameserver"],"properties":{"nameserver":{"type":"string"}}}}},{"type":"object","description":"SRV record - service","required":["value","type"],"properties":{"type":{"type":"string","enum":["SRV"]},"value":{"type":"object","description":"SRV record - service","required":["priority","weight","port","target"],"properties":{"port":{"type":"integer","format":"int32","minimum":0},"priority":{"type":"integer","format":"int32","minimum":0},"target":{"type":"string"},"weight":{"type":"integer","format":"int32","minimum":0}}}}},{"type":"object","description":"CAA record - certification authority authorization","required":["value","type"],"properties":{"type":{"type":"string","enum":["CAA"]},"value":{"type":"object","description":"CAA record - certification authority authorization","required":["flags","tag","value"],"properties":{"flags":{"type":"integer","format":"int32","minimum":0},"tag":{"type":"string"},"value":{"type":"string"}}}}},{"type":"object","description":"PTR record - pointer","required":["value","type"],"properties":{"type":{"type":"string","enum":["PTR"]},"value":{"type":"object","description":"PTR record - pointer","required":["target"],"properties":{"target":{"type":"string"}}}}}],"description":"DNS record content - varies by record type"},"DnsRecordResponse":{"type":"object","required":["record_type","name","value","status"],"properties":{"name":{"type":"string","description":"DNS record name (host)","example":"temps._domainkey.example.com"},"priority":{"type":["integer","null"],"format":"int32","description":"Priority (for MX records)","example":"10","minimum":0},"record_type":{"type":"string","description":"Record type: TXT, CNAME, MX","example":"TXT"},"status":{"$ref":"#/components/schemas/DnsRecordStatusResponse","description":"Verification status: unknown, verified, pending, failed"},"value":{"type":"string","description":"DNS record value","example":"v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3..."}}},"DnsRecordSetupResult":{"type":"object","description":"Result of a single DNS record creation","required":["record_type","name","success","automatic","message"],"properties":{"automatic":{"type":"boolean","description":"Whether the operation was automatic or manual"},"message":{"type":"string","description":"Human-readable message"},"name":{"type":"string","description":"Record name"},"record_type":{"type":"string","description":"Record type (TXT, CNAME, MX)"},"success":{"type":"boolean","description":"Whether the record was created successfully"}}},"DnsRecordStatusResponse":{"type":"string","description":"DNS record verification status","enum":["unknown","verified","pending","failed"]},"DnsZone":{"type":"object","description":"A DNS zone (domain managed by the provider)","required":["id","name","status","nameservers"],"properties":{"id":{"type":"string","description":"Provider-specific zone ID","example":"zone123"},"metadata":{"type":"object","description":"Provider-specific metadata","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":"string","description":"Zone name (domain)","example":"example.com"},"nameservers":{"type":"array","items":{"type":"string"},"description":"Nameservers for this zone"},"status":{"type":"string","description":"Zone status","example":"active"}}},"DockerComposePresetConfig":{"type":"object","description":"Configuration for Docker Compose deployments.","properties":{"composeOverride":{"type":["string","null"],"description":"User-provided docker-compose.override.yml content."},"composePath":{"type":["string","null"],"description":"Path to the Compose file relative to the project directory."},"publicPorts":{"type":"array","items":{"$ref":"#/components/schemas/ComposePublicPort"},"description":"Compose service ports that should be publicly routed."}}},"DockerRegistrySettings":{"type":"object","properties":{"ca_certificate":{"type":["string","null"],"default":null},"enabled":{"type":"boolean","default":false},"password":{"type":["string","null"],"default":null},"registry_url":{"type":["string","null"],"default":null},"tls_verify":{"type":"boolean","default":true},"username":{"type":["string","null"],"default":null}}},"DockerRegistrySettingsMasked":{"type":"object","description":"Docker registry settings with masked sensitive fields","required":["enabled","tls_verify"],"properties":{"ca_certificate":{"type":["string","null"]},"enabled":{"type":"boolean"},"password":{"type":["string","null"]},"registry_url":{"type":["string","null"]},"tls_verify":{"type":"boolean"},"username":{"type":["string","null"]}}},"DockerfilePresetConfig":{"type":"object","description":"Configuration for Dockerfile preset\nAllows customizing the Dockerfile path and build context for Docker-based deployments","properties":{"buildContext":{"type":["string","null"],"description":"Custom build context path (relative to repository root)\nIf not specified, uses the project's directory setting","example":"./api"},"dockerfilePath":{"type":["string","null"],"description":"Custom Dockerfile path (relative to build context)\nIf not specified, defaults to \"Dockerfile\" in the build context","example":"docker/Dockerfile"},"variant":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DockerfileVariant","description":"Catalog variant. Normally omitted; `custom` selects the generated\nDockerfile compatibility preset."}]}}},"DockerfileVariant":{"type":"string","description":"Catalog variant persisted under the canonical Dockerfile preset.\n\nExisting rows predate this discriminator and therefore deserialize as\n[`DockerfileVariant::File`].","enum":["file","custom"]},"DomainAction":{"type":"string","description":"What to do with a domain during migration","enum":["import","skip"]},"DomainChallengeResponse":{"type":"object","required":["domain","txt_records","status"],"properties":{"domain":{"type":"string"},"status":{"type":"string"},"txt_records":{"type":"array","items":{"$ref":"#/components/schemas/TxtRecord"},"description":"Array of TXT records to add to DNS. For wildcards, multiple records are required."}}},"DomainEnvironmentResponse":{"type":"object","required":["id","name","slug"],"properties":{"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"slug":{"type":"string"}}},"DomainError":{"type":"object","required":["message","code"],"properties":{"code":{"type":"string"},"details":{"type":["string","null"]},"message":{"type":"string"}}},"DomainPlan":{"type":"object","description":"Plan for migrating a single custom domain","required":["domain","environment","action","action_description"],"properties":{"action":{"$ref":"#/components/schemas/DomainAction","description":"What to do with this domain"},"action_description":{"type":"string","description":"Human-readable explanation"},"domain":{"type":"string","description":"Full domain name"},"environment":{"type":"string","description":"Which environment to associate with (\"production\")"},"redirect_to":{"type":["string","null"],"description":"Redirect target (if this is a redirect domain)"},"replacement":{"type":["string","null"],"description":"The temps-side address that replaces this domain when it is skipped.\n\nSource-generated domains (sslip.io / traefik.me / platform subdomains)\nembed the source server's IP and would keep pointing at the old\nmachine — this tells the user where the app will be reachable on\ntemps instead."},"status_code":{"type":["integer","null"],"format":"int32","description":"Redirect status code"}}},"DomainResponse":{"type":"object","required":["id","domain","status","is_wildcard","verification_method","created_at","updated_at"],"properties":{"certificate":{"type":["string","null"],"description":"The PEM-encoded certificate chain (can be displayed in browser or downloaded)"},"created_at":{"type":"integer","format":"int64"},"dns_challenge_token":{"type":["string","null"]},"dns_challenge_value":{"type":["string","null"]},"domain":{"type":"string"},"expiration_time":{"type":["integer","null"],"format":"int64"},"id":{"type":"integer","format":"int32"},"is_wildcard":{"type":"boolean"},"last_error":{"type":["string","null"]},"last_error_type":{"type":["string","null"]},"last_renewed":{"type":["integer","null"],"format":"int64"},"on_demand_backoff_until":{"type":["integer","null"],"format":"int64","description":"On-demand TLS negative-cache deadline (epoch millis), when this hostname's\non-demand HTTP-01 issuance is in backoff after a failure (ADR-018 §4).\n`None` means no active backoff."},"status":{"type":"string"},"updated_at":{"type":"integer","format":"int64"},"verification_method":{"type":"string"}}},"DrainNodeResponse":{"type":"object","required":["id","name","status","affected_environments","message"],"properties":{"affected_environments":{"type":"integer","minimum":0},"id":{"type":"integer","format":"int32"},"message":{"type":"string"},"name":{"type":"string"},"status":{"type":"string"}}},"DrainStatusResponse":{"type":"object","description":"Progress of a node drain operation.","required":["node_id","node_name","status","remaining_containers","drain_complete","can_remove","message"],"properties":{"can_remove":{"type":"boolean","description":"Can the node be safely removed?"},"drain_complete":{"type":"boolean","description":"Whether the drain is complete (all containers migrated)"},"message":{"type":"string"},"node_id":{"type":"integer","format":"int32"},"node_name":{"type":"string"},"remaining_containers":{"type":"integer","description":"Number of containers still on this node","minimum":0},"status":{"type":"string"}}},"DropArchiveUpload":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary"}}},"DropInspectionResponse":{"type":"object","required":["suggestedName","candidates"],"properties":{"candidates":{"type":"array","items":{"$ref":"#/components/schemas/DropPresetCandidate"}},"suggestedName":{"type":"string"}}},"DropOffPoint":{"type":"object","description":"Drop-off point: pages where visitors leave the site","required":["page_path","exit_count","total_views","exit_rate"],"properties":{"exit_count":{"type":"integer","format":"int64","description":"Number of exits from this page"},"exit_rate":{"type":"number","format":"double","description":"Exit rate for this page (exit_count / total_views)"},"page_path":{"type":"string","description":"The page path where visitors drop off"},"total_views":{"type":"integer","format":"int64","description":"Total views of this page"}}},"DropPresetCandidate":{"type":"object","required":["directory","preset","label","confidence","reason","isStatic"],"properties":{"confidence":{"type":"string"},"directory":{"type":"string"},"isStatic":{"type":"boolean"},"label":{"type":"string"},"preset":{"type":"string"},"reason":{"type":"string"}}},"EmailConfig":{"type":"object","required":["smtp_host","smtp_port","username","password","from_address","to_addresses"],"properties":{"accept_invalid_certs":{"type":"boolean"},"from_address":{"type":"string"},"from_name":{"type":["string","null"]},"password":{"type":"string"},"smtp_host":{"type":"string"},"smtp_port":{"type":"integer","format":"int32","minimum":0},"starttls_required":{"type":"boolean"},"tls_mode":{"$ref":"#/components/schemas/TlsMode"},"to_addresses":{"type":"array","items":{"type":"string"}},"username":{"type":"string"}}},"EmailDomainResponse":{"type":"object","required":["id","provider_id","domain","status","created_at","updated_at"],"properties":{"created_at":{"type":"string","example":"2025-12-03T10:30:00Z"},"domain":{"type":"string","example":"updates.example.com"},"id":{"type":"integer","format":"int32"},"last_verified_at":{"type":["string","null"]},"provider_id":{"type":"integer","format":"int32"},"status":{"type":"string","example":"verified"},"updated_at":{"type":"string","example":"2025-12-03T10:30:00Z"},"verification_error":{"type":["string","null"]}}},"EmailDomainWithDnsResponse":{"type":"object","required":["domain","dns_records"],"properties":{"dns_records":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecordResponse"}},"domain":{"$ref":"#/components/schemas/EmailDomainResponse"}}},"EmailProviderResponse":{"type":"object","required":["id","name","provider_type","region","is_active","credentials","created_at","updated_at"],"properties":{"created_at":{"type":"string","example":"2025-12-03T10:30:00Z"},"credentials":{"description":"Masked credentials for display"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"name":{"type":"string","example":"My AWS SES"},"provider_type":{"$ref":"#/components/schemas/EmailProviderTypeRoute"},"region":{"type":"string","example":"us-east-1"},"sns_topic_arn":{"type":["string","null"]},"updated_at":{"type":"string","example":"2025-12-03T10:30:00Z"}}},"EmailProviderTypeRoute":{"type":"string","enum":["ses","scaleway","smtp"]},"EmailRequest":{"type":"object","description":"Request body carrying just an email address (password-reset request).","required":["email"],"properties":{"email":{"type":"string"}}},"EmailResponse":{"type":"object","required":["id","from_address","to_addresses","subject","status","created_at","track_opens","track_clicks","open_count","click_count"],"properties":{"bcc_addresses":{"type":["array","null"],"items":{"type":"string"}},"cc_addresses":{"type":["array","null"],"items":{"type":"string"}},"click_count":{"type":"integer","format":"int32","description":"Number of times links in the email were clicked"},"created_at":{"type":"string","example":"2025-12-03T10:30:00Z"},"domain_id":{"type":["integer","null"],"format":"int32"},"error_message":{"type":["string","null"]},"first_clicked_at":{"type":["string","null"],"description":"When a link was first clicked"},"first_opened_at":{"type":["string","null"],"description":"When the email was first opened"},"from_address":{"type":"string","example":"hello@updates.example.com"},"from_name":{"type":["string","null"]},"headers":{"type":["object","null"],"additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"html_body":{"type":["string","null"]},"id":{"type":"string","example":"550e8400-e29b-41d4-a716-446655440000"},"open_count":{"type":"integer","format":"int32","description":"Number of times the email was opened"},"project_id":{"type":["integer","null"],"format":"int32"},"provider_message_id":{"type":["string","null"]},"reply_to":{"type":["string","null"]},"sent_at":{"type":["string","null"]},"status":{"type":"string","example":"sent"},"subject":{"type":"string"},"tags":{"type":["array","null"],"items":{"type":"string"}},"text_body":{"type":["string","null"]},"to_addresses":{"type":"array","items":{"type":"string"}},"track_clicks":{"type":"boolean","description":"Whether click tracking is enabled"},"track_opens":{"type":"boolean","description":"Whether open tracking is enabled"},"tracked_html_body":{"type":["string","null"],"description":"The final HTML sent to the provider (with tracking pixel and rewritten links)"}}},"EmailStatsResponse":{"type":"object","required":["total","sent","failed","queued","captured"],"properties":{"captured":{"type":"integer","format":"int64","description":"Emails captured without sending (Mailhog mode - no provider configured)","minimum":0},"failed":{"type":"integer","format":"int64","minimum":0},"queued":{"type":"integer","format":"int64","minimum":0},"sent":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"EmailStatusResponse":{"type":"object","required":["email_configured","password_reset_available","oidc_providers"],"properties":{"email_configured":{"type":"boolean"},"oidc_providers":{"type":"array","items":{"$ref":"#/components/schemas/OidcProviderSummary"}},"password_reset_available":{"type":"boolean"}}},"EmailTrackingResponse":{"type":"object","description":"Email tracking summary","required":["email_id","track_opens","track_clicks","open_count","click_count","unique_opens","unique_clicks","links"],"properties":{"click_count":{"type":"integer","format":"int32"},"email_id":{"type":"string"},"first_clicked_at":{"type":["string","null"]},"first_opened_at":{"type":["string","null"]},"links":{"type":"array","items":{"$ref":"#/components/schemas/TrackedLinkResponse"}},"open_count":{"type":"integer","format":"int32"},"track_clicks":{"type":"boolean"},"track_opens":{"type":"boolean"},"unique_clicks":{"type":"integer","format":"int64","minimum":0},"unique_opens":{"type":"integer","format":"int64","minimum":0}}},"EmailTrackingSetupResponse":{"type":"object","description":"Result of the one-click AWS-side event-tracking setup.","required":["topic_arn","webhook_url","subscription_requested","event_destination_attached"],"properties":{"event_destination_attached":{"type":"boolean","description":"The SESv2 event destination (bounce/complaint/delivery) is attached\nto the `temps-tracking` configuration set."},"subscription_requested":{"type":"boolean","description":"The webhook subscription was requested; SNS confirms it\nasynchronously through the webhook itself."},"topic_arn":{"type":"string","example":"arn:aws:sns:us-east-1:123456789012:temps-email-events-1"},"webhook_url":{"type":"string"}}},"EmailTrackingStatusResponse":{"type":"object","description":"Live status of the SES event-tracking pipeline for one provider.","required":["webhook_url","supports_event_tracking"],"properties":{"last_event_at":{"type":["string","null"],"description":"Most recent delivered/bounced/complained event recorded for an email\nsent through this provider. `null` means no provider feedback has\narrived yet.","example":"2026-07-18T10:31:00Z"},"sns_topic_arn":{"type":["string","null"]},"subscription_confirmed_at":{"type":["string","null"],"description":"When the SNS subscription for the current topic was confirmed.\n`null` with a topic set usually means the subscription is still\npending — most often because the endpoint was subscribed before the\ntopic ARN was saved here.","example":"2026-07-18T10:30:00Z"},"supports_event_tracking":{"type":"boolean","description":"Only SES providers support SNS event tracking."},"webhook_url":{"type":"string","description":"Public webhook endpoint SNS must deliver events to.","example":"https://temps.example.com/api/t/webhook/ses"}}},"EmbeddingData":{"type":"object","required":["object","embedding","index"],"properties":{"embedding":{"type":"array","items":{"type":"number","format":"double"}},"index":{"type":"integer","format":"int32"},"object":{"type":"string"}}},"EmbeddingInput":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"EmbeddingRequest":{"type":"object","required":["model","input"],"properties":{"dimensions":{"type":["integer","null"],"format":"int32"},"encoding_format":{"type":["string","null"]},"input":{"$ref":"#/components/schemas/EmbeddingInput"},"model":{"type":"string"}}},"EmbeddingResponse":{"type":"object","required":["object","data","model","usage"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/EmbeddingData"}},"model":{"type":"string"},"object":{"type":"string"},"usage":{"$ref":"#/components/schemas/EmbeddingUsage"}}},"EmbeddingUsage":{"type":"object","required":["prompt_tokens","total_tokens"],"properties":{"prompt_tokens":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"EnableBlobRequest":{"type":"object","description":"Request to enable Blob service","properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use (optional, defaults to RustFS)","example":"ghcr.io/rustfs/rustfs:0.5.0"},"root_password":{"type":["string","null"],"description":"Root password for S3 access"},"root_user":{"type":["string","null"],"description":"Root user for S3 access"}}},"EnableBlobResponse":{"type":"object","description":"Response after enabling Blob service","required":["success","message","status"],"properties":{"message":{"type":"string","description":"Human-readable message","example":"Blob service enabled successfully"},"status":{"$ref":"#/components/schemas/BlobStatusResponse","description":"Current status"},"success":{"type":"boolean","description":"Whether the operation succeeded","example":true}}},"EnableKvRequest":{"type":"object","description":"Request to enable the KV service","properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use (optional, uses default if not provided)","example":"gotempsh/redis-walg:8-bookworm"},"max_memory":{"type":["string","null"],"description":"Maximum memory allocation (e.g., \"256mb\", \"1gb\")","example":"256mb"},"persistence":{"type":"boolean","description":"Enable data persistence"}}},"EnableKvResponse":{"type":"object","description":"Response after enabling KV service","required":["success","message","status"],"properties":{"message":{"type":"string","description":"Status message","example":"KV service enabled successfully"},"status":{"$ref":"#/components/schemas/KvStatusResponse","description":"Current service status"},"success":{"type":"boolean","description":"Whether the service was successfully enabled"}}},"EnablePgStatStatementsResponse":{"type":"object","description":"Response for the enable pg_stat_statements endpoint.","required":["message"],"properties":{"message":{"type":"string","description":"Human-readable message confirming the action."}}},"EndpointDto":{"type":"object","description":"One DNS record on the wire. Mirrors `service_endpoints::Model` but\nkeeps the API stable across entity evolution. `target_ip` is a string\n(v4 or v6 literal, or CNAME target hostname) parsed by the resolver.","required":["id","fqdn","record_type","ttl","owner_kind","owner_id","generation"],"properties":{"fqdn":{"type":"string"},"generation":{"type":"integer","format":"int64"},"id":{"type":"integer","format":"int64"},"node_id":{"type":["integer","null"],"format":"int32"},"owner_id":{"type":"integer","format":"int64"},"owner_kind":{"type":"string"},"record_type":{"type":"string"},"target_ip":{"type":["string","null"]},"target_port":{"type":["integer","null"],"format":"int32"},"ttl":{"type":"integer","format":"int32"}}},"EnqueuedJob":{"type":"object","description":"A single job that was successfully enqueued during a fan-out run.","required":["backup_id","job_id","engine"],"properties":{"backup_id":{"type":"integer","format":"int32","description":"FK to `backups.id` for this job."},"engine":{"type":"string","description":"Engine key (e.g. `\"control_plane\"`, `\"redis\"`, `\"postgres_pgdump\"`)."},"job_id":{"type":"integer","format":"int64","description":"FK to `backup_jobs.id` for this job."},"target_service_id":{"type":["integer","null"],"format":"int32","description":"FK to `external_services.id` when this is an external-service job.\n`None` for the control-plane job."}}},"EnrichVisitorRequest":{"type":"object","required":["custom_data"],"properties":{"custom_data":{"type":"object"}}},"EnrichVisitorResponse":{"type":"object","required":["success","visitor_id","message"],"properties":{"message":{"type":"string"},"success":{"type":"boolean"},"visitor_id":{"type":"string"}}},"EnrollmentTokenInfo":{"type":"object","required":["id","expires_at","used_count","max_uses","created_at"],"properties":{"bound_node_name":{"type":["string","null"]},"created_at":{"type":"string"},"expires_at":{"type":"string"},"id":{"type":"integer","format":"int32"},"max_uses":{"type":"integer","format":"int32"},"used_count":{"type":"integer","format":"int32"}}},"EnrollmentTokenListResponse":{"type":"object","required":["tokens"],"properties":{"tokens":{"type":"array","items":{"$ref":"#/components/schemas/EnrollmentTokenInfo"}}}},"EntityInfoResponse":{"type":"object","required":["container_path","entity","entity_type","fields"],"properties":{"container_path":{"type":"array","items":{"type":"string"},"description":"Full container path","example":["mydb","public"]},"entity":{"type":"string","description":"Entity name","example":"users"},"entity_type":{"type":"string","description":"Entity type","example":"table"},"fields":{"type":"array","items":{"$ref":"#/components/schemas/FieldResponse"},"description":"Field definitions"},"metadata":{"description":"Additional metadata (content_type, last_modified, etag, etc.)"},"row_count":{"type":["integer","null"],"description":"Approximate row count (for tables/collections)","example":1234,"minimum":0},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size in bytes (for objects/files)","example":1048576,"minimum":0},"sort_schema":{"description":"JSON Schema for sort options (if supported)"}}},"EntityResponse":{"type":"object","required":["name","entity_type"],"properties":{"entity_type":{"type":"string","description":"Entity type (table, view, collection, etc.)","example":"table"},"name":{"type":"string","description":"Entity name (table/collection)","example":"users"},"row_count":{"type":["integer","null"],"description":"Approximate row count","example":1234,"minimum":0},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size in bytes (for files/objects)","example":1048576,"minimum":0}}},"EnvVarInput":{"type":"object","description":"Input for environment variable","required":["name","value"],"properties":{"name":{"type":"string","description":"Variable name"},"value":{"type":"string","description":"Variable value"}}},"EnvVarIntegrationInfo":{"type":"object","required":["service_id","service_name","service_type","service_updated_at"],"properties":{"service_id":{"type":"integer","format":"int32"},"service_name":{"type":"string"},"service_slug":{"type":["string","null"]},"service_type":{"type":"string"},"service_updated_at":{"type":"string"}}},"EnvVarResponse":{"type":"object","description":"Environment variable with masked sensitive values","required":["key","value","is_masked"],"properties":{"is_masked":{"type":"boolean","description":"Whether this is a sensitive/masked value"},"key":{"type":"string"},"value":{"type":"string"}}},"EnvVarTemplateResponse":{"type":"object","description":"Environment variable template response","required":["name","required"],"properties":{"default":{"type":["string","null"],"description":"Default value if not provided by user"},"default_generator":{"type":["string","null"],"description":"Frontend-side generator hint for the default value\n(e.g. `app_url`, `random_secret`, `random_hex_32`)"},"description":{"type":["string","null"],"description":"Description of what this variable is used for"},"example":{"type":["string","null"],"description":"Example value for documentation"},"name":{"type":"string","description":"Name of the environment variable"},"required":{"type":"boolean","description":"Whether this variable is required"}}},"EnvironmentConfiguration":{"type":"object","description":"Environment-level configuration","required":["name","subdomain","resources"],"properties":{"name":{"type":"string","description":"Environment name"},"resources":{"$ref":"#/components/schemas/ResourceLimits","description":"Resource limits for environment"},"subdomain":{"type":"string","description":"Proposed subdomain"}}},"EnvironmentDomainResponse":{"type":"object","required":["id","environment_id","domain","created_at","url"],"properties":{"created_at":{"type":"integer","format":"int64"},"domain":{"type":"string"},"environment_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"url":{"type":"string","description":"Full URL for this domain (e.g., https://buildtolearndev-production.example.com)","example":"https://buildtolearndev-production.example.com"}}},"EnvironmentInfo":{"type":"object","required":["id","name","main_url"],"properties":{"current_deployment_id":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"main_url":{"type":"string"},"name":{"type":"string"}}},"EnvironmentResponse":{"type":"object","required":["id","project_id","name","slug","main_url","subdomain","created_at","updated_at","is_preview","protected","sleeping"],"properties":{"attack_mode":{"type":["boolean","null"],"description":"Per-environment CAPTCHA attack-mode override.\n`null` means inherit the project-level `attack_mode`; `true`/`false`\nexplicitly enable/disable the challenge for this environment. Always\nserialized (NOT skipped) so the UI can distinguish `null` from `false`."},"branch":{"type":["string","null"]},"created_at":{"type":"integer","format":"int64"},"current_deployment_id":{"type":["integer","null"],"format":"int32"},"deployment_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DeploymentConfig","description":"Deployment configuration for this environment (overrides project-level config)"}]},"estimated_sleep_at":{"type":["integer","null"],"format":"int64","description":"Estimated time (epoch millis) when the environment will go to sleep\nbased on last activity + idle timeout. NULL when sleeping or on-demand disabled."},"force_https":{"type":["boolean","null"],"description":"Per-environment HTTP→HTTPS redirect override.\n`null` means inherit the proxy default (redirect only when the host has\nan active TLS certificate); `true` always redirects plain HTTP for this\nenvironment, `false` never does. Always serialized (NOT skipped) so the\nUI can distinguish `null` from `false`."},"id":{"type":"integer","format":"int32"},"is_preview":{"type":"boolean","description":"Indicates if this is a preview environment (auto-created per branch)\nFor preview environments, 'branch' contains the feature branch name"},"last_activity_at":{"type":["integer","null"],"format":"int64","description":"Last proxied request timestamp (epoch millis) for on-demand environments.\nNULL when on-demand is disabled or no traffic has been received yet."},"main_url":{"type":"string"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"protected":{"type":"boolean","description":"When true, git pushes do NOT auto-deploy to this environment.\nDeployments must be promoted from another environment."},"sleeping":{"type":"boolean","description":"When true, the environment's containers are currently stopped due to\ninactivity (on-demand mode) and will start on the next request."},"slug":{"type":"string"},"subdomain":{"type":"string","description":"The host label stored for this environment (e.g.\n`myproject-production`). This is the prefix that is combined with the\nplatform's preview domain at request time to produce `main_url`. Edit\nthis via the rename-subdomain endpoint, not the full URL."},"updated_at":{"type":"integer","format":"int64"}}},"EnvironmentVariable":{"type":"object","description":"Environment variable","required":["key","value","is_secret"],"properties":{"is_secret":{"type":"boolean","description":"Whether this is a secret (should be encrypted)"},"key":{"type":"string","description":"Variable name"},"source_description":{"type":["string","null"],"description":"Where this env var originates from (for traceability)"},"value":{"type":"string","description":"Variable value (may be redacted for secrets)"}}},"EnvironmentVariableInfo":{"type":"object","required":["name","value","sensitive"],"properties":{"name":{"type":"string"},"sensitive":{"type":"boolean","description":"Whether this variable contains sensitive data (passwords, keys, tokens)","example":false},"value":{"type":"string"}}},"EnvironmentVariableResponse":{"type":"object","required":["id","key","created_at","updated_at","environments","include_in_preview","is_secret"],"properties":{"created_at":{"type":"integer","format":"int64"},"environments":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentInfo"}},"id":{"type":"integer","format":"int32"},"include_in_preview":{"type":"boolean","description":"Include this environment variable in preview environments"},"is_secret":{"type":"boolean","description":"Whether the variable is a write-only secret. Secrets always have\n`value: None` in responses."},"key":{"type":"string"},"updated_at":{"type":"integer","format":"int64"},"value":{"type":["string","null"],"description":"Plaintext value for non-secret vars (or `\"***\"` mask for list responses).\n`None` for secret vars — secrets are write-only."}}},"EnvironmentVariableValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"ErrorDashboardStatsQuery":{"type":"object","required":["start_time","end_time"],"properties":{"compare_to_previous":{"type":["boolean","null"]},"end_time":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"start_time":{"type":"string","format":"date-time"}}},"ErrorDashboardStatsResponse":{"type":"object","required":["total_errors","total_errors_previous_period","total_errors_change_percent","error_groups","error_groups_previous_period","start_time","end_time"],"properties":{"comparison_end_time":{"type":["string","null"],"format":"date-time"},"comparison_start_time":{"type":["string","null"],"format":"date-time"},"end_time":{"type":"string","format":"date-time"},"error_groups":{"type":"integer","format":"int64"},"error_groups_previous_period":{"type":"integer","format":"int64"},"start_time":{"type":"string","format":"date-time"},"total_errors":{"type":"integer","format":"int64"},"total_errors_change_percent":{"type":"number","format":"double"},"total_errors_previous_period":{"type":"integer","format":"int64"}}},"ErrorEventResponse":{"type":"object","required":["id","error_group_id","timestamp","created_at"],"properties":{"created_at":{"type":"string"},"data":{"description":"Full error event data (contains raw Sentry event or custom error data)"},"error_group_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int64"},"source":{"type":["string","null"],"description":"Source of the error event (e.g., \"sentry\", \"custom\", \"bugsnag\")"},"timestamp":{"type":"string"}}},"ErrorGroupResponse":{"type":"object","required":["id","title","error_type","first_seen","last_seen","total_count","status","project_id","created_at","updated_at"],"properties":{"assigned_to":{"type":["string","null"]},"created_at":{"type":"string"},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_type":{"type":"string"},"first_seen":{"type":"string"},"id":{"type":"integer","format":"int32"},"last_seen":{"type":"string"},"message_template":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"status":{"type":"string"},"title":{"type":"string"},"total_count":{"type":"integer","format":"int32"},"updated_at":{"type":"string"},"visitor_id":{"type":["integer","null"],"format":"int32"}}},"ErrorGroupStatsResponse":{"type":"object","required":["total_groups","unresolved_groups","resolved_groups","ignored_groups"],"properties":{"ignored_groups":{"type":"integer","format":"int64"},"resolved_groups":{"type":"integer","format":"int64"},"total_groups":{"type":"integer","format":"int64"},"unresolved_groups":{"type":"integer","format":"int64"}}},"ErrorResponse":{"type":"object","required":["error"],"properties":{"details":{"type":["string","null"]},"error":{"type":"string"}}},"ErrorRow":{"type":"object","required":["id","ts","error_group_id","fingerprint","error_class","stacktrace_preview","stacktrace_truncated"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_class":{"type":"string"},"error_group_id":{"type":"integer","format":"int32"},"fingerprint":{"type":"string"},"id":{"type":"integer","format":"int64"},"message":{"type":["string","null"]},"stacktrace_preview":{},"stacktrace_truncated":{"type":"boolean"},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"}}},"ErrorTimeSeriesDataResponse":{"type":"object","required":["timestamp","count"],"properties":{"count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"}}},"ErrorTimeSeriesQuery":{"type":"object","required":["start_time","end_time"],"properties":{"bucket":{"type":"string","description":"Time bucket size (e.g., \"1h\", \"15m\", \"1d\", \"1 hour\", \"30 minutes\")","example":"1h"},"end_time":{"type":"string","format":"date-time"},"start_time":{"type":"string","format":"date-time"}}},"EventActivityBucket":{"type":"object","description":"Time bucket data point for event activity graph","required":["timestamp","count","unique_visitors"],"properties":{"count":{"type":"integer","format":"int64","description":"Number of event occurrences in this bucket"},"timestamp":{"type":"string","description":"Timestamp for this bucket (ISO 8601)"},"unique_visitors":{"type":"integer","format":"int64","description":"Number of unique visitors in this bucket"}}},"EventBreakdown":{"type":"string","enum":["country","region","city"]},"EventBrowserStats":{"type":"object","description":"Browser stats for an event","required":["browser","count","percentage"],"properties":{"browser":{"type":"string","description":"Browser name"},"count":{"type":"integer","format":"int64","description":"Number of event occurrences from this browser"},"percentage":{"type":"number","format":"double","description":"Percentage of total events"}}},"EventCount":{"type":"object","required":["event_name","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"event_name":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"EventCountryStats":{"type":"object","description":"Country stats for an event","required":["country","count","percentage"],"properties":{"count":{"type":"integer","format":"int64","description":"Number of event occurrences from this country"},"country":{"type":"string","description":"Country name"},"country_code":{"type":["string","null"],"description":"ISO country code (2-letter)"},"percentage":{"type":"number","format":"double","description":"Percentage of total events"}}},"EventDetailQuery":{"type":"object","description":"Query parameters for event detail analytics","required":["event_name","project_id","start_date","end_date"],"properties":{"bucket_interval":{"type":["string","null"],"description":"Bucket interval for time series: 'hour', 'day', 'week', 'month' (default: auto)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_name":{"type":"string","description":"The specific event name to get details for"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventDetailResponse":{"type":"object","description":"Summary response for a specific event's analytics","required":["event_name","total_count","unique_visitors","unique_sessions","activity_over_time","referrers","countries","browsers","bucket_interval"],"properties":{"activity_over_time":{"type":"array","items":{"$ref":"#/components/schemas/EventActivityBucket"},"description":"Time series data for event activity graph"},"browsers":{"type":"array","items":{"$ref":"#/components/schemas/EventBrowserStats"},"description":"Browser distribution of visitors who triggered this event"},"bucket_interval":{"type":"string","description":"Bucket interval used for time series ('hour', 'day', etc.)"},"countries":{"type":"array","items":{"$ref":"#/components/schemas/EventCountryStats"},"description":"Geographic distribution of visitors who triggered this event"},"event_name":{"type":"string","description":"The event name being analyzed"},"referrers":{"type":"array","items":{"$ref":"#/components/schemas/EventReferrerStats"},"description":"Top referrer hostnames for visitors who triggered this event"},"total_count":{"type":"integer","format":"int64","description":"Total number of times this event was triggered in the date range"},"unique_sessions":{"type":"integer","format":"int64","description":"Number of unique sessions where this event occurred"},"unique_visitors":{"type":"integer","format":"int64","description":"Number of unique visitors who triggered this event"}}},"EventEntriesQuery":{"type":"object","description":"Query parameters for the raw event entries list","required":["event_name","project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_name":{"type":"string","description":"The specific event name to list occurrences for"},"page":{"type":["integer","null"],"format":"int64","description":"Page number (1-based, default: 1)","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","description":"Items per page (default: 20, max: 100)","minimum":0},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventEntriesResponse":{"type":"object","description":"Paginated response for raw event entries","required":["event_name","total_count","page","per_page","entries"],"properties":{"entries":{"type":"array","items":{"$ref":"#/components/schemas/EventEntryInfo"},"description":"Individual event occurrences, most recent first"},"event_name":{"type":"string","description":"The event name"},"page":{"type":"integer","format":"int64","description":"Current page number","minimum":0},"per_page":{"type":"integer","format":"int64","description":"Items per page","minimum":0},"total_count":{"type":"integer","format":"int64","description":"Total number of occurrences of this event in the date range"}}},"EventEntryInfo":{"type":"object","description":"A single raw occurrence of an event, including its custom JSON properties","required":["id","timestamp","page_path","href"],"properties":{"browser":{"type":["string","null"],"description":"Browser name"},"city":{"type":["string","null"],"description":"City of the visitor at the time of the event"},"country":{"type":["string","null"],"description":"Country of the visitor at the time of the event"},"country_code":{"type":["string","null"],"description":"ISO country code (2-letter)"},"device_type":{"type":["string","null"],"description":"Device type (Desktop, Mobile, Tablet)"},"href":{"type":"string","description":"Full URL where the event was triggered"},"id":{"type":"integer","format":"int64","description":"Event row ID"},"page_path":{"type":"string","description":"Page path where the event was triggered"},"props":{"type":["object","null"],"description":"Custom event properties as JSON (null when the event carried no data)"},"session_id":{"type":["string","null"],"description":"Session ID the event belongs to (if any)"},"timestamp":{"type":"string","format":"date-time","description":"When the event occurred"},"visitor_id":{"type":["integer","null"],"format":"int32","description":"Visitor numeric ID (if known)"},"visitor_uuid":{"type":["string","null"],"description":"Visitor UUID (if known)"}}},"EventKind":{"type":"string","description":"Tag enum for filter parameters and routing. Matches the variant\ndiscriminator used by `ObservabilityEvent`.","enum":["request","span","error","revenue"]},"EventMetricsPayload":{"type":"object","required":["event_name","event_data","request_path","request_query"],"properties":{"cls":{"type":["number","null"],"format":"float","description":"Cumulative Layout Shift (score)"},"event_data":{},"event_name":{"type":"string"},"fcp":{"type":["number","null"],"format":"float","description":"First Contentful Paint (milliseconds)"},"fid":{"type":["number","null"],"format":"float","description":"First Input Delay (milliseconds)"},"inp":{"type":["number","null"],"format":"float","description":"Interaction to Next Paint (milliseconds)"},"language":{"type":["string","null"]},"lcp":{"type":["number","null"],"format":"float","description":"Largest Contentful Paint (milliseconds)"},"page_title":{"type":["string","null"]},"referrer":{"type":["string","null"],"description":"Referrer URL (falls back to Referer header if not provided)"},"request_path":{"type":"string"},"request_query":{"type":"string"},"screen_height":{"type":["integer","null"],"format":"int32","minimum":0},"screen_width":{"type":["integer","null"],"format":"int32","minimum":0},"ttfb":{"type":["number","null"],"format":"float","description":"Time to First Byte (milliseconds)"},"viewport_height":{"type":["integer","null"],"format":"int32","minimum":0},"viewport_width":{"type":["integer","null"],"format":"int32","minimum":0}}},"EventReferrerStats":{"type":"object","description":"Referrer stats for an event","required":["referrer","count","percentage"],"properties":{"count":{"type":"integer","format":"int64","description":"Number of event occurrences from this referrer"},"percentage":{"type":"number","format":"double","description":"Percentage of total events"},"referrer":{"type":"string","description":"Referrer hostname or \"Direct\""}}},"EventTimeline":{"type":"object","required":["date","count"],"properties":{"count":{"type":"integer","format":"int64"},"date":{"type":"string","format":"date-time"}}},"EventTimelineQuery":{"type":"object","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events (raw count), sessions (unique sessions), or visitors (unique visitors)"},"bucket_size":{"type":["string","null"],"description":"Bucket size: hour, day, or week (auto-detected if not specified)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_name":{"type":["string","null"]},"start_date":{"type":"string","format":"date-time"}}},"EventType":{"type":"object","required":["name","count"],"properties":{"count":{"type":"integer","format":"int64"},"name":{"type":"string"}}},"EventTypeBreakdown":{"type":"object","required":["event_type","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"event_type":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"EventTypeBreakdownQuery":{"type":"object","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events (raw count), sessions (unique sessions), or visitors (unique visitors)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventTypeResponse":{"type":"object","required":["event_type","description","category"],"properties":{"category":{"type":"string"},"description":{"type":"string"},"event_type":{"type":"string"}}},"EventTypesResponse":{"type":"object","required":["events","total","page","page_size"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/EventType"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"EventVisitorInfo":{"type":"object","description":"A visitor who triggered a specific event","required":["visitor_id","visitor_uuid","event_count","first_triggered","last_triggered"],"properties":{"browser":{"type":["string","null"],"description":"Browser name"},"city":{"type":["string","null"],"description":"Visitor's city"},"country":{"type":["string","null"],"description":"Visitor's country"},"country_code":{"type":["string","null"],"description":"Visitor's country code"},"device_type":{"type":["string","null"],"description":"Device type (Desktop, Mobile, Tablet)"},"event_count":{"type":"integer","format":"int64","description":"Number of times this visitor triggered the event"},"first_triggered":{"type":"string","format":"date-time","description":"When the visitor first triggered the event in the date range"},"last_triggered":{"type":"string","format":"date-time","description":"When the visitor last triggered the event in the date range"},"referrer_hostname":{"type":["string","null"],"description":"Referrer hostname for the event"},"visitor_id":{"type":"integer","format":"int32","description":"Visitor numeric ID"},"visitor_uuid":{"type":"string","description":"Visitor UUID"}}},"EventVisitorsQuery":{"type":"object","description":"Query parameters for event visitors list","required":["event_name","project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_name":{"type":"string","description":"The specific event name to list visitors for"},"page":{"type":["integer","null"],"format":"int64","description":"Page number (1-based, default: 1)","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","description":"Items per page (default: 20, max: 100)","minimum":0},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventVisitorsResponse":{"type":"object","description":"Paginated response for event visitors","required":["event_name","total_count","page","per_page","visitors"],"properties":{"event_name":{"type":"string","description":"The event name"},"page":{"type":"integer","format":"int64","description":"Current page number","minimum":0},"per_page":{"type":"integer","format":"int64","description":"Items per page","minimum":0},"total_count":{"type":"integer","format":"int64","description":"Total number of unique visitors who triggered this event"},"visitors":{"type":"array","items":{"$ref":"#/components/schemas/EventVisitorInfo"},"description":"Individual visitors who triggered this event"}}},"EventsCountQuery":{"type":"object","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events (raw count), sessions (unique sessions), or visitors (unique visitors)"},"custom_events_only":{"type":["boolean","null"],"description":"Only return custom events, excluding system events like page_view, page_leave, heartbeat (default: true)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventsResponse":{"type":"object","required":["events","applied_kinds"],"properties":{"applied_kinds":{"type":"array","items":{"$ref":"#/components/schemas/EventKind"},"description":"Echo of the kinds filter actually applied (server-resolved). Useful\nfor clients that pass `kinds=` empty and want to know what they got."},"events":{"type":"array","items":{"$ref":"#/components/schemas/ObservabilityEvent"}}}},"ExecBody":{"type":"object","required":["cmd"],"properties":{"cmd":{"type":"array","items":{"type":"string"}},"cwd":{"type":["string","null"]},"env":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}}},"additionalProperties":false},"ExecDetachedResponse":{"type":"object","required":["job_id"],"properties":{"job_id":{"type":"string"}}},"ExecResponse":{"type":"object","required":["exit_code","stdout","stderr"],"properties":{"exit_code":{"type":"integer","format":"int32"},"stderr":{"type":"string"},"stdout":{"type":"string"}}},"ExecuteImportRequest":{"type":"object","description":"Request to execute an import","required":["session_id","project_name","preset","directory","main_branch"],"properties":{"directory":{"type":"string","description":"Project directory","example":"."},"dry_run":{"type":["boolean","null"],"description":"Dry run mode (don't create resources)"},"main_branch":{"type":"string","description":"Main branch name","example":"main"},"preset":{"type":"string","description":"Preset to use for the project (e.g., \"nextjs\", \"express\", \"docker\")"},"project_name":{"type":"string","description":"Project name to use (overrides the name from the plan)","example":"my-app"},"session_id":{"type":"string","description":"Session ID from plan creation"}}},"ExecuteImportResponse":{"type":"object","description":"Response from import execution","required":["session_id","status","step_results"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32","description":"Created deployment ID (if completed)"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Created environment ID (if completed)"},"project_id":{"type":["integer","null"],"format":"int32","description":"Created project ID (if completed)"},"session_id":{"type":"string","description":"Session ID"},"status":{"$ref":"#/components/schemas/ImportExecutionStatus","description":"Execution status"},"step_results":{"type":"array","items":{"$ref":"#/components/schemas/StepResult"},"description":"Per-step results (in execution order)"}}},"ExecuteOperationRequest":{"type":"object","required":["operation"],"properties":{"operation":{"type":"string"}}},"ExpireRequest":{"type":"object","description":"Request to set expiration on a key","required":["key","seconds"],"properties":{"key":{"type":"string","description":"The key to set expiration on","example":"session:abc"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1},"seconds":{"type":"integer","format":"int64","description":"Expiration time in seconds","example":3600}}},"ExpireResponse":{"type":"object","description":"Response for expire operation","required":["success"],"properties":{"success":{"type":"boolean","description":"True if expiration was set, false if key doesn't exist"}}},"ExplorerSupportResponse":{"type":"object","required":["supported","service_type","capabilities","hierarchy"],"properties":{"capabilities":{"type":"array","items":{"type":"string"},"description":"Capabilities supported by this service","example":["sql"]},"filter_schema":{"description":"JSON Schema for filter format with embedded UI hints (if supported)"},"hierarchy":{"type":"array","items":{"$ref":"#/components/schemas/HierarchyLevel"},"description":"Hierarchy levels (describes the navigation structure)"},"reason":{"type":["string","null"],"description":"Reason why explorer is not supported (if applicable)"},"service_type":{"type":"string","description":"Service type","example":"postgres"},"supported":{"type":"boolean","description":"Whether the service supports query explorer functionality","example":true}}},"ExtendTimeoutBody":{"type":"object","properties":{"duration":{"type":["integer","null"],"format":"int64","description":"`@vercel/sandbox`-compatible alternative — duration in milliseconds.\nUsed when `extra_secs` is absent.","minimum":0},"extra_secs":{"type":["integer","null"],"format":"int64","description":"Extra seconds to add to the existing `expires_at` (temps-native).","minimum":0}}},"ExternalImageResponse":{"type":"object","required":["id","project_id","image_ref","pushed_at","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"digest":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"image_ref":{"type":"string"},"metadata":{},"project_id":{"type":"integer","format":"int32"},"pushed_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"size_bytes":{"type":["integer","null"],"format":"int64"},"tag":{"type":["string","null"]}}},"ExternalServiceBackupResponse":{"type":"object","description":"Response type for external service backup","required":["id","service_id","backup_id","backup_type","state","started_at","s3_location","metadata","compression_type","created_by"],"properties":{"backup_id":{"type":"integer","format":"int32"},"backup_type":{"type":"string"},"checksum":{"type":["string","null"]},"compression_type":{"type":"string"},"created_by":{"type":"integer","format":"int32"},"error_message":{"type":["string","null"]},"expires_at":{"type":["string","null"],"example":"2025-02-15T14:30:00.123Z"},"finished_at":{"type":["string","null"],"example":"2025-01-15T14:35:00.456Z"},"id":{"type":"integer","format":"int32"},"metadata":{},"s3_location":{"type":"string"},"service_id":{"type":"integer","format":"int32"},"size_bytes":{"type":["integer","null"],"format":"int64"},"started_at":{"type":"string","example":"2025-01-15T14:30:00.123Z"},"state":{"type":"string"}}},"ExternalServiceDetails":{"type":"object","required":["service","sensitive_parameters"],"properties":{"current_parameters":{"type":["object","null"],"additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"parameter_schema":{},"sensitive_parameters":{"type":"array","items":{"type":"string"},"description":"Parameter names whose values are masked in `current_parameters` and\nmay be fetched only through the audited reveal endpoint."},"service":{"$ref":"#/components/schemas/ExternalServiceInfo"}}},"ExternalServiceInfo":{"type":"object","required":["id","name","service_type","status","created_at","updated_at","topology"],"properties":{"connection_info":{"type":["string","null"]},"created_at":{"type":"string"},"error_message":{"type":["string","null"],"description":"Error message from failed initialization."},"id":{"type":"integer","format":"int32"},"members":{"type":"array","items":{"$ref":"#/components/schemas/ServiceMemberInfo"},"description":"Cluster members (empty for standalone services)."},"metrics_enabled":{"type":"boolean","description":"Whether metric collection is enabled for this service. The UI uses this\nto decide whether to poll the monitoring endpoints."},"name":{"type":"string"},"node_id":{"type":["integer","null"],"format":"int32","description":"Node ID where the service runs. Null means control plane (local)."},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute"},"status":{"type":"string"},"topology":{"type":"string","description":"Service topology: \"standalone\" (single container) or \"cluster\" (HA multi-member).","example":"standalone"},"updated_at":{"type":"string"},"version":{"type":["string","null"]}}},"ExternalServiceSummary":{"type":"object","description":"Summary of the external service that owns a backup. Only populated for\nexternal-service backups (Redis, Postgres, etc.); absent for control-plane\nbackups.","required":["id","name","service_type"],"properties":{"id":{"type":"integer","format":"int32","description":"Database id of the external service."},"name":{"type":"string","description":"Human-readable service name (e.g. \"redis-prod\")."},"service_type":{"type":"string","description":"Service type string (e.g. \"postgres\", \"redis\", \"mongodb\").","example":"postgres"}}},"FieldResponse":{"type":"object","required":["name","field_type","nullable"],"properties":{"field_type":{"type":"string","description":"Field type (Int32, String, Timestamp, etc.)","example":"Int64"},"name":{"type":"string","description":"Field name","example":"id"},"nullable":{"type":"boolean","description":"Whether the field is nullable","example":false}}},"FiringSeriesEntry":{"type":"object","description":"A single currently-firing series for a dynamic alert rule, snapshotted from\nthe evaluator's in-memory per-series firing map at read time (ADR-026 Phase 3).","required":["series_key","series_label"],"properties":{"alarm_id":{"type":["integer","null"],"format":"int32","description":"The open alarm's id, when one was created (absent if suppressed)."},"series_key":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"The series' label pairs, e.g. `[[\"endpoint\",\"/checkout\"],[\"region\",\"eu-west\"]]`."},"series_label":{"type":"string","description":"The human-readable joined label, e.g. `endpoint=/checkout, region=eu-west`."}}},"FlagEnvironmentResponse":{"type":"object","required":["environment_id","enabled"],"properties":{"enabled":{"type":"boolean"},"environment_id":{"type":"integer","format":"int32"},"value":{}}},"FlagListResponse":{"type":"object","description":"Note the absence of `salt`: it is never exposed. Publishing the bucketing\nsalt would let a client predict, and self-select into, a rollout cohort.","required":["flags","total","page","page_size","total_pages"],"properties":{"flags":{"type":"array","items":{"$ref":"#/components/schemas/FlagResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","description":"Total flags matching the filter, across all pages.","minimum":0},"total_pages":{"type":"integer","format":"int64","minimum":0}}},"FlagResponse":{"type":"object","required":["id","key","value_type","default_value","client_visible","created_at","updated_at","environments"],"properties":{"archived_at":{"type":["string","null"]},"client_visible":{"type":"boolean"},"created_at":{"type":"string"},"default_value":{},"description":{"type":["string","null"]},"environments":{"type":"array","items":{"$ref":"#/components/schemas/FlagEnvironmentResponse"},"description":"Per-environment overrides. Empty means the flag inherits its default\neverywhere."},"id":{"type":"integer","format":"int32"},"key":{"type":"string"},"last_evaluated_at":{"type":["string","null"],"description":"When an app last actually evaluated this flag. `None` means never seen,\nwhich is a real answer rather than missing data."},"updated_at":{"type":"string"},"value_type":{"type":"string"}}},"FlagSnapshot":{"type":"object","description":"A single flag, already resolved down to one environment. This is what the\nevaluator sees and what the SDK caches in memory.","required":["key","value_type","default_value","enabled"],"properties":{"default_value":{"description":"Served whenever evaluation cannot do better. Genuinely polymorphic by\ndesign — the surrounding struct carries the type."},"enabled":{"type":"boolean","description":"False means the kill switch is engaged for this environment."},"environment_value":{"description":"`None` means \"inherit `default_value`\"."},"key":{"type":"string"},"value_type":{"$ref":"#/components/schemas/FlagValueType"}}},"FlagSnapshotResponse":{"type":"object","required":["environment_id","flags"],"properties":{"environment_id":{"type":"integer","format":"int32"},"flags":{"type":"array","items":{"$ref":"#/components/schemas/FlagSnapshot"},"description":"Flags collapsed to what the evaluator needs, sorted by key so the\nserialized form — and therefore the ETag — is stable."}}},"FlagValueType":{"type":"string","description":"The declared type of a flag's value. Fixed at create time.","enum":["bool","string","number","json"]},"ForecastAlgorithm":{"type":"string","description":"Forecast model family.","enum":["linear","seasonal"]},"ForecastParams":{"type":"object","description":"Forecast detector parameters (stub — not yet evaluated).","required":["forecast_horizon_secs","comparator","threshold"],"properties":{"algorithm":{"$ref":"#/components/schemas/ForecastAlgorithm"},"comparator":{"$ref":"#/components/schemas/Comparator","description":"Comparator + threshold the *forecast* is checked against."},"deviations":{"type":"number","format":"double"},"forecast_horizon_secs":{"type":"integer","format":"int32","description":"How far ahead to project before checking the breach condition."},"threshold":{"type":"number","format":"double"}}},"FullError":{"type":"object","required":["id","ts","error_group_id","fingerprint","error_class"],"properties":{"data":{"description":"Full JSONB blob from `error_events.data` — stack trace, breadcrumbs,\nrequest context, everything. Schema is documented per source SDK."},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_class":{"type":"string"},"error_group_id":{"type":"integer","format":"int32"},"fingerprint":{"type":"string"},"id":{"type":"integer","format":"int64"},"message":{"type":["string","null"]},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"}}},"FullEvent":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/FullRequest"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["request"]}}}]},{"allOf":[{"$ref":"#/components/schemas/FullError"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["error"]}}}]},{"allOf":[{"$ref":"#/components/schemas/RevenueRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["revenue"]}}}]},{"allOf":[{"$ref":"#/components/schemas/SpanRow","description":"`SpanRow.attributes` is the truncated form; re-fetching returns\nthe same shape so the panel has a stable contract."},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["span"]}}}],"description":"`SpanRow.attributes` is the truncated form; re-fetching returns\nthe same shape so the panel has a stable contract."}],"description":"One un-truncated row, returned by the `/full/{type}/{id}` endpoint when\nthe user clicks \"Show full\". Same shape as the list rows, but with the\nraw heavy fields restored (no truncation flags) so the side panel can\nrender the long form."},"FullRequest":{"type":"object","required":["id","ts","method","host","path","status"],"properties":{"client_ip":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_group_id":{"type":["integer","null"],"format":"int32"},"host":{"type":"string"},"id":{"type":"string","description":"The request's unique `request_id` — same identity the list rows carry\n(backend-agnostic; ClickHouse rows have no serial PK)."},"latency_ms":{"type":["integer","null"],"format":"int32"},"method":{"type":"string"},"path":{"type":"string"},"referrer":{"type":["string","null"]},"request_headers":{},"response_headers":{},"status":{"type":"integer","format":"int32"},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"},"user_agent":{"type":["string","null"]}}},"FunnelMetricsResponse":{"type":"object","required":["funnel_id","funnel_name","total_entries","step_conversions","overall_conversion_rate","average_completion_time_seconds"],"properties":{"average_completion_time_seconds":{"type":"number","format":"double"},"funnel_id":{"type":"integer","format":"int32"},"funnel_name":{"type":"string"},"overall_conversion_rate":{"type":"number","format":"double"},"step_conversions":{"type":"array","items":{"$ref":"#/components/schemas/StepConversionResponse"}},"total_entries":{"type":"integer","format":"int64","minimum":0}}},"FunnelResponse":{"type":"object","required":["id","name","is_active","created_at","updated_at"],"properties":{"created_at":{"type":"string"},"description":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"name":{"type":"string"},"updated_at":{"type":"string"}}},"GatewayStatus":{"type":"object","description":"Detailed gateway container status surfaced to the settings UI.","required":["present","running","health","container_name","expected_image","drift","auto_upgrade"],"properties":{"auto_upgrade":{"type":"boolean","description":"True if `auto_upgrade` is enabled in settings."},"container_name":{"type":"string","description":"Container name."},"drift":{"type":"boolean","description":"True when `image != expected_image` and the container is present."},"expected_image":{"type":"string","description":"The image the supervisor *expects* (from settings/constant). If this\ndiffers from `image`, the UI shows a \"drift\" badge."},"health":{"type":"string","description":"Higher-level health label: \"running\" | \"restarting\" | \"crash_looping\"\n| \"stopped\" | \"missing\". UI should prefer this over `running`."},"host_port":{"type":["integer","null"],"format":"int32","description":"Host port that the container's :8080 is published on.","minimum":0},"image":{"type":["string","null"],"description":"Image reference the container was created with (e.g.\n`ghcr.io/gotempsh/temps-preview-gateway:latest`)."},"image_digest":{"type":["string","null"],"description":"Image digest if available (e.g. `sha256:…`)."},"last_error":{"type":["string","null"],"description":"Error string Docker recorded for the container (e.g. startup failure)."},"last_exit_code":{"type":["integer","null"],"format":"int64","description":"Exit code of the last run, if the container is not currently running."},"network":{"type":["string","null"],"description":"Network the container is attached to (should be `temps-sandbox-net`)."},"present":{"type":"boolean","description":"Whether the container exists at all."},"restart_count":{"type":["integer","null"],"format":"int64","description":"Number of times Docker has restarted the container."},"running":{"type":"boolean","description":"Whether the container is currently running."},"started_at":{"type":["string","null"],"description":"ISO 8601 timestamp the container was started at, if running."}}},"GenAiEvent":{"type":"object","description":"A GenAI-related event extracted from span events.\n\nCovers `gen_ai.client.inference.operation.details` and `gen_ai.evaluation.result`\nevents per the OTel GenAI semantic conventions.","required":["span_id","trace_id","event_name","timestamp","attributes"],"properties":{"attributes":{"type":"object","description":"All event attributes.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"event_name":{"type":"string"},"span_id":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"trace_id":{"type":"string"}}},"GenAiSpanDetail":{"type":"object","description":"A single GenAI span with extracted semantic convention fields.\n\nFields are aligned with the OpenTelemetry GenAI Semantic Conventions spec:\n","required":["span_id","name","kind","start_time","duration_ms","status_code","attributes"],"properties":{"agent_description":{"type":["string","null"],"description":"Agent description from `gen_ai.agent.description`."},"agent_id":{"type":["string","null"],"description":"Agent identifier from `gen_ai.agent.id`."},"agent_name":{"type":["string","null"],"description":"Agent name from `gen_ai.agent.name`."},"agent_version":{"type":["string","null"],"description":"Agent version from `gen_ai.agent.version`."},"attributes":{"type":"object","description":"All span attributes for extensibility.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"aws_bedrock_guardrail_id":{"type":["string","null"],"description":"AWS Bedrock guardrail ID from `aws.bedrock.guardrail.id`."},"aws_bedrock_knowledge_base_id":{"type":["string","null"],"description":"AWS Bedrock knowledge base ID from `aws.bedrock.knowledge_base.id`."},"azure_resource_provider_namespace":{"type":["string","null"],"description":"Azure resource provider namespace from `azure.resource_provider.namespace`."},"cache_creation_input_tokens":{"type":["integer","null"],"format":"int64","description":"Tokens written to provider cache from `gen_ai.usage.cache_creation.input_tokens`."},"cache_read_input_tokens":{"type":["integer","null"],"format":"int64","description":"Tokens served from provider cache from `gen_ai.usage.cache_read.input_tokens`."},"conversation_id":{"type":["string","null"],"description":"Unique conversation/session/thread ID from `gen_ai.conversation.id`."},"data_source_id":{"type":["string","null"],"description":"Data source identifier from `gen_ai.data_source.id`."},"duration_ms":{"type":"number","format":"double"},"embeddings_dimension_count":{"type":["integer","null"],"format":"int64","description":"Output embedding dimensions from `gen_ai.embeddings.dimension.count`."},"error_type":{"type":["string","null"],"description":"Error type from `error.type` when the span status is ERROR."},"gen_ai_model":{"type":["string","null"],"description":"The requested model from `gen_ai.request.model`."},"gen_ai_operation":{"type":["string","null"],"description":"The operation type from `gen_ai.operation.name` (e.g. \"chat\", \"embeddings\", \"execute_tool\")."},"gen_ai_response_model":{"type":["string","null"],"description":"The model that actually generated the response from `gen_ai.response.model`."},"gen_ai_system":{"type":["string","null"],"description":"The GenAI provider from `gen_ai.provider.name` (falls back to deprecated `gen_ai.system`)."},"input_messages":{"type":["string","null"],"description":"Chat history input from `gen_ai.input.messages` (opt-in, JSON string)."},"input_tokens":{"type":["integer","null"],"format":"int64"},"kind":{"$ref":"#/components/schemas/SpanKind"},"name":{"type":"string"},"openai_api_type":{"type":["string","null"],"description":"OpenAI API type from `openai.api.type` (chat_completions, responses)."},"openai_request_service_tier":{"type":["string","null"],"description":"Requested service tier from `openai.request.service_tier`."},"openai_response_service_tier":{"type":["string","null"],"description":"Actual service tier from `openai.response.service_tier`."},"openai_system_fingerprint":{"type":["string","null"],"description":"System fingerprint from `openai.response.system_fingerprint`."},"output_messages":{"type":["string","null"],"description":"Model output from `gen_ai.output.messages` (opt-in, JSON string)."},"output_tokens":{"type":["integer","null"],"format":"int64"},"output_type":{"type":["string","null"],"description":"Output content type from `gen_ai.output.type` (text, json, image, speech)."},"parent_span_id":{"type":["string","null"]},"request_choice_count":{"type":["integer","null"],"format":"int64","description":"Number of choices requested from `gen_ai.request.choice.count`."},"request_encoding_formats":{"type":["array","null"],"items":{"type":"string"},"description":"Requested encoding formats from `gen_ai.request.encoding_formats`."},"request_frequency_penalty":{"type":["number","null"],"format":"double","description":"Frequency penalty from `gen_ai.request.frequency_penalty`."},"request_max_tokens":{"type":["integer","null"],"format":"int64","description":"Max tokens from `gen_ai.request.max_tokens`."},"request_presence_penalty":{"type":["number","null"],"format":"double","description":"Presence penalty from `gen_ai.request.presence_penalty`."},"request_seed":{"type":["integer","null"],"format":"int64","description":"Seed for reproducibility from `gen_ai.request.seed`."},"request_stop_sequences":{"type":["array","null"],"items":{"type":"string"},"description":"Stop sequences from `gen_ai.request.stop_sequences`."},"request_temperature":{"type":["number","null"],"format":"double","description":"Temperature setting from `gen_ai.request.temperature`."},"request_top_k":{"type":["number","null"],"format":"double","description":"Top-k setting from `gen_ai.request.top_k`."},"request_top_p":{"type":["number","null"],"format":"double","description":"Top-p setting from `gen_ai.request.top_p`."},"response_finish_reasons":{"type":["array","null"],"items":{"type":"string"},"description":"Reasons the model stopped from `gen_ai.response.finish_reasons` (e.g. [\"stop\"])."},"response_id":{"type":["string","null"],"description":"Unique completion ID from `gen_ai.response.id` (e.g. \"chatcmpl-123\")."},"retrieval_documents":{"type":["string","null"],"description":"Retrieved documents from `gen_ai.retrieval.documents` (opt-in, JSON string)."},"retrieval_query_text":{"type":["string","null"],"description":"Retrieval query text from `gen_ai.retrieval.query.text` (opt-in)."},"server_address":{"type":["string","null"],"description":"GenAI server address from `server.address`."},"server_port":{"type":["integer","null"],"format":"int64","description":"GenAI server port from `server.port`."},"span_id":{"type":"string"},"start_time":{"type":"string","format":"date-time"},"status_code":{"$ref":"#/components/schemas/SpanStatusCode"},"system_instructions":{"type":["string","null"],"description":"System instructions from `gen_ai.system_instructions` (opt-in, JSON string)."},"tool_call_arguments":{"type":["string","null"],"description":"Tool call arguments from `gen_ai.tool.call.arguments` (opt-in, JSON string)."},"tool_call_id":{"type":["string","null"],"description":"Tool call ID from `gen_ai.tool.call.id`."},"tool_call_result":{"type":["string","null"],"description":"Tool call result from `gen_ai.tool.call.result` (opt-in, JSON string)."},"tool_definitions":{"type":["string","null"],"description":"Tool definitions from `gen_ai.tool.definitions` (opt-in, JSON string)."},"tool_description":{"type":["string","null"],"description":"Tool description from `gen_ai.tool.description`."},"tool_name":{"type":["string","null"],"description":"Tool name from `gen_ai.tool.name`."},"tool_type":{"type":["string","null"],"description":"Tool type from `gen_ai.tool.type` (function, extension, datastore)."}}},"GenAiTraceDetailResponse":{"type":"object","required":["trace_id","spans","span_count","events","event_count"],"properties":{"event_count":{"type":"integer","minimum":0},"events":{"type":"array","items":{"$ref":"#/components/schemas/GenAiEvent"}},"span_count":{"type":"integer","minimum":0},"spans":{"type":"array","items":{"$ref":"#/components/schemas/GenAiSpanDetail"}},"trace_id":{"type":"string"}}},"GenAiTraceSummariesResponse":{"type":"object","required":["data","total"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/GenAiTraceSummary"}},"total":{"type":"integer","format":"int64","minimum":0}}},"GenAiTraceSummary":{"type":"object","description":"Summary of a GenAI conversation — aggregated from OTel spans with `gen_ai.*` attributes.","required":["trace_id","root_span_name","service_name","start_time","duration_ms","span_count","error_count"],"properties":{"duration_ms":{"type":"number","format":"double"},"error_count":{"type":"integer","format":"int64"},"gen_ai_model":{"type":["string","null"],"description":"The requested model from `gen_ai.request.model`."},"gen_ai_operation":{"type":["string","null"],"description":"The operation type from `gen_ai.operation.name` (e.g. \"chat\", \"embeddings\")."},"gen_ai_system":{"type":["string","null"],"description":"The GenAI provider (e.g. \"openai\", \"anthropic\") from `gen_ai.provider.name`."},"root_span_name":{"type":"string"},"service_name":{"type":"string"},"span_count":{"type":"integer","format":"int64"},"start_time":{"type":"string","format":"date-time"},"total_cache_creation_input_tokens":{"type":["integer","null"],"format":"int64","description":"Total cache-creation input tokens across all spans."},"total_cache_read_input_tokens":{"type":["integer","null"],"format":"int64","description":"Total cache-read input tokens across all spans."},"total_input_tokens":{"type":["integer","null"],"format":"int64","description":"Total input tokens across all spans in this trace."},"total_output_tokens":{"type":["integer","null"],"format":"int64","description":"Total output tokens across all spans in this trace."},"trace_id":{"type":"string"}}},"GeneralStatsQuery":{"type":"object","required":["start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"start_date":{"type":"string","format":"date-time"}}},"GeneralStatsResponse":{"type":"object","required":["total_unique_visitors","total_visits","total_page_views","total_events","total_projects","avg_bounce_rate","avg_engagement_rate","project_breakdown"],"properties":{"avg_bounce_rate":{"type":"number","format":"double"},"avg_engagement_rate":{"type":"number","format":"double"},"page_views_trend_percentage":{"type":["number","null"],"format":"double","description":"Percentage change in page views vs previous period"},"previous_page_views":{"type":["integer","null"],"format":"int64","description":"Previous period page views"},"previous_unique_visitors":{"type":["integer","null"],"format":"int64","description":"Previous period unique visitors (same duration, shifted back)"},"project_breakdown":{"type":"array","items":{"$ref":"#/components/schemas/ProjectStatsBreakdown"}},"total_events":{"type":"integer","format":"int64"},"total_page_views":{"type":"integer","format":"int64"},"total_projects":{"type":"integer","format":"int64"},"total_unique_visitors":{"type":"integer","format":"int64"},"total_visits":{"type":"integer","format":"int64"},"visitors_trend_percentage":{"type":["number","null"],"format":"double","description":"Percentage change in unique visitors vs previous period"}}},"GenerateDockerfileRequest":{"type":"object","description":"Request body for generating a Dockerfile from a preset","properties":{"build_command":{"type":["string","null"],"description":"Custom build command (overrides preset default)","example":"npm run build"},"install_command":{"type":["string","null"],"description":"Custom install command (overrides preset default)","example":"npm ci"},"output_dir":{"type":["string","null"],"description":"Output directory for static builds","example":"dist"},"package_manager":{"type":["string","null"],"description":"Package manager used by the project (npm, yarn, pnpm, bun)\nIf not provided, defaults to npm","example":"npm"},"project_name":{"type":["string","null"],"description":"Project name/slug used for container naming","example":"my-app"},"use_buildkit":{"type":"boolean","description":"Whether to use BuildKit cache mounts for faster builds"}}},"GenerateDockerfileResponse":{"type":"object","description":"Response containing a generated Dockerfile and build arguments","required":["dockerfile","build_args","preset"],"properties":{"build_args":{"type":"object","description":"Build arguments to pass to `docker build --build-arg KEY=VALUE`","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"dockerfile":{"type":"string","description":"The generated Dockerfile content"},"preset":{"type":"string","description":"The preset slug used for generation"}}},"GenerateJoinTokenResponse":{"type":"object","description":"Response returned when a join token is generated (plaintext shown once)","required":["token","message"],"properties":{"message":{"type":"string"},"token":{"type":"string","description":"The plaintext join token — shown only once, save it now"}}},"GeoLocationResponse":{"type":"object","description":"Response containing geolocation information for an IP address","required":["ip","is_eu"],"properties":{"city":{"type":["string","null"],"description":"City name","example":"Mountain View"},"country":{"type":["string","null"],"description":"Country name","example":"United States"},"country_code":{"type":["string","null"],"description":"ISO country code (2 letters)","example":"US"},"ip":{"type":"string","description":"IP address that was geolocated","example":"8.8.8.8"},"is_eu":{"type":"boolean","description":"Whether the IP is in the European Union","example":false},"latitude":{"type":["number","null"],"format":"double","description":"Latitude coordinate","example":37.386},"longitude":{"type":["number","null"],"format":"double","description":"Longitude coordinate","example":-122.0838},"region":{"type":["string","null"],"description":"Region/state name","example":"California"},"timezone":{"type":["string","null"],"description":"Timezone identifier","example":"America/Los_Angeles"}}},"GeoRestrictionsConfig":{"type":"object","description":"Geographic restrictions configuration (future feature)","properties":{"allowedCountries":{"type":"array","items":{"type":"string"},"description":"Allow traffic only from specific countries"},"blockedCountries":{"type":"array","items":{"type":"string"},"description":"Block traffic from specific countries (ISO 3166-1 alpha-2 codes)"}}},"GetDeploymentsParams":{"type":"object","properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"page":{"type":["integer","null"],"format":"int64"},"per_page":{"type":["integer","null"],"format":"int64"}}},"GetEnvironmentVariablesQuery":{"type":"object","properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"service_id":{"type":["integer","null"],"format":"int32","description":"Required by integration-value reveals to bind the plaintext response to\nthe exact service displayed by the client."},"var_id":{"type":["integer","null"],"format":"int32","description":"Exact manual env-var row to reveal. Required by the dashboard so\nduplicate keys on disjoint environments cannot cross-reveal."}}},"GetFunnelMetricsQuery":{"type":"object","properties":{"country_code":{"type":["string","null"]},"end_date":{"type":["string","null"],"format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"start_date":{"type":["string","null"],"format":"date-time"}}},"GetOrCreateDSNRequest":{"type":"object","properties":{"base_url":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"}}},"GetProjectSecretsQuery":{"type":"object","properties":{"environment_id":{"type":["integer","null"],"format":"int32"}}},"GetProjectSessionReplaysQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0},"project_id":{"type":"integer","format":"int32"}}},"GetProjectSessionReplaysResponse":{"type":"object","required":["sessions","page","per_page","total_count"],"properties":{"page":{"type":"integer","format":"int64","minimum":0},"per_page":{"type":"integer","format":"int64","minimum":0},"sessions":{"type":"array","items":{"$ref":"#/components/schemas/SessionReplayWithVisitorDto"}},"total_count":{"type":"integer","format":"int64","minimum":0}}},"GetRequest":{"type":"object","description":"Request to get a value by key","required":["key"],"properties":{"key":{"type":"string","description":"The key to retrieve","example":"user:123"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"GetResponse":{"type":"object","description":"Response for get operation","properties":{"value":{"description":"The value, or null if not found"}}},"GetSessionReplayResponse":{"type":"object","required":["session"],"properties":{"session":{"$ref":"#/components/schemas/SessionReplayWithVisitorDto"}}},"GetUniqueEventsQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","minimum":0},"page_size":{"type":["integer","null"],"format":"int64","minimum":0}}},"GetVisitorSessionsQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0}}},"GetVisitorSessionsResponse":{"type":"object","required":["sessions","page","per_page","total_count"],"properties":{"page":{"type":"integer","format":"int64","minimum":0},"per_page":{"type":"integer","format":"int64","minimum":0},"sessions":{"type":"array","items":{"$ref":"#/components/schemas/SessionReplayWithVisitorDto"}},"total_count":{"type":"integer","minimum":0}}},"GitPushEvent":{"type":"object","description":"Git push event information that triggered the deployment","required":["repo","owner","branch","commit"],"properties":{"branch":{"type":"string","description":"Branch that was pushed"},"commit":{"type":"string","description":"Commit SHA"},"owner":{"type":"string","description":"Repository owner/organization"},"repo":{"type":"string","description":"Repository name"}}},"GitRefResponse":{"type":"object","description":"Git repository reference response","required":["url","ref"],"properties":{"path":{"type":["string","null"],"description":"Path within the repository (for monorepos)"},"ref":{"type":"string","description":"Git reference (branch, tag, or commit)"},"url":{"type":"string","description":"Git repository URL"}}},"GitSourcePlan":{"type":"object","description":"Git repository the source platform deploys from","required":["owner","repo","branch","is_public"],"properties":{"branch":{"type":"string","description":"Branch the source platform deploys"},"clone_url":{"type":["string","null"],"description":"Full clone URL, e.g. `https://github.com/owner/repo.git`"},"is_public":{"type":"boolean","description":"True when the repository is public (no credentials on the source\nplatform) — the project can then build without a git provider\nconnection."},"owner":{"type":"string","description":"Repository owner (organization or user)"},"repo":{"type":"string","description":"Repository name"}}},"GlobalConversationResponse":{"type":"object","description":"A conversation in the unified cross-project switcher: carries the project it\nbelongs to (name/slug) so the UI can show where the chat was started and\nlink back to the source.","required":["public_id","project_id","context_type","context_id","status","created_at","last_activity_at"],"properties":{"context_id":{"type":"string"},"context_type":{"type":"string"},"created_at":{"type":"string"},"last_activity_at":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":["string","null"]},"project_slug":{"type":["string","null"]},"public_id":{"type":"string"},"status":{"type":"string"},"title":{"type":["string","null"]}}},"GlobalEventStatsResponse":{"type":"object","required":["delivered","opened","clicked","bounced","complained"],"properties":{"bounce_rate":{"type":["number","null"],"format":"double"},"bounced":{"type":"integer","format":"int64","minimum":0},"click_rate":{"type":["number","null"],"format":"double"},"clicked":{"type":"integer","format":"int64","minimum":0},"complained":{"type":"integer","format":"int64","minimum":0},"delivered":{"type":"integer","format":"int64","minimum":0},"open_rate":{"type":["number","null"],"format":"double"},"opened":{"type":"integer","format":"int64","minimum":0}}},"GlobalMrrResponse":{"type":"object","required":["currency","current_mrr_minor","previous_mrr_minor"],"properties":{"change_percentage":{"type":["number","null"],"format":"double","description":"Percentage change vs 24h ago. Null when previous MRR is zero\n(no baseline to compare against)."},"currency":{"type":"string"},"current_mrr_minor":{"type":"integer","format":"int64"},"previous_mrr_minor":{"type":"integer","format":"int64","description":"MRR 24h before now, reconstructed from the event log."}}},"GlobalRecentEventResponse":{"type":"object","required":["id","project_id","project_name","occurred_at","event_type"],"properties":{"amount_minor":{"type":["integer","null"],"format":"int64"},"currency":{"type":["string","null"]},"customer_ref":{"type":["string","null"]},"event_type":{"type":"string"},"id":{"type":"integer","format":"int64"},"mrr_minor":{"type":["integer","null"],"format":"int64"},"occurred_at":{"type":"string","format":"date-time"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"}}},"GlobalRevenueSummaryResponse":{"type":"object","required":["currency","current_mrr_minor","paid_last_30d_minor","refunded_last_30d_minor","paid_all_time_minor","refunded_all_time_minor","active_subscriptions","active_customers","transactions_last_30d"],"properties":{"active_customers":{"type":"integer","format":"int64"},"active_subscriptions":{"type":"integer","format":"int64"},"currency":{"type":"string"},"current_mrr_minor":{"type":"integer","format":"int64"},"paid_all_time_minor":{"type":"integer","format":"int64"},"paid_last_30d_minor":{"type":"integer","format":"int64"},"refunded_all_time_minor":{"type":"integer","format":"int64"},"refunded_last_30d_minor":{"type":"integer","format":"int64"},"transactions_last_30d":{"type":"integer","format":"int64"}}},"GroupedPageMetric":{"type":"object","required":["group_key","events"],"properties":{"cls":{"type":["number","null"],"format":"float"},"country_code":{"type":["string","null"],"description":"ISO 3166-1 alpha-2 code of the group's country. Populated for the\ngeographic dimensions (country/region/city) so clients can match map\ngeometries without name-based lookups; null otherwise."},"events":{"type":"integer","format":"int64"},"fcp":{"type":["number","null"],"format":"float"},"group_key":{"type":"string"},"inp":{"type":["number","null"],"format":"float"},"lcp":{"type":["number","null"],"format":"float"},"ttfb":{"type":["number","null"],"format":"float"}}},"GroupedPageMetricsQuery":{"allOf":[{"$ref":"#/components/schemas/SpeedSegmentFilters","description":"Segment filters — same shape as `PerformanceMetricsQuery`."},{"type":"object","required":["start_date","end_date","project_id","group_by"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"device_type":{"type":["string","null"],"description":"Device type filter: \"desktop\" or \"mobile\""},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"group_by":{"type":"string"},"include_bots":{"type":["boolean","null"],"description":"Include crawler/datacenter (bot) samples. Defaults to false."},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}}]},"GroupedPageMetricsResponse":{"type":"object","required":["groups","total_events","grouped_by"],"properties":{"grouped_by":{"type":"string"},"groups":{"type":"array","items":{"$ref":"#/components/schemas/GroupedPageMetric"}},"total_events":{"type":"integer","format":"int64"}}},"HasAnalyticsEventsResponse":{"type":"object","required":["has_events"],"properties":{"has_events":{"type":"boolean"}}},"HasErrorGroupsResponse":{"type":"object","required":["has_error_groups"],"properties":{"has_error_groups":{"type":"boolean"}}},"HasEventsQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"HasEventsResponse":{"type":"object","required":["has_events"],"properties":{"has_events":{"type":"boolean"}}},"HasMetricsQuery":{"type":"object","required":["project_id"],"properties":{"project_id":{"type":"integer","format":"int32"}}},"HasMetricsResponse":{"type":"object","required":["has_metrics"],"properties":{"has_metrics":{"type":"boolean"}}},"HealthCheckConfiguration":{"type":"object","description":"Health check configuration","required":["port","interval","timeout","retries"],"properties":{"http_path":{"type":["string","null"],"description":"HTTP path to check (if applicable)"},"interval":{"type":"integer","format":"int32","description":"Interval between checks (seconds)","minimum":0},"port":{"type":"integer","format":"int32","description":"Port to check","minimum":0},"retries":{"type":"integer","format":"int32","description":"Number of retries before marking unhealthy","minimum":0},"timeout":{"type":"integer","format":"int32","description":"Timeout for each check (seconds)","minimum":0}}},"HealthCheckEntryResponse":{"type":"object","required":["checked_at","status"],"properties":{"checked_at":{"type":"string","description":"ISO 8601 timestamp of when the probe ran.","example":"2026-04-22T11:30:00Z"},"error_message":{"type":["string","null"],"description":"Present only when the probe failed or was degraded."},"response_time_ms":{"type":["integer","null"],"format":"int32","description":"TCP connect latency in milliseconds."},"status":{"type":"string","description":"\"operational\" | \"degraded\" | \"down\"","example":"operational"}}},"HealthResponse":{"type":"object","required":["summaries"],"properties":{"summaries":{"type":"array","items":{"$ref":"#/components/schemas/HealthSummary"}}}},"HealthStatus":{"type":"string","description":"Overall health status.","enum":["healthy","degraded","down","unknown"]},"HealthSummary":{"type":"object","description":"Pre-computed health summary for a project environment.","required":["project_id","service_name","status","uptime_pct","error_rate","p95_latency_ms","cpu_usage_pct","memory_usage_pct","computed_at"],"properties":{"computed_at":{"type":"string","format":"date-time"},"cpu_usage_pct":{"type":"number","format":"double"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_rate":{"type":"number","format":"double"},"last_deploy_at":{"type":["string","null"],"format":"date-time"},"last_deploy_id":{"type":["integer","null"],"format":"int32"},"memory_usage_pct":{"type":"number","format":"double"},"p95_latency_ms":{"type":"number","format":"double"},"project_id":{"type":"integer","format":"int32"},"service_name":{"type":"string"},"status":{"$ref":"#/components/schemas/HealthStatus"},"uptime_pct":{"type":"number","format":"double"}}},"HeartbeatApiRequest":{"type":"object","properties":{"architecture":{"type":["string","null"],"description":"Container platform of this node's Docker daemon (`linux/amd64`,\n`linux/arm64`), read from `docker info` by the agent. Absent from\npre-multi-arch agents; the stored value is then left untouched."},"capacity":{"description":"Resource capacity/usage info as JSON (cpu_usage, memory_usage, etc.)"},"containers":{"type":["array","null"],"items":{"$ref":"#/components/schemas/ContainerInventoryItem"},"description":"Container inventory for reconciliation (sent on first heartbeat after agent startup).\nEach entry has `container_id` and `container_name` of temps-managed containers."},"labels":{"description":"Updated node labels for scheduling (allows runtime label changes)."}}},"HeartbeatResponse":{"type":"object","required":["status","message"],"properties":{"message":{"type":"string"},"status":{"type":"string"}}},"HierarchyLevel":{"type":"object","description":"Describes a level in the data source hierarchy","required":["level","name","container_type","can_list_containers","can_list_entities"],"properties":{"can_list_containers":{"type":"boolean","description":"Can list containers at this level?","example":true},"can_list_entities":{"type":"boolean","description":"Can list entities at this level?","example":false},"container_type":{"type":"string","description":"Type of container at this level","example":"database"},"level":{"type":"integer","format":"int32","description":"Level number (0 = root)","example":0,"minimum":0},"name":{"type":"string","description":"Human-readable name for this level","example":"root"}}},"HistogramSummary":{"type":"object","description":"An explicit-bucket histogram aggregated over a time bucket.\n\nCarries the reduced scalars (count/sum/min/max) plus the explicit bucket\nlayout — `bounds` (the upper bounds) and `bucket_counts` (observation counts,\nsummed element-wise across the window; length is `bounds.len() + 1`, the last\nentry being the +Inf overflow bucket). With these, a caller can reconstruct\nany quantile (e.g. p95) via cumulative-count interpolation.","required":["count","sum","bounds","bucket_counts"],"properties":{"bounds":{"type":"array","items":{"type":"number","format":"double"},"description":"Explicit bucket upper bounds (OTLP `explicit_bounds`), ascending."},"bucket_counts":{"type":"array","items":{"type":"integer","format":"int64","minimum":0},"description":"Per-bucket observation counts summed element-wise across the window.\nLength is `bounds.len() + 1` (the trailing element is the +Inf bucket)."},"count":{"type":"integer","format":"int64","description":"Total observation count summed across the bucket window.","minimum":0},"max":{"type":["number","null"],"format":"double","description":"Maximum observed value, when reported by the producer."},"min":{"type":["number","null"],"format":"double","description":"Minimum observed value, when reported by the producer."},"sum":{"type":"number","format":"double","description":"Sum of observed values across the bucket window."}}},"HostnameChange":{"type":"object","description":"A single generated-hostname change in a flatten preview/apply.","required":["kind","id","old","new"],"properties":{"id":{"type":"integer","format":"int32","description":"Row id of the affected record."},"kind":{"type":"string","description":"`\"deployment\"` or `\"environment\"`."},"new":{"type":"string"},"old":{"type":"string"}}},"HostnamePreviewResponse":{"type":"object","description":"Combined preview of a hostname-mode change.","required":["hostname_changes","dns_changes","total"],"properties":{"dns_changes":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecordChange"}},"hostname_changes":{"type":"array","items":{"$ref":"#/components/schemas/HostnameChange"}},"total":{"type":"integer","minimum":0},"zone_access_ok":{"type":["boolean","null"],"description":"Whether the provider token can manage this zone (None if not checked)."}}},"HourlyPageSessions":{"type":"object","required":["timestamp","session_count","event_count","avg_duration_seconds"],"properties":{"avg_duration_seconds":{"type":"number","format":"double"},"event_count":{"type":"integer","format":"int64"},"session_count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"}}},"HourlyVisitsQuery":{"type":"object","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events (page views), sessions (unique sessions), or visitors (unique visitors)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"HttpChallengeDebugResponse":{"type":"object","required":["domain","challenge_exists","dns_a_records","dns_aaaa_records"],"properties":{"challenge_exists":{"type":"boolean"},"challenge_token":{"type":["string","null"]},"challenge_url":{"type":["string","null"],"description":"The full URL that Let's Encrypt will try to access to validate the challenge"},"dns_a_records":{"type":"array","items":{"type":"string"},"description":"IPv4 addresses the domain points to"},"dns_aaaa_records":{"type":"array","items":{"type":"string"},"description":"IPv6 addresses the domain points to"},"dns_error":{"type":["string","null"],"description":"Any DNS resolution errors"},"domain":{"type":"string"},"validation_url":{"type":["string","null"],"description":"The ACME validation URL (internal to ACME protocol)"}}},"ImportCredentials":{"type":"object","description":"Platform-specific credentials for accessing the source system.\n\nFor platforms like Vercel and Railway, this contains the API token.\nFor self-hosted platforms like Coolify and Dokploy, this also contains\nthe `base_url` of the instance.\n\nLocal importers (Docker) can use `ImportCredentials::none()`.","properties":{"base_url":{"type":["string","null"],"description":"Base URL override (for self-hosted platforms like Coolify, Dokploy)\n\nExample: `https://coolify.example.com`"},"extra":{"type":"object","description":"Additional platform-specific parameters","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"team_id":{"type":["string","null"],"description":"Team or organization ID (for platforms with team scoping like Vercel)"},"token":{"type":["string","null"],"description":"API token / bearer token for the source platform"}}},"ImportExecutionStatus":{"type":"string","description":"Import execution status","enum":["pending","inprogress","completed","failed"]},"ImportExternalServiceRequest":{"type":"object","description":"Request to import a Docker container as a managed service","required":["name","service_type","parameters","container_id"],"properties":{"container_id":{"type":"string","description":"Container ID or name to import","example":"abc123def456"},"name":{"type":"string","description":"Name to register the service as in Temps","example":"production-database"},"parameters":{"type":"object","description":"Service configuration parameters","additionalProperties":{},"propertyNames":{"type":"string"}},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute","description":"Service type"},"version":{"type":["string","null"],"description":"Optional version override"}}},"ImportOutcomeResponse":{"type":"object","required":["rows_read","inserted","updated","skipped_stale","skipped_invalid","errors"],"properties":{"errors":{"type":"array","items":{"$ref":"#/components/schemas/ImportRowErrorResponse"}},"inserted":{"type":"integer","minimum":0},"rows_read":{"type":"integer","minimum":0},"skipped_invalid":{"type":"integer","minimum":0},"skipped_stale":{"type":"integer","minimum":0},"updated":{"type":"integer","minimum":0}}},"ImportPlan":{"type":"object","description":"Complete import plan describing all operations to onboard a workload.\n\nThe plan is generated from a snapshot and presented to the user for review\nbefore any resources are created. Users can modify individual items\n(skip services, change actions) before approving execution.","required":["version","source","source_id","project","environment","deployment","summary","metadata"],"properties":{"additional_deployments":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentConfiguration"},"description":"Additional deployments (workers, cron jobs, etc.)"},"cost_analysis":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/CostAnalysis","description":"Cost, overprovisioning, and savings analysis. Populated by importers\nthat can observe the whole source cluster (currently Kubernetes);\n`None` for container/platform imports."}]},"deployment":{"$ref":"#/components/schemas/DeploymentConfiguration","description":"Primary deployment configuration"},"domains":{"type":"array","items":{"$ref":"#/components/schemas/DomainPlan"},"description":"Custom domains to migrate"},"environment":{"$ref":"#/components/schemas/EnvironmentConfiguration","description":"Environment configuration"},"metadata":{"$ref":"#/components/schemas/PlanMetadata","description":"Plan metadata"},"project":{"$ref":"#/components/schemas/ProjectConfiguration","description":"Project configuration"},"services":{"type":"array","items":{"$ref":"#/components/schemas/ServicePlan"},"description":"Services to migrate (databases, caches, blob stores)\n\nEach service has an `action` field the user can change before execution."},"source":{"type":"string","description":"Source system this plan was generated from"},"source_id":{"type":"string","description":"Source workload / project ID in the source system"},"steps":{"type":"array","items":{"$ref":"#/components/schemas/MigrationStep"},"description":"Ordered list of migration steps that will be executed.\n\nThis is the human-readable execution plan. Each step describes what\nwill happen, what risks are involved, and what the user should verify.\nSteps are executed in order. If a step fails, execution stops and\nalready-created resources are reported for manual cleanup."},"summary":{"$ref":"#/components/schemas/MigrationSummary","description":"Human-readable summary of the entire migration"},"version":{"type":"string","description":"Plan version for compatibility tracking"}}},"ImportRowErrorResponse":{"type":"object","required":["row","reason"],"properties":{"reason":{"type":"string"},"row":{"type":"integer","minimum":0}}},"ImportSelector":{"type":"object","description":"Selector for discovering workloads","properties":{"label_filter":{"type":["object","null"],"description":"Filter by labels/tags","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"limit":{"type":["integer","null"],"description":"Limit number of results","minimum":0},"name_pattern":{"type":["string","null"],"description":"Filter by name pattern (glob/regex)"},"status_filter":{"type":["array","null"],"items":{"type":"string"},"description":"Filter by status (running, stopped, deployed, etc.)"},"workload_type_filter":{"type":["array","null"],"items":{"type":"string"},"description":"Filter by workload type (container, function, static-site, etc.)"}}},"ImportSource":{"type":"string","description":"Import source identifier","enum":["docker","coolify","dokploy","vercel","netlify","railway","render","fly","kubernetes","caprover","portainer","kamal","custom"]},"ImportSourceCapabilities":{"type":"object","description":"Source capabilities","required":["supports_volumes","supports_networks","supports_health_checks","supports_resource_limits","supports_build","supports_services","supports_domains","supports_project_snapshot","supports_cost_analysis","requires_credentials"],"properties":{"requires_credentials":{"type":"boolean","description":"Whether this source requires API credentials (token, base URL)"},"supports_build":{"type":"boolean"},"supports_cost_analysis":{"type":"boolean","description":"Supports cluster cost + overprovisioning analysis in the plan"},"supports_domains":{"type":"boolean","description":"Supports custom domain migration"},"supports_health_checks":{"type":"boolean"},"supports_networks":{"type":"boolean"},"supports_project_snapshot":{"type":"boolean","description":"Supports full project-level snapshots"},"supports_resource_limits":{"type":"boolean"},"supports_services":{"type":"boolean","description":"Supports service migration (databases, caches, etc.)"},"supports_volumes":{"type":"boolean"}}},"ImportSourceInfo":{"type":"object","description":"Information about an import source","required":["source","name","version","available","capabilities"],"properties":{"available":{"type":"boolean","description":"Whether the source is currently available"},"capabilities":{"$ref":"#/components/schemas/ImportSourceCapabilities","description":"Capabilities"},"name":{"type":"string","description":"Human-readable name"},"source":{"$ref":"#/components/schemas/ImportSource","description":"Source identifier"},"version":{"type":"string","description":"Source version"}}},"ImportStatusResponse":{"type":"object","description":"Response with import status","required":["session_id","status","errors","warnings","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","description":"Created at timestamp"},"deployment_id":{"type":["integer","null"],"format":"int32","description":"Created deployment ID"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Created environment ID"},"errors":{"type":"array","items":{"type":"string"},"description":"Errors (if any)"},"plan":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ImportPlan","description":"Import plan"}]},"project_id":{"type":["integer","null"],"format":"int32","description":"Created project ID"},"session_id":{"type":"string","description":"Session ID"},"status":{"$ref":"#/components/schemas/ImportExecutionStatus","description":"Current status"},"updated_at":{"type":"string","format":"date-time","description":"Updated at timestamp"},"validation":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ValidationReport","description":"Validation report"}]},"warnings":{"type":"array","items":{"type":"string"},"description":"Warnings (if any)"}}},"IncidentBucket":{"type":"object","required":["bucket_start","total_incidents","minor_incidents","major_incidents","critical_incidents","resolved_incidents","active_incidents"],"properties":{"active_incidents":{"type":"integer","format":"int64"},"avg_resolution_time_minutes":{"type":["number","null"],"format":"double"},"bucket_start":{"type":"string","format":"date-time"},"critical_incidents":{"type":"integer","format":"int64"},"major_incidents":{"type":"integer","format":"int64"},"minor_incidents":{"type":"integer","format":"int64"},"resolved_incidents":{"type":"integer","format":"int64"},"total_incidents":{"type":"integer","format":"int64"}}},"IncidentBucketedResponse":{"type":"object","required":["project_id","interval","buckets"],"properties":{"buckets":{"type":"array","items":{"$ref":"#/components/schemas/IncidentBucket"}},"environment_id":{"type":["integer","null"],"format":"int32"},"interval":{"type":"string"},"project_id":{"type":"integer","format":"int32"}}},"IncidentResponse":{"type":"object","required":["id","project_id","title","severity","status","started_at","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time"},"description":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"monitor_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"resolved_at":{"type":["string","null"],"format":"date-time"},"severity":{"type":"string"},"started_at":{"type":"string","format":"date-time"},"status":{"type":"string"},"title":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}},"IncidentUpdateResponse":{"type":"object","required":["id","incident_id","status","message","created_at"],"properties":{"created_at":{"type":"string","format":"date-time"},"id":{"type":"integer","format":"int32"},"incident_id":{"type":"integer","format":"int32"},"message":{"type":"string"},"status":{"type":"string"}}},"IncrRequest":{"type":"object","description":"Request to increment a value","required":["key"],"properties":{"amount":{"type":["integer","null"],"format":"int64","description":"Amount to increment by (default: 1)"},"key":{"type":"string","description":"The key to increment","example":"counter"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"IncrResponse":{"type":"object","description":"Response for increment operation","required":["value"],"properties":{"value":{"type":"integer","format":"int64","description":"New value after increment","example":42}}},"InitAuthResponse":{"type":"object","required":["auth_url","session_token"],"properties":{"auth_url":{"type":"string"},"session_token":{"type":"string"}}},"Insight":{"type":"object","description":"An anomaly insight.","required":["id","project_id","service_name","severity","status","title","description","anomaly_ids","started_at","created_at","updated_at"],"properties":{"anomaly_ids":{"type":"array","items":{"type":"integer","format":"int64"}},"correlated_deploy_id":{"type":["integer","null"],"format":"int32"},"created_at":{"type":"string","format":"date-time"},"description":{"type":"string"},"environment":{"type":["string","null"]},"id":{"type":"integer","format":"int64"},"metric_name":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"resolved_at":{"type":["string","null"],"format":"date-time"},"service_name":{"type":"string"},"severity":{"$ref":"#/components/schemas/InsightSeverity"},"started_at":{"type":"string","format":"date-time"},"status":{"$ref":"#/components/schemas/InsightStatus"},"title":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}},"InsightSeverity":{"type":"string","description":"Severity of an anomaly insight.","enum":["low","medium","high","critical"]},"InsightStatus":{"type":"string","description":"Status of an insight.","enum":["active","resolved"]},"InsightsResponse":{"type":"object","required":["data","count"],"properties":{"count":{"type":"integer","minimum":0},"data":{"type":"array","items":{"$ref":"#/components/schemas/Insight"}}}},"IntegrationResponse":{"type":"object","required":["id","project_id","provider","webhook_path_token","webhook_path","status","has_secret","created_at"],"properties":{"config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ProviderConfig","description":"Typed provider config — allowlist and metered-billing mode. Null\nwhen the operator hasn't configured one yet (accept everything)."}]},"created_at":{"type":"string","format":"date-time"},"has_secret":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"last_event_at":{"type":["string","null"],"format":"date-time"},"project_id":{"type":"integer","format":"int32"},"provider":{"type":"string"},"status":{"type":"string"},"webhook_path":{"type":"string","description":"Relative path the UI can display and copy. The frontend builds\nthe full URL by prefixing its own origin."},"webhook_path_token":{"type":"string","description":"Unguessable token embedded in the public webhook URL. The full\nURL is `{api_origin}/webhooks/revenue/{provider}/{webhook_path_token}`."}}},"IpAccessControlQuery":{"type":"object","description":"Query parameters for listing IP access control rules","properties":{"action":{"type":["string","null"],"description":"Filter by action (\"block\" or \"allow\")"}}},"IpAccessControlResponse":{"type":"object","description":"Response model for IP access control rules","required":["id","ip_address","action","created_at","updated_at"],"properties":{"action":{"type":"string"},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609Z"},"created_by":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":"string"},"reason":{"type":["string","null"]},"updated_at":{"type":"string","example":"2025-10-12T12:15:47.609Z"}}},"JobStatusResponse":{"type":"object","description":"Snapshot of a background job. `status` is one of \"running\" | \"exited\"\n| \"failed\"; `exit_code` is populated only when `status == \"exited\"`.","required":["status","stdout","stderr"],"properties":{"exit_code":{"type":["integer","null"],"format":"int32"},"reason":{"type":["string","null"]},"status":{"type":"string"},"stderr":{"type":"string"},"stdout":{"type":"string"}}},"JobSummaryResponse":{"type":"object","description":"Row in the jobs list. Omits stdout/stderr so a noisy dev server doesn't\nbloat the list payload — callers drill into `GET /jobs/{id}` for the\nfull buffer.","required":["id","status","cmd","started_at"],"properties":{"cmd":{"type":"string"},"exit_code":{"type":["integer","null"],"format":"int32"},"id":{"type":"string"},"reason":{"type":["string","null"]},"started_at":{"type":"string"},"status":{"type":"string"}}},"JoinTokenStatusResponse":{"type":"object","description":"Response for join token status check","required":["has_token"],"properties":{"has_token":{"type":"boolean","description":"Whether a join token has been configured"}}},"JourneyEvent":{"type":"object","description":"A single event in the visitor journey timeline","required":["id","event_type","event_name","occurred_at","is_entry","is_exit","is_bounce"],"properties":{"event_data":{"description":"Custom event properties (for custom events)"},"event_name":{"type":"string","description":"Resolved event name (event_name for custom events, event_type for system events)"},"event_type":{"type":"string","description":"Event type: \"page_view\", \"page_leave\", \"custom\", \"web_vitals\""},"id":{"type":"integer","format":"int64","description":"Event ID"},"is_bounce":{"type":"boolean","description":"Whether this was a bounce"},"is_entry":{"type":"boolean","description":"Whether this is the entry page of the session"},"is_exit":{"type":"boolean","description":"Whether this is the exit page of the session"},"occurred_at":{"type":"string","format":"date-time","description":"When the event occurred"},"page_path":{"type":["string","null"],"description":"Page path where the event happened"},"page_title":{"type":["string","null"],"description":"Page title (if available)"},"referrer":{"type":["string","null"],"description":"Referrer URL for this event"},"scroll_depth":{"type":["integer","null"],"format":"int32","description":"Scroll depth percentage (0-100)"},"session_page_number":{"type":["integer","null"],"format":"int32","description":"Page number within the session (1-indexed)"},"time_on_page":{"type":["integer","null"],"format":"int32","description":"Time spent on page in seconds (computed, not from column)"}}},"JourneySession":{"type":"object","description":"A session within the visitor journey, grouping events","required":["session_id","started_at","duration_seconds","page_views","events_count","is_bounced","is_engaged","events"],"properties":{"channel":{"type":["string","null"],"description":"Traffic source: channel (e.g. \"organic\", \"direct\", \"social\")"},"duration_seconds":{"type":"integer","format":"int64","description":"Session duration in seconds"},"ended_at":{"type":["string","null"],"format":"date-time","description":"When the session ended"},"entry_path":{"type":["string","null"],"description":"Entry page path"},"events":{"type":"array","items":{"$ref":"#/components/schemas/JourneyEvent"},"description":"Events within this session, ordered chronologically"},"events_count":{"type":"integer","format":"int64","description":"Total events in this session"},"exit_path":{"type":["string","null"],"description":"Exit page path"},"is_bounced":{"type":"boolean","description":"Whether the session was a bounce"},"is_engaged":{"type":"boolean","description":"Whether the visitor was engaged (had non-pageview events)"},"page_views":{"type":"integer","format":"int64","description":"Number of page views in this session"},"referrer":{"type":["string","null"],"description":"Traffic source: referrer URL"},"referrer_hostname":{"type":["string","null"],"description":"Traffic source: referrer hostname"},"session_id":{"type":"integer","format":"int32","description":"Session internal ID"},"started_at":{"type":"string","format":"date-time","description":"When the session started"},"utm_campaign":{"type":["string","null"],"description":"UTM campaign parameter"},"utm_medium":{"type":["string","null"],"description":"UTM medium parameter"},"utm_source":{"type":["string","null"],"description":"UTM source parameter"}}},"KeysRequest":{"type":"object","description":"Request to get keys matching a pattern","required":["pattern"],"properties":{"pattern":{"type":"string","description":"Pattern to match (supports * and ? wildcards)","example":"user:*"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"KeysResponse":{"type":"object","description":"Response for keys operation","required":["keys"],"properties":{"keys":{"type":"array","items":{"type":"string"},"description":"List of matching keys","example":["user:1","user:2","user:3"]}}},"KillJobBody":{"type":"object","properties":{"force":{"type":"boolean","description":"When true, sends SIGKILL immediately. Defaults to SIGTERM so the\nprocess gets a chance to flush (mirrors `Command.kill()` in\n`@vercel/sandbox`, which also accepts a signal override)."}},"additionalProperties":false},"KnownAiAgentsResponse":{"type":"object","description":"Response listing every AI agent the detector knows about.","required":["items"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AiAgentDescriptor"}}}},"KvStatusResponse":{"type":"object","description":"Response for KV service status","required":["enabled","healthy"],"properties":{"docker_image":{"type":["string","null"],"description":"Docker image being used","example":"gotempsh/redis-walg:8-bookworm"},"enabled":{"type":"boolean","description":"Whether the KV service is enabled"},"healthy":{"type":"boolean","description":"Whether the underlying Redis service is healthy"},"version":{"type":["string","null"],"description":"Service version","example":"7.2"}}},"LemonSqueezyConfig":{"type":"object","properties":{"product_allowlist":{"type":"array","items":{"type":"string"}},"variant_allowlist":{"type":"array","items":{"type":"string"}}}},"LetsEncryptSettings":{"type":"object","properties":{"email":{"type":["string","null"],"default":null},"environment":{"type":"string","default":"production"}}},"LineContext":{"type":"object","description":"Raw surrounding lines for a single match (grep -C style).","required":["before","after"],"properties":{"after":{"type":"array","items":{"$ref":"#/components/schemas/ContextLine"},"description":"Lines immediately after the match, oldest-first."},"before":{"type":"array","items":{"$ref":"#/components/schemas/ContextLine"},"description":"Lines immediately before the match, oldest-first."}}},"LinkServiceRequest":{"type":"object","required":["project_id"],"properties":{"project_id":{"type":"integer","format":"int32"}}},"ListAgentsResponse":{"type":"object","required":["items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AgentConfigResponse"}},"total":{"type":"integer","minimum":0}}},"ListApiKeysQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","minimum":0},"page_size":{"type":["integer","null"],"format":"int64","minimum":0}}},"ListAuditLogsQuery":{"type":"object","description":"Query parameters for listing audit logs.\n\nEvery field is optional — omitting one means \"don't filter on it\". Deriving\n`IntoParams` makes utoipa render them as optional query params with the\ncorrect types; the previous hand-written `params((\"operation_type\", Query,\n…))` tuples defaulted every param to `required: true, type: string`, which\nmisled both API clients and the AI `describe_api`/`call_api` tools into\nthinking all filters were mandatory.","properties":{"from":{"type":["string","null"],"format":"date-time","description":"Start timestamp (milliseconds since epoch)"},"limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of logs to return"},"offset":{"type":["integer","null"],"format":"int32","description":"Number of logs to skip"},"operation_type":{"type":["string","null"],"description":"Filter logs by operation type (omit for all)"},"to":{"type":["string","null"],"format":"date-time","description":"End timestamp (milliseconds since epoch)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter logs by user ID (omit for all users)"}}},"ListBlobsQuery":{"type":"object","description":"Query parameters for listing blobs","properties":{"cursor":{"type":["string","null"],"description":"Continuation token for pagination"},"limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of items to return","example":100},"prefix":{"type":["string","null"],"description":"Prefix to filter by","example":"images/"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"ListBlobsResponse":{"type":"object","description":"Response for listing blobs","required":["blobs","hasMore"],"properties":{"blobs":{"type":"array","items":{"$ref":"#/components/schemas/BlobResponse"},"description":"List of blobs"},"cursor":{"type":["string","null"],"description":"Continuation token for next page"},"hasMore":{"type":"boolean","description":"Whether there are more results","example":false}}},"ListCustomDomainsResponse":{"type":"object","required":["domains","total"],"properties":{"domains":{"type":"array","items":{"$ref":"#/components/schemas/CustomDomainResponse"}},"total":{"type":"integer","minimum":0}}},"ListDeploymentTokensQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","example":1,"minimum":0},"page_size":{"type":["integer","null"],"format":"int64","example":20,"minimum":0}}},"ListDomainsResponse":{"type":"object","required":["domains","total","page","page_size"],"properties":{"domains":{"type":"array","items":{"$ref":"#/components/schemas/DomainResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"ListEntitiesQuery":{"type":"object","properties":{"limit":{"type":"integer","description":"Maximum number of entities to return","example":100,"minimum":0},"token":{"type":["string","null"],"description":"Continuation token for pagination (backend-specific)"}}},"ListErrorEventsQuery":{"type":"object","properties":{"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0}}},"ListErrorGroupsQuery":{"type":"object","properties":{"end_date":{"type":["string","null"],"format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"sort_by":{"type":["string","null"]},"sort_order":{"type":"string"},"start_date":{"type":["string","null"],"format":"date-time"},"status":{"type":["string","null"]}}},"ListJobsResponse":{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/JobSummaryResponse"}}}},"ListMcpsResponse":{"type":"object","description":"Concrete list wrapper for MCP server definitions (utoipa requires non-generic types).","required":["items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/McpDefinitionResponse"}},"total":{"type":"integer","minimum":0}}},"ListOnDemandCertsResponse":{"type":"object","description":"Paginated list of on-demand cert attempts (ADR-018 §5 console \"Certificates\"\nsurface). Joined with current `domains.status`, newest first.","required":["certs","total","page","page_size"],"properties":{"certs":{"type":"array","items":{"$ref":"#/components/schemas/OnDemandCertRow"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"ListOrdersResponse":{"type":"object","required":["orders"],"properties":{"orders":{"type":"array","items":{"$ref":"#/components/schemas/AcmeOrderResponse"}}}},"ListPresetsResponse":{"type":"object","required":["presets","total"],"properties":{"presets":{"type":"array","items":{"$ref":"#/components/schemas/PresetResponse"}},"total":{"type":"integer","minimum":0}}},"ListRunsResponse":{"type":"object","required":["items","total","page","page_size"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AgentRunResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"ListSandboxesResponse":{"type":"object","description":"SDK list response: `{ sandboxes: [...], pagination: {...} }`.","required":["sandboxes","pagination"],"properties":{"pagination":{"$ref":"#/components/schemas/Pagination"},"sandboxes":{"type":"array","items":{"$ref":"#/components/schemas/SandboxInner"}}}},"ListScansQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","example":1,"minimum":0},"page_size":{"type":["integer","null"],"format":"int64","example":20,"minimum":0}}},"ListSecretsResponse":{"type":"object","required":["items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/SecretResponse"}},"total":{"type":"integer","minimum":0}}},"ListSkillsResponse":{"type":"object","description":"Concrete list wrapper for skill definitions (utoipa requires non-generic types).","required":["items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/SkillDefinitionResponse"}},"total":{"type":"integer","minimum":0}}},"ListTagsResponse":{"type":"object","description":"Response for listing tags","required":["tags","total"],"properties":{"tags":{"type":"array","items":{"type":"string"},"description":"List of available tags"},"total":{"type":"integer","description":"Total number of tags","minimum":0}}},"ListTemplatesQuery":{"type":"object","description":"Query parameters for listing templates","properties":{"featured":{"type":["boolean","null"],"description":"Only return featured templates"},"tag":{"type":["string","null"],"description":"Filter templates by tag"}}},"ListTemplatesResponse":{"type":"object","description":"Response for listing templates","required":["templates","total"],"properties":{"templates":{"type":"array","items":{"$ref":"#/components/schemas/TemplateResponse"},"description":"List of templates"},"total":{"type":"integer","description":"Total number of templates","minimum":0}}},"ListVulnerabilitiesQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","example":1,"minimum":0},"page_size":{"type":["integer","null"],"format":"int64","example":20,"minimum":0},"severity":{"type":["string","null"],"example":"CRITICAL"}}},"LiveVisitorInfo":{"type":"object","required":["id","visitor_id","project_id","environment_id","first_seen","last_seen","is_crawler"],"properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"crawler_name":{"type":["string","null"]},"current_page":{"type":["string","null"],"description":"Most recent page path visited by this visitor"},"custom_data":{},"environment_id":{"type":"integer","format":"int32"},"first_channel":{"type":["string","null"],"description":"Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")"},"first_referrer":{"type":["string","null"],"description":"Full referrer URL from the visitor's first session"},"first_referrer_hostname":{"type":["string","null"],"description":"Hostname extracted from first_referrer"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":["string","null"]},"ip_address_id":{"type":["integer","null"],"format":"int32"},"is_crawler":{"type":"boolean"},"is_eu":{"type":["boolean","null"]},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"latitude":{"type":["number","null"],"format":"double"},"longitude":{"type":["number","null"],"format":"double"},"project_id":{"type":"integer","format":"int32"},"region":{"type":["string","null"]},"timezone":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":"string"}}},"LiveVisitorsListResponse":{"type":"object","required":["total_count","visitors","window_minutes"],"properties":{"total_count":{"type":"integer","format":"int64"},"visitors":{"type":"array","items":{"$ref":"#/components/schemas/LiveVisitorInfo"}},"window_minutes":{"type":"integer","format":"int32"}}},"LocationCount":{"type":"object","required":["location","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"location":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"LocationGranularity":{"type":"string","enum":["country","region","city"]},"LocationInfo":{"type":"object","properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"region":{"type":["string","null"]}}},"LogLevel":{"type":"string","description":"Normalized log level","enum":["TRACE","DEBUG","INFO","WARN","ERROR"]},"LogRecord":{"type":"object","description":"A single log record ready for storage.","required":["project_id","resource","timestamp","observed_timestamp","severity","severity_text","body","attributes"],"properties":{"attributes":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"body":{"type":"string"},"deployment_id":{"type":["integer","null"],"format":"int32"},"observed_timestamp":{"type":"string","format":"date-time"},"project_id":{"type":"integer","format":"int32"},"resource":{"$ref":"#/components/schemas/ResourceInfo"},"severity":{"$ref":"#/components/schemas/LogSeverity"},"severity_text":{"type":"string"},"span_id":{"type":["string","null"]},"timestamp":{"type":"string","format":"date-time"},"trace_id":{"type":["string","null"]}}},"LogSearchLine":{"type":"object","description":"A single line in search results","required":["timestamp","level","service","message","chunk_id","line_offset"],"properties":{"chunk_id":{"type":"string"},"container_id":{"type":"string","description":"Container this line came from — lets the UI tag/group lines by container\nin a combined (\"show all\") multi-container view."},"context":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/LineContext","description":"Raw surrounding lines (grep -C). `None` unless `context_lines > 0` was\nrequested. Overlapping windows between nearby matches are merged: the\nshared neighbors appear on the earlier match only, so the frontend can\nrender one continuous block without duplicated lines."}]},"deploy_id":{"type":["integer","null"],"format":"int32"},"fields":{},"level":{"$ref":"#/components/schemas/LogLevel"},"line_offset":{"type":"integer","format":"int32"},"message":{"type":"string"},"node_id":{"type":["integer","null"],"format":"int32","description":"Worker node the line came from (`None` = control-plane-local)."},"node_name":{"type":["string","null"],"description":"Human-readable node name for display."},"service":{"type":"string"},"timestamp":{"type":"string"}}},"LogSeverity":{"type":"string","description":"Log severity level (simplified from OTel's 24 levels).","enum":["TRACE","DEBUG","INFO","WARN","ERROR","FATAL"]},"LogSource":{"type":"object","description":"A distinct log source (container) seen in the queried scope. Used to populate\nthe history filter dropdowns with the *full* set of containers/nodes for the\nproject + env + deployment + time window — independent of the active\ncontainer/node/service filter, so the user can switch between them.","required":["container_id","service"],"properties":{"container_id":{"type":"string"},"node_id":{"type":["integer","null"],"format":"int32"},"node_name":{"type":["string","null"]},"service":{"type":"string"}}},"LogStream":{"type":"string","description":"Log output stream","enum":["stdout","stderr"]},"LoginRequest":{"type":"object","required":["email","password"],"properties":{"email":{"type":"string"},"password":{"type":"string"}}},"LogsQuery":{"type":"object","properties":{"tail":{"type":["integer","null"],"description":"Number of lines to return from the tail. Defaults to 200, capped at 2000.","minimum":0}}},"LogsResponse":{"type":"object","required":["data","count"],"properties":{"count":{"type":"integer","minimum":0},"data":{"type":"array","items":{"$ref":"#/components/schemas/LogRecord"}}}},"ManagedDomainResponse":{"type":"object","description":"Managed domain response","required":["id","provider_id","domain","auto_manage","verified","generated_hostname_mode","sync_generated_records","created_at","updated_at"],"properties":{"auto_manage":{"type":"boolean"},"created_at":{"type":"string"},"domain":{"type":"string"},"generated_hostname_mode":{"type":"string","description":"Generated hostname layout: `\"standard\"` or `\"flat\"`."},"id":{"type":"integer","format":"int32"},"provider_id":{"type":"integer","format":"int32"},"sync_generated_records":{"type":"boolean","description":"Whether generated hostnames are reconciled into the provider's DNS zone."},"updated_at":{"type":"string"},"verification_error":{"type":["string","null"]},"verified":{"type":"boolean"},"verified_at":{"type":["string","null"]},"zone_access_error":{"type":["string","null"],"description":"Detail for a failed zone-access check."},"zone_access_ok":{"type":["boolean","null"],"description":"Last token zone-access check: `Some(true)`/`Some(false)`/`None` (unchecked)."},"zone_id":{"type":["string","null"]}}},"ManualAction":{"type":"object","description":"A manual action the user must perform outside of the automated migration","required":["timing","description","reason"],"properties":{"description":{"type":"string","description":"Human-readable description"},"reason":{"type":"string","description":"Why this can't be automated"},"timing":{"$ref":"#/components/schemas/ManualActionTiming","description":"When this action needs to happen"}}},"ManualActionTiming":{"type":"string","description":"When a manual action needs to happen relative to migration","enum":["before-migration","after-migration","within-hours"]},"McpDefinitionResponse":{"type":"object","required":["id","slug","name","config","created_at","updated_at"],"properties":{"config":{"type":"object"},"created_at":{"type":"string"},"description":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"project_id":{"type":["integer","null"],"format":"int32"},"slug":{"type":"string"},"updated_at":{"type":"string"}}},"MessageContent":{"oneOf":[{"type":"string"},{"type":"array","items":{"$ref":"#/components/schemas/ContentPart"}}]},"MessagePart":{"oneOf":[{"type":"object","required":["text","type"],"properties":{"text":{"type":"string"},"type":{"type":"string","enum":["text"]}}},{"type":"object","required":["tool","type"],"properties":{"tool":{"$ref":"#/components/schemas/ToolInfo"},"type":{"type":"string","enum":["tool"]}}}],"description":"One ordered segment of an assistant turn: a chunk of prose, or a tool\ninvocation. Mirrors the `metadata.parts` persisted by the chat service."},"MessageResponse":{"type":"object","required":["role","content","created_at"],"properties":{"content":{"type":"string"},"created_at":{"type":"string"},"parts":{"type":["array","null"],"items":{"$ref":"#/components/schemas/MessagePart"},"description":"Ordered render segments (text / tool, in the order they occurred) so a\nreloaded chat shows the same interleaving as the live stream. Absent for\nolder messages persisted before parts were tracked; the client then falls\nback to `tools` (rendered first) + `content`."},"role":{"type":"string"},"tools":{"type":["array","null"],"items":{"$ref":"#/components/schemas/ToolInfo"},"description":"Tools the assistant ran on this turn (persisted in message metadata), so\nthe chat replays its tool work after a reload. Absent for plain turns."}}},"MeteredMode":{"type":"string","description":"How to treat metered-billing subscriptions when computing MRR.\n\n* `DeriveFromInvoices` (default): ignore the subscription row's\n `mrr_minor` for metered items and rely on the per-invoice\n [`NormalizedEventType::MrrRealized`] events instead. Correct for\n pure-metered, hybrid, tiered, and flat — recommended.\n* `UseSubscription`: trust whatever MRR the subscription parser\n returns (0 for metered). Legacy behavior.\n* `Ignore`: drop metered subscriptions from MRR entirely.","enum":["derive_from_invoices","use_subscription","ignore"]},"MetricAggregation":{"oneOf":[{"type":"string","description":"Arithmetic mean of the scalar value in each bucket. The default.","enum":["avg"]},{"type":"string","description":"Sum of the scalar value in each bucket.","enum":["sum"]},{"type":"string","description":"Minimum scalar value in each bucket.","enum":["min"]},{"type":"string","description":"Maximum scalar value in each bucket.","enum":["max"]},{"type":"string","description":"Number of points in each bucket.","enum":["count"]},{"type":"string","description":"Per-second rate of change of a cumulative monotonic counter, computed as\n`(max - min) / window_seconds` within each bucket. Non-monotonic series\nfall back to a simple delta.","enum":["rate_per_sec"]},{"type":"object","description":"A quantile of the scalar value in each bucket. The carried `f64` is the\nrequested quantile in `[0.0, 1.0]`.","required":["quantile"],"properties":{"quantile":{"type":"number","format":"double","description":"A quantile of the scalar value in each bucket. The carried `f64` is the\nrequested quantile in `[0.0, 1.0]`."}}}],"description":"The aggregation applied when reducing raw metric points into a time bucket.\n\nStore-neutral: every storage backend (ClickHouse today, TimescaleDB later)\nmust be able to satisfy this contract. `Quantile(q)` carries the requested\nquantile in `[0.0, 1.0]` (e.g. `0.95` for p95)."},"MetricBucket":{"type":"object","description":"A time-bucketed metric aggregate for chart display.\n\nStore-neutral response contract. The legacy scalar fields\n(`avg_value`/`min_value`/`max_value`/`count`) are always populated for chart\nback-compat. The richer fields describe the explicitly-requested\n[`MetricAggregation`] (`value`), optional `quantiles`, an optional\n`histogram_summary`, and a `series_key` identifying the label-set when the\nquery used `group_by`.","required":["bucket","avg_value","min_value","max_value","count"],"properties":{"avg_value":{"type":"number","format":"double"},"bucket":{"type":"string","format":"date-time"},"count":{"type":"integer","format":"int64"},"histogram_summary":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/HistogramSummary","description":"A reduced histogram summary when the bucketed metric is a histogram."}]},"max_value":{"type":"number","format":"double"},"min_value":{"type":"number","format":"double"},"quantiles":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"number","format":"double"},{"type":"number","format":"double"}]},"description":"Computed quantile/value pairs `(quantile, value)` when the query asked for\nquantile aggregation; otherwise empty."},"series_key":{"type":["array","null"],"items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"The label-set this bucket belongs to, as ordered `(key, value)` pairs,\nwhen the query grouped by labels. Empty/`None` = the single ungrouped\naggregate stream."},"value":{"type":"number","format":"double","description":"The value of the requested [`MetricAggregation`] for this bucket. For the\ndefault `Avg` aggregation this equals `avg_value`. `#[serde(default)]` so\npre-existing payloads (which only carried avg/min/max/count) still parse."}}},"MetricDataPoint":{"type":"object","description":"A single `(timestamp, value)` data point in a metric series.","required":["time","value"],"properties":{"time":{"type":"string","description":"ISO 8601 timestamp with `Z` suffix."},"value":{"type":"number","format":"double","description":"Metric value at this bucket."}}},"MetricType":{"type":"string","description":"The type of an OTel metric.","enum":["gauge","sum","histogram","exponential_histogram","summary"]},"MetricsOverTimeResponse":{"type":"object","required":["timestamps","ttfb","lcp","fid","fcp","cls","inp"],"properties":{"cls":{"type":"array","items":{"type":["number","null"],"format":"float"}},"cls_p75":{"type":["number","null"],"format":"float"},"cls_p90":{"type":["number","null"],"format":"float"},"cls_p95":{"type":["number","null"],"format":"float"},"cls_p99":{"type":["number","null"],"format":"float"},"fcp":{"type":"array","items":{"type":["number","null"],"format":"float"}},"fcp_p75":{"type":["number","null"],"format":"float"},"fcp_p90":{"type":["number","null"],"format":"float"},"fcp_p95":{"type":["number","null"],"format":"float"},"fcp_p99":{"type":["number","null"],"format":"float"},"fid":{"type":"array","items":{"type":["number","null"],"format":"float"}},"fid_p75":{"type":["number","null"],"format":"float"},"fid_p90":{"type":["number","null"],"format":"float"},"fid_p95":{"type":["number","null"],"format":"float"},"fid_p99":{"type":["number","null"],"format":"float"},"inp":{"type":"array","items":{"type":["number","null"],"format":"float"}},"inp_p75":{"type":["number","null"],"format":"float"},"inp_p90":{"type":["number","null"],"format":"float"},"inp_p95":{"type":["number","null"],"format":"float"},"inp_p99":{"type":["number","null"],"format":"float"},"lcp":{"type":"array","items":{"type":["number","null"],"format":"float"}},"lcp_p75":{"type":["number","null"],"format":"float"},"lcp_p90":{"type":["number","null"],"format":"float"},"lcp_p95":{"type":["number","null"],"format":"float"},"lcp_p99":{"type":["number","null"],"format":"float"},"timestamps":{"type":"array","items":{"type":"string"}},"ttfb":{"type":"array","items":{"type":["number","null"],"format":"float"}},"ttfb_p75":{"type":["number","null"],"format":"float"},"ttfb_p90":{"type":["number","null"],"format":"float"},"ttfb_p95":{"type":["number","null"],"format":"float"},"ttfb_p99":{"type":["number","null"],"format":"float"}}},"MetricsQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"MetricsRangeQuery":{"type":"object","description":"Query params for range metric queries.","required":["metric"],"properties":{"metric":{"type":"string","description":"Metric name, e.g. `\"pg.connections_active\"`."},"percentile":{"type":["number","null"],"format":"double","description":"Optional histogram percentile (0–100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile."},"range":{"type":"string","description":"Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`."}}},"MetricsStatusResponse":{"type":"object","description":"Freshness status: when metrics were last received for this service.","properties":{"last_received_at":{"type":["string","null"],"description":"ISO 8601 timestamp of the most recent metric row, or null if none yet."}}},"MetricsStoreKind":{"type":"string","description":"Which storage backend to use for the MetricsStore.","enum":["timescale_db","click_house"]},"MetricsSummaryResponse":{"type":"object","required":["currency","current_mrr_minor","current_arr_minor","active_subscriptions","active_customers","churned_last_30d","arpu_minor"],"properties":{"active_customers":{"type":"integer","format":"int64"},"active_subscriptions":{"type":"integer","format":"int64"},"arpu_minor":{"type":"integer","format":"int64"},"churned_last_30d":{"type":"integer","format":"int64"},"currency":{"type":"string"},"current_arr_minor":{"type":"integer","format":"int64"},"current_mrr_minor":{"type":"integer","format":"int64"}}},"MfaRequiredResponse":{"type":"object","required":["requires_mfa","session_token"],"properties":{"requires_mfa":{"type":"boolean"},"session_token":{"type":"string"}}},"MfaSetupResponse":{"type":"object","required":["secret_key","qr_code","recovery_codes"],"properties":{"qr_code":{"type":"string"},"recovery_codes":{"type":"array","items":{"type":"string"}},"secret_key":{"type":"string"}}},"MfaVerificationRequest":{"type":"object","required":["code"],"properties":{"code":{"type":"string"}}},"MigrationStep":{"type":"object","description":"A single step in the migration execution plan.\n\nSteps are presented to the user before execution so they know exactly\nwhat will happen. During execution, each step runs in order and reports\nits outcome before proceeding to the next.","required":["order","id","title","description","resource_type","risk","skippable","reversible"],"properties":{"data_implications":{"type":"array","items":{"$ref":"#/components/schemas/DataImplication"},"description":"Data implications — what could go wrong or what the user needs to know"},"description":{"type":"string","description":"Detailed description of what this step does"},"estimated_duration":{"type":["string","null"],"description":"Estimated duration hint (e.g., \"< 1 second\", \"10-30 seconds\")"},"id":{"type":"string","description":"Machine-readable step identifier (e.g., \"create-project\", \"create-service-postgres\")"},"order":{"type":"integer","description":"Step number (1-based, for display)","minimum":0},"post_conditions":{"type":"array","items":{"type":"string"},"description":"Things the user should verify AFTER this step completes"},"pre_conditions":{"type":"array","items":{"type":"string"},"description":"Things the user should verify BEFORE this step runs"},"resource_type":{"$ref":"#/components/schemas/StepResourceType","description":"What kind of resource this step creates/modifies"},"reversible":{"type":"boolean","description":"Whether this step is reversible (can be cleaned up on failure)"},"risk":{"$ref":"#/components/schemas/RiskLevel","description":"Risk level for this step"},"skippable":{"type":"boolean","description":"Whether this step can be skipped by the user"},"skipped":{"type":"boolean","description":"Whether the user has chosen to skip this step (set during review)"},"title":{"type":"string","description":"Human-readable title (e.g., \"Create project 'my-app'\")"}}},"MigrationSummary":{"type":"object","description":"Human-readable summary of the entire migration plan","required":["headline","overall_risk","resource_counts"],"properties":{"critical_warnings":{"type":"array","items":{"type":"string"},"description":"Critical warnings that must be acknowledged before proceeding.\nThese are the most important things the user needs to know."},"headline":{"type":"string","description":"One-line summary (e.g., \"Migrate 'my-app' from Vercel with 1 database, 2 domains\")"},"manual_actions_required":{"type":"array","items":{"$ref":"#/components/schemas/ManualAction"},"description":"Manual actions the user must perform (before or after migration)"},"overall_risk":{"$ref":"#/components/schemas/RiskLevel","description":"Overall risk assessment for the migration"},"resource_counts":{"$ref":"#/components/schemas/ResourceCounts","description":"Resource counts for quick overview"},"unsupported_features":{"type":"array","items":{"$ref":"#/components/schemas/UnsupportedFeature"},"description":"Features from the source platform that cannot be migrated"}}},"MintEnrollmentTokenRequest":{"type":"object","properties":{"bound_node_name":{"type":["string","null"],"description":"Optional: restrict the token to register one specific node name."},"max_uses":{"type":["integer","null"],"format":"int32","description":"Maximum registrations this token may authorize (default 1)."},"ttl_secs":{"type":["integer","null"],"format":"int64","description":"Time-to-live in seconds (default 3600 = 1h)."}}},"MintEnrollmentTokenResponse":{"type":"object","required":["id","token","expires_at","max_uses","message"],"properties":{"ca_fingerprint":{"type":["string","null"],"description":"SHA-256 fingerprint of the cluster CA (if mTLS is set up). Pass it to the\nworker as `temps join --ca-fingerprint ` to verify the CA on join."},"expires_at":{"type":"string"},"id":{"type":"integer","format":"int32"},"max_uses":{"type":"integer","format":"int32"},"message":{"type":"string"},"token":{"type":"string","description":"The plaintext enrollment token — shown only once, save it now."}}},"MiscResult":{"type":"object","description":"Miscellaneous validation result","required":["is_disposable","is_role_account","is_b2c"],"properties":{"gravatar_url":{"type":["string","null"],"description":"Gravatar URL if available"},"is_b2c":{"type":"boolean","description":"Whether the email provider is a B2C (consumer) email provider"},"is_disposable":{"type":"boolean","description":"Whether the email is from a disposable email provider"},"is_role_account":{"type":"boolean","description":"Whether the email is a role-based account (e.g., admin@, info@)"}}},"MkdirBody":{"type":"object","required":["path"],"properties":{"path":{"type":"string"}},"additionalProperties":false},"ModelInfo":{"type":"object","required":["id","object","owned_by"],"properties":{"id":{"type":"string"},"object":{"type":"string"},"owned_by":{"type":"string"}}},"ModelListResponse":{"type":"object","required":["object","data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ModelInfo"}},"object":{"type":"string"}}},"ModelPricing":{"type":"object","description":"Pricing for a single model, all values in USD per 1M tokens.\nFields are optional because not every provider supports every pricing tier.","required":["model","display_name","provider","input_per_million","output_per_million"],"properties":{"batch_input_per_million":{"type":["number","null"],"format":"double","description":"Batch API input cost per 1M tokens (if provider offers batch pricing)"},"batch_output_per_million":{"type":["number","null"],"format":"double","description":"Batch API output cost per 1M tokens"},"cache_hit_per_million":{"type":["number","null"],"format":"double","description":"Cache hit / refresh cost per 1M tokens"},"cache_write_1h_per_million":{"type":["number","null"],"format":"double","description":"1-hour cache write cost per 1M tokens"},"cache_write_5m_per_million":{"type":["number","null"],"format":"double","description":"5-minute cache write cost per 1M tokens (Anthropic-style prompt caching)"},"deprecated":{"type":"boolean","description":"Whether the model is deprecated"},"display_name":{"type":"string","description":"Human-readable model name (e.g. \"Claude Sonnet 4.6\")"},"input_per_million":{"type":"number","format":"double","description":"Base input token cost per 1M tokens"},"model":{"type":"string","description":"Model identifier (e.g. \"gpt-5.4\", \"claude-sonnet-4-6\")"},"output_per_million":{"type":"number","format":"double","description":"Output token cost per 1M tokens"},"provider":{"type":"string","description":"Provider ID (e.g. \"openai\", \"anthropic\")"}}},"ModelUsage":{"type":"object","required":["model","provider","request_count","input_tokens","output_tokens","total_tokens","avg_latency_ms"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"input_tokens":{"type":"integer","format":"int64"},"model":{"type":"string"},"output_tokens":{"type":"integer","format":"int64"},"provider":{"type":"string"},"request_count":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"MonitorResponse":{"type":"object","required":["id","project_id","name","monitor_type","monitor_url","check_interval_seconds","is_active","created_at","updated_at"],"properties":{"check_interval_seconds":{"type":"integer","format":"int32"},"check_path":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"monitor_type":{"type":"string"},"monitor_url":{"type":"string"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","format":"date-time"}}},"MonitorStatus":{"type":"object","required":["monitor","current_status","uptime_percentage"],"properties":{"avg_response_time_ms":{"type":["integer","null"],"format":"int32"},"current_status":{"type":"string"},"monitor":{"$ref":"#/components/schemas/MonitorResponse"},"uptime_percentage":{"type":"number","format":"double"}}},"MonitoringSettings":{"type":"object","description":"Global metrics observability configuration.\n\nControls whether the MetricsScraper and AlertEvaluator background tasks\nare active, which storage backend they write to, and how long data is kept\nat each retention tier.","properties":{"clickhouse_url":{"type":["string","null"],"description":"ClickHouse DSN (legacy, optional). The runtime metrics store is built\nfrom the `TEMPS_CLICKHOUSE_*` env vars, never from this field; it is\nretained for compatibility and operator reference only.\nExample: `\"http://localhost:8123\"`.","default":null},"enabled":{"type":"boolean","description":"Enable or disable all metrics collection (scraping + alerting).\nDefaults to `false` so new installs don't write to TimescaleDB until\nan operator explicitly enables the feature.","default":false},"retention_daily_years":{"type":"integer","format":"int32","description":"How many years of daily-aggregate data to keep (converted to days internally).","default":2,"example":2,"maximum":10,"minimum":1},"retention_hourly_days":{"type":"integer","format":"int32","description":"How many days of hourly-aggregate data to keep.","default":90,"example":90,"minimum":1},"retention_raw_days":{"type":"integer","format":"int32","description":"How many days of raw (30 s resolution) metric data to keep.","default":7,"example":7,"minimum":1},"scrape_interval_secs":{"type":"integer","format":"int64","description":"How often the MetricsScraper collects data from all sources, in seconds.\nMinimum effective value is 10 s; values below that are clamped at runtime.","default":30,"example":30,"minimum":10},"store":{"oneOf":[{"$ref":"#/components/schemas/MetricsStoreKind","description":"Storage backend for metric data."}],"default":"timescale_db"}}},"MonitoringSettingsMasked":{"type":"object","description":"Monitoring settings with the ClickHouse DSN masked.\n\n`clickhouse_url` can embed credentials (`http://user:pass@host`), so it is\nreported only as a boolean (`clickhouse_url_set`) rather than echoed back —\nconsistent with how the DNS API key and Docker registry password are masked.","required":["enabled","store","scrape_interval_secs","retention_raw_days","retention_hourly_days","retention_daily_years","clickhouse_url_set"],"properties":{"clickhouse_url_set":{"type":"boolean","description":"True when a ClickHouse DSN is configured. The DSN itself is never\nreturned over HTTP because it may contain credentials."},"enabled":{"type":"boolean"},"retention_daily_years":{"type":"integer","format":"int32","minimum":0},"retention_hourly_days":{"type":"integer","format":"int32","minimum":0},"retention_raw_days":{"type":"integer","format":"int32","minimum":0},"scrape_interval_secs":{"type":"integer","format":"int64","minimum":0},"store":{"$ref":"#/components/schemas/MetricsStoreKind"}}},"MrrBucketResponse":{"type":"object","required":["bucket","mrr_minor","charge_total_minor","refund_total_minor","charge_count"],"properties":{"bucket":{"type":"string","format":"date-time"},"charge_count":{"type":"integer","format":"int64"},"charge_total_minor":{"type":"integer","format":"int64"},"mrr_minor":{"type":"integer","format":"int64"},"refund_total_minor":{"type":"integer","format":"int64"}}},"MultiNodeSettings":{"type":"object","description":"Multi-node cluster settings","properties":{"cluster_ca_cert_pem":{"type":["string","null"],"description":"Per-cluster CA certificate (PEM) for multi-node mTLS (ADR-020 WS-2.1).\nPublic — distributed to nodes as the trust root and used by the control\nplane as the root for verifying agent server certs. Minted lazily on the\nfirst CSR-bearing registration.","default":null},"cluster_ca_key_encrypted":{"type":["string","null"],"description":"Per-cluster CA private key, AES-256-GCM ciphertext (EncryptionService).\nSECRET — never returned over HTTP (elided in the masked response).","default":null},"join_token_hash":{"type":["string","null"],"description":"SHA-256 hash of the join token (never store plaintext)","default":null},"legacy_shared_token_enabled":{"type":"boolean","description":"Whether the legacy single shared join token is still accepted for node\nregistration (ADR-020 WS-1.1). Defaults to `true` so existing clusters\nkeep working on upgrade; fresh installs should set it `false` and rely on\nshort-lived, single-use enrollment tokens instead.","default":true},"node_cpu_alert_percent":{"type":["number","null"],"format":"double","description":"CPU-usage percent above which a worker node raises a resource alert\n(ADR-020 / monitoring). `None` disables CPU alerting. Default 90.","default":90.0},"node_disk_alert_percent":{"type":["number","null"],"format":"double","description":"Disk-usage percent above which a worker node raises a resource alert.\n`None` disables disk alerting. Default 90.","default":90.0},"node_memory_alert_percent":{"type":["number","null"],"format":"double","description":"Memory-usage percent above which a worker node raises a resource alert.\n`None` disables memory alerting. Default 90.","default":90.0},"private_address":{"type":["string","null"],"description":"Private/WireGuard IP address of the control plane node.\nUsed by remote worker nodes to reach services (databases, etc.) running on the control plane.\nSet via `--private-address` or `TEMPS_PRIVATE_ADDRESS`.","default":null},"require_mtls":{"type":"boolean","description":"Whether to enforce multi-node mTLS (ADR-020 WS-2.1). When `false`\n(default), the control plane ignores join-time CSRs and nodes keep\nserving plaintext HTTP — zero behavior change. When `true`, the CP signs\nnode CSRs, nodes serve mutual TLS, and every CP→agent call uses the\ncluster client cert. Observe-then-enforce: flip this on only once all\nworkers have re-enrolled with certs.","default":false}}},"MultiNodeSettingsMasked":{"type":"object","description":"Multi-node settings with `join_token_hash` elided.","required":["has_join_token","require_mtls","legacy_shared_token_enabled"],"properties":{"cluster_ca_fingerprint":{"type":["string","null"],"description":"SHA-256 fingerprint of the cluster CA certificate (public — operators can\nverify it out of band; the CA private key is never exposed)."},"has_join_token":{"type":"boolean"},"legacy_shared_token_enabled":{"type":"boolean","description":"Whether the deprecated shared join token is still accepted."},"node_cpu_alert_percent":{"type":["number","null"],"format":"double","description":"Node resource-alert thresholds (percent); `None` = that alert disabled."},"node_disk_alert_percent":{"type":["number","null"],"format":"double"},"node_memory_alert_percent":{"type":["number","null"],"format":"double"},"private_address":{"type":["string","null"]},"require_mtls":{"type":"boolean","description":"Whether control-plane↔agent mutual TLS is enforced."}}},"MxResult":{"type":"object","description":"MX (Mail Exchange) validation result","required":["accepts_mail","records"],"properties":{"accepts_mail":{"type":"boolean","description":"Whether the domain accepts mail"},"error":{"type":["string","null"],"description":"Error message if MX lookup failed"},"records":{"type":"array","items":{"type":"string"},"description":"List of MX records for the domain","example":["alt1.gmail-smtp-in.l.google.com.","gmail-smtp-in.l.google.com."]}}},"NavEntry":{"type":"object","description":"A navigation entry that the plugin contributes to the Temps UI.","required":["label","icon","section","path","order"],"properties":{"icon":{"type":"string","description":"Lucide icon name (e.g., \"puzzle\", \"database\", \"activity\")"},"label":{"type":"string","description":"Display label in the sidebar"},"order":{"type":"integer","format":"int32","description":"Sort order within the section (lower = higher in list)","minimum":0},"path":{"type":"string","description":"Client-side route path (e.g., \"/my-plugin\")"},"section":{"$ref":"#/components/schemas/NavSection","description":"Which sidebar section this entry belongs to"}}},"NavSection":{"type":"string","description":"Where the plugin's nav entry appears in the Temps UI sidebar.","enum":["platform","settings","project"]},"NetworkConfiguration":{"type":"object","description":"Network configuration","required":["mode","dns_servers"],"properties":{"dns_servers":{"type":"array","items":{"type":"string"},"description":"DNS servers"},"hostname":{"type":["string","null"],"description":"Hostname"},"mode":{"$ref":"#/components/schemas/NetworkMode","description":"Network mode"}}},"NetworkMode":{"oneOf":[{"type":"string","enum":["bridge"]},{"type":"string","enum":["host"]},{"type":"string","enum":["none"]},{"type":"object","required":["custom"],"properties":{"custom":{"type":"string"}}}],"description":"Network mode"},"NixpacksPresetConfig":{"type":"object","description":"Configuration for Nixpacks preset\nNixpacks provider and inline build-plan configuration.","properties":{"nixpacksConfig":{"type":["string","null"],"description":"Optional inline nixpacks.toml contents."},"providers":{"type":"array","items":{"$ref":"#/components/schemas/NixpacksProvider"},"description":"Ordered Nixpacks providers. Empty means repository config or auto-detect;\ninclude `...` to combine auto-detection with explicit providers."}}},"NixpacksProvider":{"type":"string","description":"A Nixpacks build provider.\n\n`Auto` serializes as the native Nixpacks `...` marker, which includes the\nprovider detected from the project alongside any explicitly listed\nproviders.","enum":["...","node","python","rust","go","java","php","ruby","deno","elixir","csharp","fsharp","dart","swift","zig","scala","haskell","clojure","crystal","cobol","gleam","lunatic","scheme","static"]},"NodeContainerListResponse":{"type":"object","required":["containers","total"],"properties":{"containers":{"type":"array","items":{"$ref":"#/components/schemas/NodeContainerResponse"}},"total":{"type":"integer","minimum":0}}},"NodeContainerResponse":{"type":"object","description":"A container running on a specific node, enriched with project/environment context.","required":["container_id","container_name","image_name","status","created_at","deployment_id","project_id","project_name","environment_id","environment_name"],"properties":{"container_id":{"type":"string"},"container_name":{"type":"string"},"created_at":{"type":"string"},"deployment_id":{"type":"integer","format":"int32"},"environment_id":{"type":"integer","format":"int32"},"environment_name":{"type":"string"},"image_name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"status":{"type":"string"}}},"NodeCostInfo":{"type":"object","description":"One cluster node with capacity and (when priceable) a cost estimate","required":["name","cpu_millis","memory_mb"],"properties":{"cpu_millis":{"type":"integer","format":"int64","description":"CPU capacity in millicores"},"instance_type":{"type":["string","null"],"description":"Instance type from `node.kubernetes.io/instance-type` (e.g. \"m5.xlarge\")"},"memory_mb":{"type":"integer","format":"int64","description":"Memory capacity in MB"},"monthly_usd":{"type":["number","null"],"format":"double","description":"Estimated on-demand monthly price in USD. `None` when the instance\ntype is unknown or not in the price table."},"name":{"type":"string","description":"Node name"},"region":{"type":["string","null"],"description":"Region from `topology.kubernetes.io/region`"}}},"NodeInfoResponse":{"type":"object","required":["id","name","address","private_address","role","status","labels","capacity","created_at"],"properties":{"address":{"type":"string"},"architecture":{"type":["string","null"],"description":"Container platform this node runs (`linux/amd64`, `linux/arm64`).\n`None` until an agent that reports it has heartbeated."},"capacity":{"description":"Resource capacity/usage metrics from the latest heartbeat"},"created_at":{"type":"string"},"id":{"type":"integer","format":"int32"},"labels":{},"last_heartbeat":{"type":["string","null"]},"name":{"type":"string"},"private_address":{"type":"string"},"role":{"type":"string"},"status":{"type":"string"}}},"NodeListResponse":{"type":"object","required":["nodes","total"],"properties":{"nodes":{"type":"array","items":{"$ref":"#/components/schemas/NodeInfoResponse"}},"total":{"type":"integer","minimum":0}}},"NotificationPreferencesResponse":{"type":"object","required":["email_enabled","slack_enabled","batch_similar_notifications","minimum_severity","deployment_failures_enabled","build_errors_enabled","runtime_errors_enabled","error_threshold","error_time_window","ssl_expiration_enabled","ssl_days_before_expiration","domain_expiration_enabled","dns_changes_enabled","backup_failures_enabled","backup_successes_enabled","s3_connection_issues_enabled","retention_policy_violations_enabled","route_downtime_enabled","load_balancer_issues_enabled","weekly_digest_enabled","digest_send_day","digest_send_time","digest_sections"],"properties":{"backup_failures_enabled":{"type":"boolean"},"backup_successes_enabled":{"type":"boolean"},"batch_similar_notifications":{"type":"boolean"},"build_errors_enabled":{"type":"boolean"},"deployment_failures_enabled":{"type":"boolean"},"digest_sections":{"$ref":"#/components/schemas/DigestSections"},"digest_send_day":{"type":"string"},"digest_send_time":{"type":"string"},"dns_changes_enabled":{"type":"boolean"},"domain_expiration_enabled":{"type":"boolean"},"email_enabled":{"type":"boolean"},"error_threshold":{"type":"integer","format":"int32"},"error_time_window":{"type":"integer","format":"int32"},"load_balancer_issues_enabled":{"type":"boolean"},"minimum_severity":{"type":"string"},"retention_policy_violations_enabled":{"type":"boolean"},"route_downtime_enabled":{"type":"boolean"},"runtime_errors_enabled":{"type":"boolean"},"s3_connection_issues_enabled":{"type":"boolean"},"slack_enabled":{"type":"boolean"},"ssl_days_before_expiration":{"type":"integer","format":"int32"},"ssl_expiration_enabled":{"type":"boolean"},"weekly_digest_enabled":{"type":"boolean"}}},"NotificationProviderResponse":{"type":"object","required":["id","name","provider_type","config","enabled","created_at","updated_at"],"properties":{"config":{},"created_at":{"type":"integer","format":"int64"},"enabled":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"provider_type":{"type":"string"},"updated_at":{"type":"integer","format":"int64"}}},"ObservabilityCompressionSettings":{"type":"object","description":"TimescaleDB compression policy configuration for append-only observability\ntables. Values are expressed in hours so operators can choose sub-day\nwindows while keeping the API representation unambiguous.","properties":{"otel_spans_after_hours":{"type":"integer","format":"int32","description":"Compress OpenTelemetry span chunks after this many hours. Defaults to\n24 hours.","default":24,"example":24,"maximum":2160,"minimum":1},"proxy_logs_after_hours":{"type":"integer","format":"int32","description":"Compress proxy-log chunks after this many hours. Defaults to 24 hours.","default":24,"example":24,"maximum":720,"minimum":1}}},"ObservabilityEvent":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/RequestRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["request"]}}}]},{"allOf":[{"$ref":"#/components/schemas/SpanRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["span"]}}}]},{"allOf":[{"$ref":"#/components/schemas/ErrorRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["error"]}}}]},{"allOf":[{"$ref":"#/components/schemas/RevenueRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["revenue"]}}}]}],"description":"Discriminated union of every row that can appear in the Observe list.\n\nSerializes to `{ \"type\": \"request\" | \"span\" | ... , ...rest }` so the UI\ncan switch on `event.type` without ambiguity.\n\n**No `Log` variant**: runtime stdout/stderr lines live on a dedicated\nLogs page rather than Observe. Logs are too high-volume to interleave\nwith business signals (requests, errors, revenue) without dominating\nthe timeline, and they have their own retention/storage constraints\n(TimescaleDB hypertable + chunked file/S3 store) that don't compose\nwith the merge service's per-kind LIMIT strategy."},"ObservabilityRetentionSettings":{"type":"object","description":"Retention policy configuration for raw observability tables. Values are in\ndays. The Settings API applies them to TimescaleDB; ClickHouse-backed proxy\nlogs and spans retain their storage-level per-row TTL behavior.","properties":{"otel_logs_days":{"type":"integer","format":"int32","description":"Retain OpenTelemetry log events for this many days.","default":90,"example":90,"maximum":3650,"minimum":1},"otel_metrics_days":{"type":"integer","format":"int32","description":"Retain OpenTelemetry metric points for this many days.","default":90,"example":90,"maximum":3650,"minimum":1},"otel_spans_days":{"type":"integer","format":"int32","description":"Retain OpenTelemetry spans (traces) for this many days.","default":90,"example":90,"maximum":3650,"minimum":1},"proxy_logs_days":{"type":"integer","format":"int32","description":"Retain proxy request logs for this many days.","default":30,"example":30,"maximum":3650,"minimum":1}}},"OidcProviderResponse":{"type":"object","required":["id","name","issuer_url","client_id","client_secret","scopes","jit_provisioning","enabled","template","group_claim","role_claim","default_role","trust_idp_email"],"properties":{"client_id":{"type":"string"},"client_secret":{"type":"string","description":"Always masked — the secret is never returned after creation."},"default_role":{"type":"string"},"enabled":{"type":"boolean"},"group_claim":{"type":"string"},"id":{"type":"integer","format":"int32"},"issuer_url":{"type":"string"},"jit_provisioning":{"type":"boolean"},"name":{"type":"string"},"role_claim":{"type":"string"},"scopes":{"type":"string"},"template":{"type":"string"},"trust_idp_email":{"type":"boolean","description":"When true, the resolver skips the `email_verified` claim gate\nduring SSO login. Only safe for IdPs where an admin controls\nuser provisioning — see `oidc_providers::Model::trust_idp_email`."}}},"OidcProviderSummary":{"type":"object","required":["slug","name","template"],"properties":{"name":{"type":"string"},"slug":{"type":"string","description":"Stable opaque slug — use this as the path parameter when initiating\nOIDC login (`/auth/oidc/login/{slug}`). The integer database ID is\nintentionally omitted from this public endpoint to prevent provider\nenumeration."},"template":{"type":"string","description":"The template the provider was created from — e.g. `keycloak`,\n`okta`, `auth0`, `google`, `azure-ad`, or `generic`. Surfaced on\nthe public login endpoint so the unauthenticated login page can\nrender the right brand logo on the \"Sign in with X\" button.\nNever sensitive — the template name is part of the provider's\npublic identity, not configuration."}}},"OidcProviderUserResponse":{"type":"object","description":"A user that has logged in via a given OIDC provider. Used by the\nadmin \"Users for provider\" panel — the `oidc_subject` is the\nIdP-side identifier we matched on, useful when diagnosing why a\nuser can or can't log in.","required":["id","name","email","email_verified","mfa_enabled","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-15T14:30:00Z"},"email":{"type":"string"},"email_verified":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"mfa_enabled":{"type":"boolean"},"name":{"type":"string"},"oidc_subject":{"type":["string","null"]},"updated_at":{"type":"string","format":"date-time","example":"2024-01-15T14:30:00Z"}}},"OidcProvidersListResponse":{"type":"object","required":["providers"],"properties":{"providers":{"type":"array","items":{"$ref":"#/components/schemas/OidcProviderSummary"}}}},"OidcRoleMappingResponse":{"type":"object","required":["id","provider_id","priority","idp_group","role"],"properties":{"id":{"type":"integer","format":"int32"},"idp_group":{"type":"string"},"priority":{"type":"integer","format":"int32"},"provider_id":{"type":"integer","format":"int32"},"role":{"type":"string"}}},"OidcTestConnectionResponse":{"type":"object","required":["success","message"],"properties":{"message":{"type":"string"},"success":{"type":"boolean"}}},"OnDemandCertAttemptResponse":{"type":"object","description":"A single on-demand HTTP-01 issuance attempt from the append-only\n`on_demand_cert_attempts` audit log. Carries the full forensic detail for one\nattempt; the current cert state lives on the enclosing row's domain fields.\n\nContains no private-key or certificate material — only audit metadata — so it\nis safe to return without masking.","required":["id","hostname","trigger","outcome","created_at"],"properties":{"acme_request_sent":{"type":["boolean","null"],"description":"Did we reach the Let's Encrypt API?"},"acme_response_status":{"type":["string","null"],"description":"HTTP status or ACME error type returned by Let's Encrypt, when known."},"challenge_served":{"type":["boolean","null"],"description":"Did the proxy serve the `/.well-known/acme-challenge/` request?"},"created_at":{"type":"integer","format":"int64","description":"When the attempt was recorded (epoch millis)."},"duration_ms":{"type":["integer","null"],"format":"int32","description":"End-to-end issuance duration in milliseconds (0/None for skipped)."},"error_category":{"type":["string","null"],"description":"Coarse error category for UI labelling: `\"rate_limited\"`, `\"dns_failure\"`,\n`\"acme_order_expired\"`, `\"challenge_mismatch\"`, `\"timeout\"`, `\"internal\"`."},"error_chain":{"type":["string","null"],"description":"Full `Display` chain of the error (all `source()` levels), when failed."},"hostname":{"type":"string","description":"SNI hostname that triggered the attempt."},"id":{"type":"integer","format":"int32"},"outcome":{"type":"string","description":"Final outcome: `\"issued\"`, `\"failed\"`, `\"skipped_duplicate\"`,\n`\"skipped_gate\"`, `\"skipped_rate_limit\"`, or `\"skipped_no_route\"`."},"trigger":{"type":"string","description":"What triggered the attempt (always `\"tls_callback\"` today)."}}},"OnDemandCertRow":{"type":"object","description":"One row of the on-demand certificates list: the most-recent attempt for a\nhostname plus the current authoritative cert state from its `domains` row.","required":["hostname","attempt"],"properties":{"attempt":{"$ref":"#/components/schemas/OnDemandCertAttemptResponse","description":"The audit record for the attempt this row represents (newest first in\nthe list)."},"backoff_until":{"type":["integer","null"],"format":"int64","description":"On-demand negative-cache deadline (epoch millis), when in backoff."},"expiration_time":{"type":["integer","null"],"format":"int64","description":"Certificate expiration (epoch millis), when an active cert exists."},"hostname":{"type":"string","description":"SNI hostname."},"status":{"type":["string","null"],"description":"Current cert lifecycle status from the `domains` row, when one exists:\n`on_demand_pending`, `on_demand_issuing`, `active`, `on_demand_failed`,\netc. `None` when no `domains` row exists yet for this hostname."}}},"OnDemandTlsSettings":{"type":"object","description":"On-demand (lazy) HTTP-01 TLS issuance settings (ADR-018).\n\nWhen `enabled`, the proxy's `certificate_callback` triggers ACME HTTP-01\nissuance for allowlisted, STABLE hostnames (per-environment aliases and the\nconsole host) that have no active cert, rather than silently failing the\nhandshake. Ephemeral per-deployment hostnames are NEVER certed (ADR §2).\n\nOff by default — operators opt in explicitly, except QuickStart (`sslip.io`)\ninstalls where `temps setup` auto-enables it and derives `zone`.","properties":{"deployment_url_mode":{"type":"string","description":"How ephemeral per-deployment hostnames behave when they have no cert\n(they are NEVER certed — see ADR §2). One of:\n - `\"http\"` (default): serve plain HTTP on :80.\n - `\"redirect_to_env\"`: 308-redirect to the stable per-environment URL,\n which IS certed.","default":"http","example":"http"},"enabled":{"type":"boolean","description":"Master switch. When `false` (default) the proxy's on-demand cert gate\nrejects every SNI and no issuance is ever triggered.","default":false,"example":false},"hourly_cap":{"type":"integer","format":"int32","description":"Global cap on total on-demand issuances per hour across all hostnames\n(ADR §4 Layer 3). The operator's self-imposed safety net, separate from\nthe Let's Encrypt rate limit.","default":10,"example":10,"minimum":1},"max_concurrent":{"type":"integer","format":"int32","description":"Maximum number of ACME issuance flows allowed to run simultaneously\n(the concurrent-issuance semaphore, ADR §4 Layer 1). Min 1.","default":3,"example":3,"minimum":1},"zone":{"type":["string","null"],"description":"Zone suffix for the allowlist gate. A hostname passes the gate only if\nit is a direct subdomain of this zone (e.g. zone `1.2.3.4.sslip.io`\nadmits `myapp.1.2.3.4.sslip.io` but not `deep.sub.1.2.3.4.sslip.io`).\n`None` (default) means \"auto-derive from `external_url`\"; if no zone can\nbe derived the gate rejects all SNI, disabling the feature.","default":null,"example":"1.2.3.4.sslip.io"}}},"OpenAiError":{"type":"object","required":["message","type"],"properties":{"code":{"type":["string","null"]},"message":{"type":"string"},"type":{"type":"string"}}},"OpenAiErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"$ref":"#/components/schemas/OpenAiError"}}},"OperatingSystemCount":{"type":"object","required":["operating_system","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"operating_system":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"OperationResultResponse":{"type":"object","required":["operation","success","message","executed_at"],"properties":{"data":{},"executed_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"message":{"type":"string"},"operation":{"type":"string"},"success":{"type":"boolean"}}},"OperationResultsResponse":{"type":"object","required":["deployment_id","operations"],"properties":{"deployment_id":{"type":"string"},"operations":{"type":"array","items":{"$ref":"#/components/schemas/OperationResultResponse"}}}},"OtelDashboardResponse":{"type":"object","required":["id","project_id","name","layout","created_at","updated_at"],"properties":{"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"id":{"type":"integer","format":"int32"},"layout":{"$ref":"#/components/schemas/DashboardLayout"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"}}},"OtelDashboardsResponse":{"type":"object","required":["data","total"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OtelDashboardResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"OtelMetricAlertRuleResponse":{"type":"object","required":["id","project_id","name","metric_name","aggregation","detection_kind","detection_config","window_secs","for_duration_secs","severity","enabled","last_state","label_filters","group_by","dynamic_alerts","max_series","grouped_notification_threshold","last_dropped_series_count","series_states","created_at","updated_at"],"properties":{"aggregation":{"type":"string"},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"detection_config":{"$ref":"#/components/schemas/DetectionConfig","description":"The typed detector definition (discriminated union keyed by `kind`)."},"detection_kind":{"type":"string","description":"Coarse detector discriminator: `static|anomaly|forecast|outlier|auto_watch`."},"dynamic_alerts":{"type":"boolean","description":"Whether per-series (\"dynamic\") alerting is enabled for this rule."},"enabled":{"type":"boolean"},"firing_series":{"type":"array","items":{"$ref":"#/components/schemas/FiringSeriesEntry"},"description":"Currently-firing series for a dynamic rule, snapshotted from the evaluator's\nin-memory firing map at read time. Empty for static/aggregate rules or when\nnothing is firing."},"for_duration_secs":{"type":"integer","format":"int32"},"group_by":{"type":"array","items":{"type":"string"},"description":"Label keys the rule breaks the metric down by. Empty = one aggregate stream."},"grouped_notification_threshold":{"type":"integer","format":"int32","description":"Notification-grouping threshold: when more than this many series fire in the\nsame tick, only the first gets chart/AI enrichment (1–1000)."},"id":{"type":"integer","format":"int32"},"label_filters":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"AND-combined label equality filters applied when evaluating this rule.\nEmpty = no filtering (matches all series)."},"last_dropped_series_count":{"type":"integer","format":"int32","description":"Number of series dropped by the cardinality cap on the latest dynamic tick\n(0 when nothing was dropped or for static/aggregate rules). Lets a UI warn\n\"N series were dropped this tick\" without reading server logs."},"last_evaluated_at":{"type":["string","null"],"example":"2025-10-12T12:15:47.609192Z"},"last_state":{"type":"string","description":"One of `ok|firing|unknown`."},"last_value":{"type":["number","null"],"format":"double"},"max_series":{"type":"integer","format":"int32","description":"Cardinality cap for dynamic alerting (1–100)."},"metric_name":{"type":"string"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"series_states":{"type":"object","description":"Full per-series state snapshot persisted after the latest dynamic-rule tick,\nkeyed by the human-readable series label (`endpoint=/checkout`). Empty for\nstatic/aggregate rules. Unlike `firing_series` (a live in-memory snapshot),\nthis is decoded from the persisted `series_states` jsonb column, so an\nexternal consumer that only reads the rule row still sees per-series detail.","additionalProperties":{"$ref":"#/components/schemas/SeriesStateEntry"},"propertyNames":{"type":"string"}},"severity":{"type":"string"},"updated_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"window_secs":{"type":"integer","format":"int32"}}},"OtelMetricAlertsResponse":{"type":"object","required":["data","total"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OtelMetricAlertRuleResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"OtelMetricLabelKeysResponse":{"type":"object","required":["keys"],"properties":{"keys":{"type":"array","items":{"type":"string"}}}},"OtelMetricLabelValuesResponse":{"type":"object","required":["values"],"properties":{"values":{"type":"array","items":{"type":"string"}}}},"OtelMetricNamesResponse":{"type":"object","required":["names"],"properties":{"names":{"type":"array","items":{"type":"string"}}}},"OtelMetricsResponse":{"type":"object","required":["data","count"],"properties":{"count":{"type":"integer","minimum":0},"data":{"type":"array","items":{"$ref":"#/components/schemas/MetricBucket"}}}},"OutlierAlgorithm":{"type":"string","description":"Outlier detection algorithm.","enum":["dbscan","scaled_dbscan","mad","scaled_mad"]},"OutlierParams":{"type":"object","description":"Outlier (cross-series population) detector parameters (stub — not evaluated).","required":["peer_group_key"],"properties":{"algorithm":{"$ref":"#/components/schemas/OutlierAlgorithm"},"peer_group_key":{"type":"string","description":"Label key defining the peer population compared across series (e.g. `host`)."},"tolerance":{"type":"number","format":"double","description":"Sensitivity; higher tolerates larger spread before flagging."}}},"OverprovisioningAssessment":{"type":"object","description":"Requests-vs-capacity-vs-usage assessment","required":["verdict","explanation"],"properties":{"cpu_request_inflation_ratio":{"type":["number","null"],"format":"double","description":"Ratio of requested CPU to measured CPU usage (e.g. 40.0 = requests\nreserve 40× what the workloads actually use). `None` without metrics."},"cpu_requested_pct":{"type":["number","null"],"format":"double","description":"Requested CPU as % of cluster capacity"},"cpu_utilization_pct":{"type":["number","null"],"format":"double","description":"Measured CPU usage as % of cluster capacity (`None` without metrics)"},"explanation":{"type":"string","description":"Human-readable explanation of the verdict, e.g. \"Cluster capacity is\n8 vCPU but measured usage is 0.3 vCPU (3.7%) — severely overprovisioned\""},"memory_request_inflation_ratio":{"type":["number","null"],"format":"double","description":"Ratio of requested memory to measured memory usage"},"memory_requested_pct":{"type":["number","null"],"format":"double","description":"Requested memory as % of cluster capacity"},"memory_utilization_pct":{"type":["number","null"],"format":"double","description":"Measured memory usage as % of cluster capacity (`None` without metrics)"},"verdict":{"$ref":"#/components/schemas/OverprovisioningVerdict","description":"Overall verdict"}}},"OverprovisioningVerdict":{"type":"string","description":"Overall overprovisioning verdict","enum":["severe","moderate","reasonable","unknown"]},"PageActivityBucket":{"type":"object","description":"Time bucket data point for page activity graph","required":["timestamp","visitors","page_views","avg_time_seconds"],"properties":{"avg_time_seconds":{"type":"number","format":"double","description":"Average time on page in seconds"},"page_views":{"type":"integer","format":"int64","description":"Number of page views in this bucket"},"timestamp":{"type":"string","description":"Timestamp for this bucket (ISO 8601)"},"visitors":{"type":"integer","format":"int64","description":"Number of unique visitors in this bucket"}}},"PageCountryStats":{"type":"object","description":"Geographic distribution of visitors for a page","required":["country","visitors","page_views","percentage"],"properties":{"country":{"type":"string","description":"Country name"},"country_code":{"type":["string","null"],"description":"ISO country code (2-letter)"},"page_views":{"type":"integer","format":"int64","description":"Number of page views from this country"},"percentage":{"type":"number","format":"double","description":"Percentage of total visitors"},"visitors":{"type":"integer","format":"int64","description":"Number of unique visitors from this country"}}},"PageFlowEntry":{"type":"object","description":"A single page with its entry/exit/bounce statistics","required":["page_path","entry_count","exit_count","bounce_count","total_views","entry_rate","exit_rate","bounce_rate"],"properties":{"avg_time_on_page":{"type":["number","null"],"format":"double","description":"Average time spent on this page in seconds"},"bounce_count":{"type":"integer","format":"int64","description":"Number of times visitors bounced on this page"},"bounce_rate":{"type":"number","format":"double","description":"Bounce rate: bounce_count / entry_count (only meaningful for entry pages)"},"entry_count":{"type":"integer","format":"int64","description":"Number of times this page was the entry page of a session"},"entry_rate":{"type":"number","format":"double","description":"Entry rate: entry_count / total_views"},"exit_count":{"type":"integer","format":"int64","description":"Number of times this page was the exit page of a session"},"exit_rate":{"type":"number","format":"double","description":"Exit rate: exit_count / total_views"},"page_path":{"type":"string","description":"The page path (e.g. \"/pricing\", \"/docs/getting-started\")"},"total_views":{"type":"integer","format":"int64","description":"Total page views for this page"}}},"PageFlowQuery":{"type":"object","description":"Query parameters for page flow analytics","required":["project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of entry/exit pages to return (default: 20)"},"min_views_for_dropoff":{"type":["integer","null"],"format":"int32","description":"Minimum views for drop-off analysis (default: 5)"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"},"transitions_limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of transitions to return (default: 50)"}}},"PageFlowResponse":{"type":"object","description":"Complete page flow analytics response","required":["top_entry_pages","top_exit_pages","drop_off_points","transitions","total_pages","total_sessions"],"properties":{"drop_off_points":{"type":"array","items":{"$ref":"#/components/schemas/DropOffPoint"},"description":"Top drop-off points (highest exit rates with meaningful traffic)"},"top_entry_pages":{"type":"array","items":{"$ref":"#/components/schemas/PageFlowEntry"},"description":"Top entry pages (where visitors land), sorted by entry_count DESC"},"top_exit_pages":{"type":"array","items":{"$ref":"#/components/schemas/PageFlowEntry"},"description":"Top exit pages (where visitors leave), sorted by exit_count DESC"},"total_pages":{"type":"integer","format":"int64","description":"Total unique pages seen in the period"},"total_sessions":{"type":"integer","format":"int64","description":"Total sessions in the period"},"transitions":{"type":"array","items":{"$ref":"#/components/schemas/PageTransition"},"description":"Page-to-page transitions (most common navigation paths)"}}},"PageHourlySessionsQuery":{"type":"object","description":"Query parameters for page hourly sessions endpoint","required":["page_path","project_id","start_time","end_time"],"properties":{"bucket_interval":{"type":["string","null"]},"end_time":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page_path":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"start_time":{"type":"string","format":"date-time"}}},"PageHourlySessionsResponse":{"type":"object","required":["page_path","hourly_data","total_sessions","hours"],"properties":{"hourly_data":{"type":"array","items":{"$ref":"#/components/schemas/HourlyPageSessions"}},"hours":{"type":"integer","format":"int32"},"page_path":{"type":"string"},"total_sessions":{"type":"integer","format":"int64"}}},"PagePathDetailQuery":{"type":"object","description":"Query parameters for page path detail analytics","required":["page_path","project_id","start_date","end_date"],"properties":{"bucket_interval":{"type":["string","null"],"description":"Bucket interval for time series: 'hour', 'day', 'week', 'month' (default: auto)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page_path":{"type":"string","description":"The specific page path to get details for (URL-encoded)"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"PagePathDetailResponse":{"type":"object","description":"Detailed analytics response for a specific page path","required":["page_path","unique_visitors","total_page_views","avg_time_on_page","bounce_rate","entry_rate","exit_rate","activity_over_time","countries","referrers","bucket_interval"],"properties":{"activity_over_time":{"type":"array","items":{"$ref":"#/components/schemas/PageActivityBucket"},"description":"Time series data for activity graph"},"avg_time_on_page":{"type":"number","format":"double","description":"Average time on page in seconds"},"bounce_rate":{"type":"number","format":"double","description":"Bounce rate percentage (0-100)"},"bucket_interval":{"type":"string","description":"Bucket interval used for time series ('hour', 'day', etc.)"},"countries":{"type":"array","items":{"$ref":"#/components/schemas/PageCountryStats"},"description":"Geographic distribution of visitors"},"entry_rate":{"type":"number","format":"double","description":"Entry rate - percentage of sessions that started on this page"},"exit_rate":{"type":"number","format":"double","description":"Exit rate - percentage of sessions that ended on this page"},"page_path":{"type":"string","description":"The page path being analyzed"},"referrers":{"type":"array","items":{"$ref":"#/components/schemas/PageReferrerStats"},"description":"Top referrers to this page"},"total_page_views":{"type":"integer","format":"int64","description":"Total page views in the date range"},"unique_visitors":{"type":"integer","format":"int64","description":"Total unique visitors to this page in the date range"}}},"PagePathInfo":{"type":"object","required":["page_path","session_count","page_view_count","first_seen","last_seen"],"properties":{"avg_time_seconds":{"type":["number","null"],"format":"double"},"first_seen":{"type":"string"},"last_seen":{"type":"string"},"page_path":{"type":"string"},"page_view_count":{"type":"integer","format":"int64"},"session_count":{"type":"integer","format":"int64"}}},"PagePathSparkline":{"type":"object","required":["page_path","points"],"properties":{"page_path":{"type":"string"},"points":{"type":"array","items":{"$ref":"#/components/schemas/PagePathSparklinePoint"}}}},"PagePathSparklinePoint":{"type":"object","required":["timestamp","session_count"],"properties":{"session_count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"}}},"PagePathVisitorsQuery":{"type":"object","description":"Query parameters for page path visitors","required":["page_path","project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page":{"type":["integer","null"],"format":"int64","description":"Page number (1-based, default: 1)","minimum":0},"page_path":{"type":"string","description":"The specific page path to get visitors for"},"per_page":{"type":["integer","null"],"format":"int64","description":"Items per page (default: 50, max: 100)","minimum":0},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"PagePathVisitorsResponse":{"type":"object","description":"Response for page path visitors endpoint","required":["page_path","total_count","page","per_page","sessions"],"properties":{"page":{"type":"integer","format":"int64","description":"Current page number","minimum":0},"page_path":{"type":"string","description":"The page path"},"per_page":{"type":"integer","format":"int64","description":"Items per page","minimum":0},"sessions":{"type":"array","items":{"$ref":"#/components/schemas/PageVisitorSession"},"description":"Individual visitor sessions"},"total_count":{"type":"integer","format":"int64","description":"Total number of visitor sessions matching the query"}}},"PagePathsQuery":{"type":"object","required":["project_id"],"properties":{"end_date":{"type":["string","null"],"format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":["string","null"],"format":"date-time"}}},"PagePathsResponse":{"type":"object","required":["page_paths","total_count"],"properties":{"page_paths":{"type":"array","items":{"$ref":"#/components/schemas/PagePathInfo"}},"total_count":{"type":"integer","minimum":0}}},"PagePathsSparklineQuery":{"type":"object","description":"Query parameters for batch page paths sparkline endpoint","required":["project_id","start_time","end_time","page_paths"],"properties":{"end_time":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page_paths":{"type":"string","description":"Comma-separated list of page paths"},"project_id":{"type":"integer","format":"int32"},"start_time":{"type":"string","format":"date-time"}}},"PagePathsSparklineResponse":{"type":"object","required":["sparklines"],"properties":{"sparklines":{"type":"array","items":{"$ref":"#/components/schemas/PagePathSparkline"}}}},"PageReferrerStats":{"type":"object","description":"Referrer source for the page","required":["referrer","visits","percentage"],"properties":{"percentage":{"type":"number","format":"double","description":"Percentage of total visits"},"referrer":{"type":"string","description":"Referrer URL or domain"},"visits":{"type":"integer","format":"int64","description":"Number of visits from this referrer"}}},"PageSessionComparison":{"type":"object","required":["page_path","date","session_count","event_count","avg_duration_seconds"],"properties":{"avg_duration_seconds":{"type":"number","format":"double"},"date":{"type":"string"},"event_count":{"type":"integer","format":"int64"},"page_path":{"type":"string"},"session_count":{"type":"integer","format":"int64"}}},"PageSessionStats":{"type":"object","required":["page_path","total_sessions","avg_time_seconds","min_time_seconds","max_time_seconds","total_page_views","avg_page_views_per_session"],"properties":{"avg_page_views_per_session":{"type":"number","format":"double"},"avg_time_seconds":{"type":"number","format":"double"},"max_time_seconds":{"type":"number","format":"double"},"min_time_seconds":{"type":"number","format":"double"},"page_path":{"type":"string"},"total_page_views":{"type":"integer","format":"int64"},"total_sessions":{"type":"integer","format":"int64"}}},"PageSessionStatsQuery":{"type":"object","required":["page_path","project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page_path":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"PageTransition":{"type":"object","description":"A page-to-page transition with count","required":["from_page","to_page","transition_count","percentage"],"properties":{"from_page":{"type":"string","description":"The source page path"},"percentage":{"type":"number","format":"double","description":"Percentage of transitions from the source page that go to this destination"},"to_page":{"type":"string","description":"The destination page path"},"transition_count":{"type":"integer","format":"int64","description":"Number of times this transition occurred"}}},"PageVisit":{"type":"object","required":["path","visits"],"properties":{"path":{"type":"string"},"visits":{"type":"integer","format":"int64"}}},"PageVisitorSession":{"type":"object","description":"Individual visitor session that viewed a specific page","required":["visitor_id","visitor_uuid","viewed_at","is_entry","is_exit","is_bounce"],"properties":{"browser":{"type":["string","null"],"description":"Browser name"},"city":{"type":["string","null"],"description":"Visitor's city"},"country":{"type":["string","null"],"description":"Visitor's country"},"country_code":{"type":["string","null"],"description":"Visitor's country code"},"device_type":{"type":["string","null"],"description":"Device type (Desktop, Mobile, Tablet)"},"is_bounce":{"type":"boolean","description":"Whether this was a bounce"},"is_entry":{"type":"boolean","description":"Whether this was the entry page for the session"},"is_exit":{"type":"boolean","description":"Whether this was the exit page for the session"},"operating_system":{"type":["string","null"],"description":"Operating system"},"referrer":{"type":["string","null"],"description":"Referrer URL"},"session_id":{"type":["string","null"],"description":"Session ID"},"session_page_number":{"type":["integer","null"],"format":"int32","description":"Page number in session flow"},"time_on_page":{"type":["integer","null"],"format":"int32","description":"Time spent on this page in seconds"},"viewed_at":{"type":"string","format":"date-time","description":"When the page was viewed"},"visitor_id":{"type":"integer","format":"int32","description":"Visitor numeric ID"},"visitor_uuid":{"type":"string","description":"Visitor UUID"}}},"PagesComparisonResponse":{"type":"object","required":["comparisons","page_paths"],"properties":{"comparisons":{"type":"array","items":{"$ref":"#/components/schemas/PageSessionComparison"}},"page_paths":{"type":"array","items":{"type":"string"}}}},"PaginatedEmailsResponse":{"type":"object","required":["data","total","page","page_size"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/EmailResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"PaginatedEntitiesResponse":{"type":"object","required":["entities","count","limit","has_more"],"properties":{"count":{"type":"integer","description":"Number of entities returned","minimum":0},"entities":{"type":"array","items":{"$ref":"#/components/schemas/EntityResponse"},"description":"List of entities"},"has_more":{"type":"boolean","description":"Whether there are more entities available"},"limit":{"type":"integer","description":"Limit used for this request","minimum":0},"next_token":{"type":["string","null"],"description":"Continuation token for next page (S3, etc.)"},"total":{"type":["integer","null"],"description":"Total number of entities (if available)","minimum":0}}},"PaginatedErrorEventsResponse":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ErrorEventResponse"}},"pagination":{"$ref":"#/components/schemas/PaginationMeta"}}},"PaginatedErrorGroupsResponse":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ErrorGroupResponse"}},"pagination":{"$ref":"#/components/schemas/PaginationMeta"}}},"PaginatedEventsResponse":{"type":"object","required":["events","total","page","page_size"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/TrackingEventResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"PaginatedExternalImagesResponse":{"type":"object","required":["data","total","page","page_size"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ExternalImageResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"PaginatedProjectList":{"type":"object","required":["projects","total","page","per_page"],"properties":{"page":{"type":"integer","format":"int64"},"per_page":{"type":"integer","format":"int64"},"projects":{"type":"array","items":{"$ref":"#/components/schemas/ProjectResponse"}},"total":{"type":"integer","format":"int64"}}},"PaginatedStaticBundlesResponse":{"type":"object","required":["data","total","page","page_size"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/StaticBundleResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"Pagination":{"type":"object","description":"SDK pagination cursor. We use opaque page numbers internally but\nexpose `count`/`next`/`prev` the way `@vercel/sandbox` expects.","required":["count"],"properties":{"count":{"type":"integer","format":"int64","minimum":0},"next":{"type":["integer","null"],"format":"int64","minimum":0},"prev":{"type":["integer","null"],"format":"int64","minimum":0}}},"PaginationMeta":{"type":"object","required":["page","page_size","total_count","total_pages"],"properties":{"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total_count":{"type":"integer","format":"int64","minimum":0},"total_pages":{"type":"integer","format":"int64","minimum":0}}},"PaginationParams":{"type":"object","properties":{"page":{"type":"integer","format":"int64"},"per_page":{"type":"integer","format":"int64"}}},"PasswordProtectionConfig":{"type":"object","description":"Password protection configuration\n\nWhen enabled, the proxy shows an HTML password form before allowing access.\nAfter the user enters the correct password, an HMAC-signed cookie is set\nso subsequent requests pass through without re-entering the password.","required":["enabled","passwordHash"],"properties":{"enabled":{"type":"boolean","description":"Whether password protection is enabled"},"passwordHash":{"type":"string","description":"The bcrypt-hashed password (never stored or returned in plaintext)"}}},"PatchSettingsRequest":{"type":"object","properties":{"auto_upgrade":{"type":["boolean","null"]},"host_port":{"type":["integer","null"],"format":"int32","minimum":0},"image":{"type":["string","null"]}}},"PathVisitors":{"type":"object","required":["name","visitors","percentage"],"properties":{"name":{"type":"string"},"percentage":{"type":"number","format":"double"},"visitors":{"type":"integer","format":"int64"}}},"PathVisitorsAnalyticsQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"PathVisitorsResponse":{"type":"object","required":["results"],"properties":{"results":{"type":"array","items":{"$ref":"#/components/schemas/PathVisitors"}}}},"PeerEntry":{"type":"object","description":"Wire-format peer entry. Matches `temps_network::config::Peer` but\nuses strings on the wire to keep the API stable across underlying\ntype evolution.","required":["node_id","compute_cidr","underlay_address"],"properties":{"compute_cidr":{"type":"string","description":"Per-node CIDR (e.g. `\"172.20.5.0/24\"`)."},"node_id":{"type":"string","description":"Stable v5 UUID derived from the database node id. Workers use\nthis as the kernel-layer identifier when calling\n`NetworkManager::reconcile_peers`."},"underlay_address":{"type":"string","description":"Address the local node should use to reach this peer over the\nunderlay (private VPC IP for same-DC, public IP for cross-DC)."}}},"PeerListResponse":{"type":"object","description":"Response body for `GET /internal/nodes/{node_id}/network/peers`.","required":["peers","cluster_dns_enabled"],"properties":{"alloc":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AllocEntry","description":"Caller's own allocation, or `null` if multi-host networking has\nnot been enabled for this node yet."}]},"cluster_dns_enabled":{"type":"boolean","description":"Whether the cluster-DNS resolver is enabled on this control plane\n(`AppSettings.cluster_dns.enabled`). Workers should start their\nper-node resolver and write `overlay_bridge_address` only when this\nis `true`. Always serialized (never `skip_serializing_if`) so older\nand newer version skew degrades to the safe default of `false`."},"peers":{"type":"array","items":{"$ref":"#/components/schemas/PeerEntry"},"description":"All other nodes with a `compute_cidr` set, excluding the caller."}}},"PendingActionResponse":{"type":"object","description":"A proposed AI write action awaiting human confirmation.","required":["public_id","operation_id","method","summary","status","step_index","params","created_at"],"properties":{"confirmed_at":{"type":["string","null"]},"created_at":{"type":"string"},"error":{"type":["string","null"]},"executed_at":{"type":["string","null"]},"method":{"type":"string"},"operation_id":{"type":"string"},"params":{"description":"The flat params to be replayed at execute time (shown pre-execution for review)."},"plan_public_id":{"type":["string","null"],"description":"Set when this action is one step of a multi-step plan (chained actions);\nall steps of the plan share this id. Absent for standalone single actions."},"public_id":{"type":"string"},"required_permission":{"type":["string","null"]},"result":{},"status":{"type":"string"},"step_index":{"type":"integer","format":"int32","description":"0-based order of this step within its plan (0 for standalone actions)."},"summary":{"type":"string"}}},"PerformanceMetricsQuery":{"allOf":[{"$ref":"#/components/schemas/SpeedSegmentFilters","description":"Segment filters (filter_path, filter_country, filter_region,\nfilter_city, filter_browser, filter_operating_system) — flattened so\neach remains a top-level query string param."},{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"device_type":{"type":["string","null"],"description":"Device type filter: \"desktop\" or \"mobile\""},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"include_bots":{"type":["boolean","null"],"description":"Include crawler/datacenter (bot) samples. Defaults to false — bots\nare excluded from the read view but always stored at ingest."},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}}]},"PerformanceMetricsResponse":{"type":"object","properties":{"cls":{"type":["number","null"],"format":"float"},"cls_p75":{"type":["number","null"],"format":"float"},"cls_p90":{"type":["number","null"],"format":"float"},"cls_p95":{"type":["number","null"],"format":"float"},"cls_p99":{"type":["number","null"],"format":"float"},"fcp":{"type":["number","null"],"format":"float"},"fcp_p75":{"type":["number","null"],"format":"float"},"fcp_p90":{"type":["number","null"],"format":"float"},"fcp_p95":{"type":["number","null"],"format":"float"},"fcp_p99":{"type":["number","null"],"format":"float"},"fid":{"type":["number","null"],"format":"float"},"fid_p75":{"type":["number","null"],"format":"float"},"fid_p90":{"type":["number","null"],"format":"float"},"fid_p95":{"type":["number","null"],"format":"float"},"fid_p99":{"type":["number","null"],"format":"float"},"inp":{"type":["number","null"],"format":"float"},"inp_p75":{"type":["number","null"],"format":"float"},"inp_p90":{"type":["number","null"],"format":"float"},"inp_p95":{"type":["number","null"],"format":"float"},"inp_p99":{"type":["number","null"],"format":"float"},"lcp":{"type":["number","null"],"format":"float"},"lcp_p75":{"type":["number","null"],"format":"float"},"lcp_p90":{"type":["number","null"],"format":"float"},"lcp_p95":{"type":["number","null"],"format":"float"},"lcp_p99":{"type":["number","null"],"format":"float"},"ttfb":{"type":["number","null"],"format":"float"},"ttfb_p75":{"type":["number","null"],"format":"float"},"ttfb_p90":{"type":["number","null"],"format":"float"},"ttfb_p95":{"type":["number","null"],"format":"float"},"ttfb_p99":{"type":["number","null"],"format":"float"}}},"PermissionInfo":{"type":"object","description":"Information about a single permission","required":["name","description","category"],"properties":{"category":{"type":"string","description":"Category of the permission (e.g., \"Projects\", \"Deployments\")"},"description":{"type":"string","description":"Human-readable description of the permission"},"name":{"type":"string","description":"The permission identifier (e.g., \"projects:read\")"}}},"PgUpgradeLogResponse":{"type":"object","required":["log_id","content"],"properties":{"content":{"type":"string"},"log_id":{"type":"string"}}},"PgUpgradeResponse":{"type":"object","required":["id","service_id","from_version","to_version","from_image","to_image","status","phase","log_id","attempt","created_at"],"properties":{"attempt":{"type":"integer","format":"int32"},"created_at":{"type":"string"},"error_message":{"type":["string","null"]},"finished_at":{"type":["string","null"]},"from_image":{"type":"string"},"from_version":{"type":"string"},"id":{"type":"integer","format":"int32"},"log_id":{"type":"string"},"phase":{"type":"string"},"pre_upgrade_backup_id":{"type":["integer","null"],"format":"int32"},"rollback_volume_name":{"type":["string","null"]},"service_id":{"type":"integer","format":"int32"},"started_at":{"type":["string","null"]},"status":{"type":"string"},"to_image":{"type":"string"},"to_version":{"type":"string"}}},"PipelineStats":{"type":"object","description":"Internal pipeline statistics for self-observability.","required":["metrics_received","metrics_stored","metrics_dropped","spans_received","spans_stored","spans_dropped","logs_received","logs_stored_db","logs_stored_s3","logs_dropped","ingest_errors"],"properties":{"ingest_errors":{"type":"integer","format":"int64","minimum":0},"logs_dropped":{"type":"integer","format":"int64","minimum":0},"logs_received":{"type":"integer","format":"int64","minimum":0},"logs_stored_db":{"type":"integer","format":"int64","minimum":0},"logs_stored_s3":{"type":"integer","format":"int64","minimum":0},"metrics_dropped":{"type":"integer","format":"int64","minimum":0},"metrics_received":{"type":"integer","format":"int64","minimum":0},"metrics_stored":{"type":"integer","format":"int64","minimum":0},"spans_dropped":{"type":"integer","format":"int64","minimum":0},"spans_received":{"type":"integer","format":"int64","minimum":0},"spans_stored":{"type":"integer","format":"int64","minimum":0}}},"PipelineStatsResponse":{"type":"object","required":["stats"],"properties":{"stats":{"$ref":"#/components/schemas/PipelineStats"}}},"PlanComplexity":{"type":"string","description":"Plan complexity indicator","enum":["low","medium","high"]},"PlanMetadata":{"type":"object","description":"Plan metadata","required":["generated_at","generator_version","complexity","warnings"],"properties":{"complexity":{"$ref":"#/components/schemas/PlanComplexity","description":"Estimated complexity (low, medium, high)"},"generated_at":{"type":"string","format":"date-time","description":"When the plan was generated"},"generator_version":{"type":"string","description":"Generator (importer) version"},"warnings":{"type":"array","items":{"type":"string"},"description":"Warnings detected during planning"}}},"PlanSourceBackup":{"type":"object","required":["location","location_was_resolved","format"],"properties":{"created_at":{"type":["string","null"]},"format":{"type":"string","description":"\"walg\", \"pg_dump\", \"unknown\"."},"id":{"type":["integer","null"],"format":"int32","description":"DB id, absent for orphan (S3-scan) backups."},"location":{"type":"string","description":"Resolved S3 location the orchestrator will actually use."},"location_was_resolved":{"type":"boolean","description":"True when the original row's `s3_location` was empty and we resolved\na location by probing S3. The UI shows this as a warning."},"origin_service_name":{"type":["string","null"],"description":"Service that originally produced the backup, if known."},"size_bytes":{"type":["integer","null"],"format":"int64"}}},"PlanTarget":{"type":"object","required":["id","name","container"],"properties":{"container":{"type":"string","description":"Expected Docker container name."},"id":{"type":"integer","format":"int32"},"name":{"type":"string"}}},"PlatformInfo":{"type":"object","description":"Platform compatibility information","required":["os_type","architecture","platforms"],"properties":{"architecture":{"type":"string","description":"System architecture (e.g., \"x86_64\", \"aarch64\")"},"os_type":{"type":"string","description":"Operating system type (e.g., \"linux\", \"windows\", \"darwin\")"},"platforms":{"type":"array","items":{"type":"string"},"description":"List of supported platforms in \"os/arch\" format (e.g., [\"linux/amd64\"])"}}},"PluginManifest":{"type":"object","description":"The complete plugin manifest — the handshake contract.","required":["name","version"],"properties":{"description":{"type":["string","null"],"description":"Short description of what the plugin does"},"display_name":{"type":["string","null"],"description":"Human-readable display name"},"events":{"type":"array","items":{"type":"string"},"description":"Platform event types the plugin subscribes to.\n\nWhen specified, Temps will POST matching events to the plugin's\n`/_events` endpoint. Uses dot-notation event names matching the\nwebhook event types (e.g., \"deployment.succeeded\", \"project.created\").\n\nAvailable events:\n- `deployment.created`, `deployment.succeeded`, `deployment.failed`,\n `deployment.cancelled`, `deployment.ready`\n- `project.created`, `project.deleted`\n- `domain.created`, `domain.provisioned`"},"health_path":{"type":"string","description":"Health check endpoint path (relative to plugin root)"},"name":{"type":"string","description":"Unique plugin identifier (kebab-case, e.g., \"backup-manager\")"},"nav":{"type":"array","items":{"$ref":"#/components/schemas/NavEntry"},"description":"Navigation entries for the UI sidebar"},"requires_db":{"type":"boolean","description":"Whether the plugin needs database access"},"ui":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/UiManifest","description":"UI bundle manifest (if the plugin has a UI)"}]},"version":{"type":"string","description":"SemVer version string"}}},"PortMapping":{"type":"object","description":"Port mapping","required":["container_port","protocol","is_primary"],"properties":{"container_port":{"type":"integer","format":"int32","description":"Container port","minimum":0},"host_port":{"type":["integer","null"],"format":"int32","description":"Host port (optional - can be assigned dynamically)","minimum":0},"is_primary":{"type":"boolean","description":"Whether this is the primary HTTP port"},"protocol":{"$ref":"#/components/schemas/Protocol","description":"Protocol (tcp, udp)"}}},"PostgresWalHealth":{"type":"object","required":["probed_at","pg_wal_bytes","max_wal_size_bytes","archive_mode","archive_backlog","stale_slots","oldest_wal_age_secs","warnings"],"properties":{"archive_backlog":{"type":"integer","format":"int64","description":"Number of `archive_status/*.ready` files — un-shipped WAL segments."},"archive_command":{"type":["string","null"],"description":"The literal `archive_command` setting. May be empty or `/bin/true`\nwhen archiving is effectively disabled despite `archive_mode = on`."},"archive_mode":{"$ref":"#/components/schemas/ArchiveMode"},"archiver_failed_count":{"type":["integer","null"],"format":"int64"},"archiver_last_failed_at":{"type":["string","null"],"format":"date-time"},"max_wal_size_bytes":{"type":"integer","format":"int64","description":"`max_wal_size` setting in bytes (parsed from `pg_settings`)."},"oldest_wal_age_secs":{"type":"integer","format":"int64","description":"Age of the oldest WAL file in `pg_wal/` (seconds)."},"pg_wal_bytes":{"type":"integer","format":"int64","description":"Total size of files under `pg_wal/`, from `pg_ls_waldir()`."},"probed_at":{"type":"string","format":"date-time","description":"When the snapshot was taken."},"stale_slots":{"type":"array","items":{"$ref":"#/components/schemas/StaleSlot"}},"warnings":{"type":"array","items":{"$ref":"#/components/schemas/WalWarning"},"description":"Computed warnings, ordered by severity (critical first)."}}},"PresetConfigSchema":{"oneOf":[{"$ref":"#/components/schemas/DockerfilePresetConfig","description":"Configuration for Dockerfile preset"},{"$ref":"#/components/schemas/DockerComposePresetConfig","description":"Configuration for Docker Compose"},{"$ref":"#/components/schemas/NixpacksPresetConfig","description":"Configuration for Nixpacks provider selection and inline build plan"},{"$ref":"#/components/schemas/StaticPresetConfig","description":"Configuration for static site presets (Vite, Next.js, etc.)"}],"description":"Union type for preset configurations\nUse the appropriate configuration type based on your preset"},"PresetInfo":{"type":"object","description":"Detected preset information","required":["path","preset","preset_label","project_type"],"properties":{"compose_files":{"type":["array","null"],"items":{"type":"string"},"description":"Compose file paths found in the repository (only for docker-compose preset)"},"exposed_port":{"type":["integer","null"],"format":"int32","description":"Default exposed port for this preset"},"icon_url":{"type":["string","null"],"description":"Icon URL for this preset"},"path":{"type":"string","description":"Path where preset was detected (empty for root)"},"preset":{"type":"string","description":"Preset slug (e.g., \"nextjs\", \"fastapi\")"},"preset_label":{"type":"string","description":"Human-readable preset label"},"project_type":{"type":"string","description":"Project type (e.g., \"frontend\", \"backend\", \"fullstack\")"}}},"PresetResponse":{"type":"object","required":["slug","label","icon_url","project_type","description"],"properties":{"default_port":{"type":["integer","null"],"format":"int32","description":"Default port the application listens on (None for static sites)","example":3000,"minimum":0},"description":{"type":"string","description":"Description of what this preset does"},"icon_url":{"type":"string","description":"Icon URL for the preset"},"label":{"type":"string","description":"Display name/label for the preset"},"project_type":{"type":"string","description":"Project type (server or static)"},"slug":{"type":"string","description":"Unique identifier slug for the preset"}}},"PreviewGatewaySettings":{"type":"object","description":"Workspace preview gateway settings.\n\nThe preview gateway is a single shared Docker container that lives on the\n`temps-sandbox-net` network and routes requests to workspace sandbox dev\nservers based on the `Host` header (`ws--.`).\n`temps serve` reconciles this container on startup; these settings let an\noperator override the image, host port, and auto-upgrade behavior.","properties":{"auto_upgrade":{"type":"boolean","description":"When true (default), the supervisor will pull and apply the image\npinned in the Temps binary on every startup. When false, the\ncurrently-running image is left alone — operators upgrade manually\nfrom the settings UI.","default":true,"example":true},"host_port":{"type":"integer","format":"int32","description":"Host port to publish the gateway on (always bound to 127.0.0.1).\nPingora forwards `ws-*` traffic to this port after authenticating.","default":8090,"example":8090,"minimum":0},"image":{"type":"string","description":"Docker image reference for the gateway. Pinned per Temps release.\nOperators can override this to test a custom build.","default":"ghcr.io/gotempsh/temps-preview-gateway:latest","example":"ghcr.io/gotempsh/temps-preview-gateway:latest"},"shared_secret":{"type":"string","description":"Shared secret the host-side Pingora sends on every forwarded preview\nrequest via `X-Temps-Preview-Token`; the gateway rejects requests\nwithout it. Auto-generated on first boot, persisted in DB so the\nsecret is stable across `temps serve` restarts regardless of cwd,\n`TEMPS_DATA_DIR`, or data-dir changes. MUST be masked (`***`) in any\nAPI response — never expose it over HTTP.","default":"","example":""}}},"PreviewGatewaySettingsMasked":{"type":"object","description":"Preview gateway settings with `shared_secret` elided.","required":["image","host_port","auto_upgrade","shared_secret_set"],"properties":{"auto_upgrade":{"type":"boolean"},"host_port":{"type":"integer","format":"int32","minimum":0},"image":{"type":"string"},"shared_secret_set":{"type":"boolean"}}},"PreviewGatewaySettingsResponse":{"type":"object","required":["image","host_port","auto_upgrade","default_image","default_host_port"],"properties":{"auto_upgrade":{"type":"boolean"},"default_host_port":{"type":"integer","format":"int32","description":"The compile-time default host port.","minimum":0},"default_image":{"type":"string","description":"The compile-time default image — exposed so the UI can offer a\n\"Reset to default\" link without round-tripping."},"host_port":{"type":"integer","format":"int32","minimum":0},"image":{"type":"string"}}},"PreviewShareLinkBody":{"type":"object","description":"Request body for minting a preview share link.","required":["port"],"properties":{"path":{"type":["string","null"],"description":"Path the recipient lands on. Must be same-origin (start with a single\n`/`); anything else is replaced with `/` so a share link can never be\nturned into an open redirect."},"port":{"type":"integer","format":"int32","description":"Port inside the sandbox the preview serves on.","minimum":0},"ttl_seconds":{"type":["integer","null"],"format":"int64","description":"How long the link stays usable, in seconds. Clamped to 24 hours.\nDefaults to one hour — long enough to send to a reviewer, short enough\nthat a link pasted in a ticket does not stay live indefinitely.","minimum":0}}},"PreviewShareLinkResponse":{"type":"object","required":["url","expires_at"],"properties":{"expires_at":{"type":"integer","format":"int64","description":"Unix seconds after which the link stops working.","minimum":0},"url":{"type":"string","description":"The full link. Its fragment contains the grant and must be treated as a\ncredential; URL fragments are not sent to servers or in Referer headers."}}},"PricingResponse":{"type":"object","required":["models"],"properties":{"models":{"type":"array","items":{"$ref":"#/components/schemas/ModelPricing"}}}},"ProblemDetails":{"type":"object","description":"Representation of a Problem error to return to the client.\nFollows RFC 7807 - Problem Details for HTTP APIs","required":["title","extensions"],"properties":{"detail":{"type":["string","null"],"description":"A human-readable explanation specific to this occurrence of the problem","example":"The server encountered an unexpected condition"},"extensions":{"type":"object","description":"Additional properties of the problem","additionalProperties":true},"instance":{"type":["string","null"],"description":"A URI reference that identifies the specific occurrence of the problem","example":"/account/12345/msgs/abc"},"title":{"type":"string","description":"A short, human-readable summary of the problem type","example":"Internal Server Error"},"type":{"type":["string","null"],"description":"A URI reference that identifies the problem type","example":"https://example.com/probs/out-of-memory"}},"example":{"type":"https://example.com/probs/out-of-memory","title":"Internal Server Error","detail":"The server encountered an unexpected condition","instance":"/account/12345/msgs/abc","additional_info":"Custom field with additional details"}},"ProjectAccessResponse":{"type":"object","required":["id","project_id","team_id","role","granted_by","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"},"granted_by":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"role":{"$ref":"#/components/schemas/TeamRole"},"team_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"}}},"ProjectConfiguration":{"type":"object","description":"Project-level configuration","required":["name","slug","project_type","is_web_app"],"properties":{"is_web_app":{"type":"boolean","description":"Whether this is a web application"},"name":{"type":"string","description":"Proposed project name"},"project_type":{"$ref":"#/components/schemas/ProjectType","description":"Project type"},"slug":{"type":"string","description":"Proposed slug (URL-safe identifier)"}}},"ProjectDSNResponse":{"type":"object","required":["id","project_id","name","public_key","dsn","created_at","is_active","event_count"],"properties":{"created_at":{"type":"string"},"deployment_id":{"type":["integer","null"],"format":"int32"},"dsn":{"type":"string"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_count":{"type":"integer","format":"int64"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"public_key":{"type":"string"}}},"ProjectDashboardAnalytics":{"type":"object","description":"Analytics data for a single project in the dashboard batch response","required":["project_id","unique_visitors","previous_unique_visitors","hourly_visits"],"properties":{"hourly_visits":{"type":"array","items":{"$ref":"#/components/schemas/EventTimeline"},"description":"Hourly sparkline data points"},"previous_unique_visitors":{"type":"integer","format":"int64","description":"Unique visitor count in the previous period (same duration, shifted back)"},"project_id":{"type":"integer","format":"int32"},"trend_percentage":{"type":["number","null"],"format":"double","description":"Percentage change from previous period (positive = growth, negative = decline)\nNull when previous period had zero visitors (no baseline to compare)"},"unique_visitors":{"type":"integer","format":"int64","description":"Unique visitor count in the current time range"}}},"ProjectHealthSummary":{"type":"object","description":"Health summary for a single project (last 1 hour)","required":["project_id","total_requests","total_errors","avg_response_time_ms","error_rate","status"],"properties":{"avg_response_time_ms":{"type":"number","format":"double","description":"Average response time in ms"},"error_rate":{"type":"number","format":"double","description":"Error rate as a percentage (0-100)"},"project_id":{"type":"integer","format":"int32"},"status":{"type":"string","description":"Health status: \"healthy\", \"degraded\", \"down\", \"unknown\""},"total_errors":{"type":"integer","format":"int64","description":"Total server errors (status >= 500) in the period"},"total_requests":{"type":"integer","format":"int64","description":"Total requests in the period"}}},"ProjectInfo":{"type":"object","required":["id","slug","created_at"],"properties":{"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"id":{"type":"integer","format":"int32"},"slug":{"type":"string"}}},"ProjectMonitorHealth":{"type":"object","description":"Health summary for a single project based on its production monitors","required":["project_id","status"],"properties":{"project_id":{"type":"integer","format":"int32"},"status":{"type":"string","description":"Overall status: \"operational\", \"degraded\", \"down\", or \"no_monitors\""}}},"ProjectPresetResponse":{"type":"object","required":["path","preset","presetLabel","projectType"],"properties":{"composeFiles":{"type":["array","null"],"items":{"type":"string"},"description":"Compose file paths found in the repository (only for docker-compose preset)"},"exposedPort":{"type":["integer","null"],"format":"int32","description":"Default exposed port for this preset (e.g., 3000 for Next.js, 8000 for FastAPI)"},"iconUrl":{"type":["string","null"],"description":"Icon URL for the preset"},"path":{"type":"string"},"preset":{"type":"string"},"presetLabel":{"type":"string"},"projectType":{"type":"string","description":"Project type category (e.g., \"frontend\", \"backend\", \"fullstack\")"}}},"ProjectQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"ProjectRef":{"type":"object","description":"A lightweight project descriptor included in `UnifiedTrace`.","required":["project_id","project_name","project_slug"],"properties":{"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"project_slug":{"type":"string","description":"URL slug used to link a span back into its owning project's trace view."}}},"ProjectResponse":{"type":"object","required":["id","slug","name","directory","main_branch","created_at","updated_at","deployment_config","attack_mode","ai_write_actions_enabled","error_source_context_enabled","enable_preview_environments","preview_envs_on_demand","preview_envs_idle_timeout_seconds","preview_envs_wake_timeout_seconds","source_type","cross_project_trace_sharing"],"properties":{"ai_alert_summaries_enabled":{"type":["boolean","null"],"description":"Opt-in to AI summarization of metric alert notifications (NULL/false = off)."},"ai_debug_chat_enabled":{"type":["boolean","null"],"description":"Opt-in to AI debugging chat, e.g. on deployment failures (NULL/false = off)."},"ai_write_actions_enabled":{"type":"boolean","description":"Opt-in to AI propose-then-confirm write capability (false = off)."},"attack_mode":{"type":"boolean","description":"Attack mode - when enabled, requires CAPTCHA verification for all project environments"},"created_at":{"type":"integer","format":"int64"},"cross_project_trace_sharing":{"type":"boolean","description":"ADR-027 Phase 3 opt-out: when false, this project's traces are suppressed\nfrom cross-project discovery results. Default true (consistent with the\nOSS global-observability model where any OtelRead holder can query any\nproject's telemetry)."},"deployment_config":{"$ref":"#/components/schemas/DeploymentConfig","description":"Deployment configuration (resources, autoscaling, features)"},"directory":{"type":"string"},"enable_preview_environments":{"type":"boolean","description":"Enable automatic preview environment creation for each branch"},"error_source_context_enabled":{"type":"boolean","description":"Opt-in to native error-tracking source context (false = off). When on,\nTemps stores uploaded source files and shows source code in stack traces."},"error_source_root":{"type":["string","null"],"description":"Where auto-capture reads source from (relative to the checkout). Null =\nthe deployment's Docker build context."},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"git_url":{"type":["string","null"],"description":"Git clone URL for the repository (used for public repos without a provider connection)"},"gitlab_webhook_id":{"type":["integer","null"],"format":"int32","description":"GitLab webhook ID installed on the connected repository.\n`null` when no GitLab webhook is installed (not connected to GitLab,\nor webhook was removed / never created).","example":42},"id":{"type":"integer","format":"int32"},"last_deployment":{"type":["integer","null"],"format":"int64"},"main_branch":{"type":"string"},"name":{"type":"string"},"preset":{"type":["string","null"]},"preset_config":{"description":"Preset-specific configuration (Dockerfile path, build context, etc.)"},"preview_envs_idle_timeout_seconds":{"type":"integer","format":"int32","description":"Idle timeout (seconds) for on-demand preview environments."},"preview_envs_on_demand":{"type":"boolean","description":"When true, newly-created preview environments default to on-demand mode\n(containers stop after the configured idle timeout to save resources)."},"preview_envs_wake_timeout_seconds":{"type":"integer","format":"int32","description":"Wake timeout (seconds) for on-demand preview environments."},"repo_name":{"type":["string","null"]},"repo_owner":{"type":["string","null"]},"slug":{"type":"string"},"source_type":{"$ref":"#/components/schemas/SourceType","description":"Source type for deployments (git, docker_image, or static_files)"},"updated_at":{"type":"integer","format":"int64"}}},"ProjectSecretEnvironmentInfo":{"type":"object","required":["id","name","main_url"],"properties":{"id":{"type":"integer","format":"int32"},"main_url":{"type":"string"},"name":{"type":"string"}}},"ProjectSecretResponse":{"type":"object","description":"Project secret metadata. There is deliberately no `value` field — secret\nplaintext is never returned after creation. Callers that need the value\nmust read it from the mounted file inside the container.","required":["id","project_id","key","include_in_preview","created_at","updated_at","environments"],"properties":{"created_at":{"type":"integer","format":"int64"},"environments":{"type":"array","items":{"$ref":"#/components/schemas/ProjectSecretEnvironmentInfo"}},"id":{"type":"integer","format":"int32"},"include_in_preview":{"type":"boolean"},"key":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"updated_at":{"type":"integer","format":"int64"}}},"ProjectServiceInfo":{"type":"object","required":["id","project","service"],"properties":{"id":{"type":"integer","format":"int32"},"project":{"$ref":"#/components/schemas/ProjectInfo"},"service":{"$ref":"#/components/schemas/ExternalServiceInfo"}}},"ProjectStatisticsResponse":{"type":"object","required":["total_count"],"properties":{"total_count":{"type":"integer","format":"int64"}}},"ProjectStatsBreakdown":{"type":"object","required":["project_id","unique_visitors","total_visits","total_page_views","bounce_rate","engagement_rate"],"properties":{"bounce_rate":{"type":"number","format":"double"},"engagement_rate":{"type":"number","format":"double"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":["string","null"]},"total_page_views":{"type":"integer","format":"int64"},"total_visits":{"type":"integer","format":"int64"},"unique_visitors":{"type":"integer","format":"int64"}}},"ProjectType":{"type":"string","description":"Project type enumeration","enum":["static","docker","buildpack","git"]},"ProjectUsageInfoResponse":{"type":"object","required":["id","name","slug","connection_id","connection_name"],"properties":{"connection_id":{"type":"integer","format":"int32"},"connection_name":{"type":"string"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"slug":{"type":"string"}}},"ProjectsHealthResponse":{"type":"object","description":"Batch health summary response","required":["projects"],"properties":{"projects":{"type":"object","description":"Health summaries keyed by project ID","additionalProperties":{"$ref":"#/components/schemas/ProjectHealthSummary"},"propertyNames":{"type":"string"}}}},"ProjectsMonitorHealthResponse":{"type":"object","description":"Batch response for projects health","required":["projects"],"properties":{"projects":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/ProjectMonitorHealth"},"propertyNames":{"type":"string"}}}},"PromoteDeploymentRequest":{"type":"object","required":["target_environment_id"],"properties":{"target_environment_id":{"type":"integer","format":"int32","description":"Target environment ID to promote the deployment to"}}},"PropertyBreakdownItem":{"type":"object","required":["value","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"percentage":{"type":"number","format":"double"},"value":{"type":"string"}}},"PropertyBreakdownQuery":{"type":"object","description":"Query parameters for property breakdown (group by column)","required":["start_date","end_date","group_by"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level"},"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment filter"},"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment filter"},"event_name":{"type":["string","null"],"description":"Optional event name filter (e.g., \"page_view\", \"click\")"},"filter_browser":{"type":["string","null"],"description":"Filter by browser name (for browser version drill-downs)"},"filter_channel":{"type":["string","null"],"description":"Filter by channel name (for channel -> referrer drill-downs)"},"filter_country":{"type":["string","null"],"description":"Filter by country (for region/city drill-downs). Requires geolocation join."},"filter_os":{"type":["string","null"],"description":"Filter by operating system name (for OS version drill-downs)"},"filter_referrer":{"type":["string","null"],"description":"Filter by referrer hostname (for referrer -> pages drill-downs)"},"filter_region":{"type":["string","null"],"description":"Filter by region (for city drill-downs). Requires geolocation join."},"group_by":{"$ref":"#/components/schemas/PropertyColumn","description":"Property column to group by"},"limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of results to return (default: 20, max: 100)"},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"PropertyBreakdownResponse":{"type":"object","required":["property","items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/PropertyBreakdownItem"}},"property":{"type":"string"},"total":{"type":"integer","format":"int64"}}},"PropertyColumn":{"type":"string","enum":["channel","device_type","browser","browser_version","operating_system","operating_system_version","utm_source","utm_medium","utm_campaign","utm_term","utm_content","referrer_hostname","language","event_type","event_name","page_path","pathname","country","region","city"]},"PropertyTimelineItem":{"type":"object","required":["timestamp","value","count"],"properties":{"count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"},"value":{"type":"string"}}},"PropertyTimelineQuery":{"type":"object","description":"Query parameters for property timeline (group by column over time)","required":["start_date","end_date","group_by"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level"},"bucket_size":{"type":["string","null"],"description":"Time bucket size: \"hour\", \"day\", \"week\", \"month\" (default: auto-detect)"},"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment filter"},"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment filter"},"event_name":{"type":["string","null"],"description":"Optional event name filter"},"group_by":{"$ref":"#/components/schemas/PropertyColumn","description":"Property column to group by"},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"PropertyTimelineResponse":{"type":"object","required":["property","bucket_size","items"],"properties":{"bucket_size":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/PropertyTimelineItem"}},"property":{"type":"string"}}},"Protocol":{"type":"string","description":"Network protocol","enum":["tcp","udp"]},"ProviderCatalogDto":{"type":"object","description":"One catalog entry rendered for the settings UI.","required":["id","name","install_command","auth_command","auth_flavors","models","credential_saved","supports_max_turns"],"properties":{"auth_command":{"type":"string"},"auth_flavors":{"type":"array","items":{"$ref":"#/components/schemas/AuthFlavorDto"}},"credential_saved":{"type":"boolean","description":"True when a credential is currently saved for this provider in the\nsettings JSON. Lets the UI render \"Configured\" badges without the\nfrontend having to inspect the encrypted blob."},"current_auth_type":{"type":["string","null"],"description":"Currently saved auth flavor id (when `credential_saved` is true).\n`None` when no credential is saved yet."},"default_model":{"type":["string","null"],"description":"Currently saved default model id for this provider, if one was\npicked. `None` means \"use the CLI's own default\" — the UI renders\nthat as \"Use provider default\"."},"id":{"type":"string"},"install_command":{"type":"string"},"max_turns_analysis":{"type":["integer","null"],"format":"int32","description":"Default max turns for the autofixer analysis phase. `None` = built-in\ndefault (10). Only enforced for CLIs with a turn flag (Claude Code)."},"max_turns_feedback":{"type":["integer","null"],"format":"int32","description":"Default max turns for autofixer feedback rounds. `None` = built-in\ndefault (10)."},"max_turns_fix":{"type":["integer","null"],"format":"int32","description":"Default max turns for the autofixer fix phase. `None` = built-in\ndefault (20)."},"models":{"type":"array","items":{"type":"string"},"description":"Model ids this provider accepts, in display order. The first entry is\nthe recommended default. Empty when the provider doesn't expose model\nselection (e.g. OpenCode), which the UI uses to hide the dropdown."},"name":{"type":"string"},"supports_max_turns":{"type":"boolean","description":"True when this provider's CLI supports enforcing a turn cap. False\nfor Codex/OpenCode, which run to completion — the UI labels their\nmax-turns inputs accordingly."}}},"ProviderCatalogResponse":{"type":"object","required":["default_provider","providers"],"properties":{"default_provider":{"type":"string","description":"Active provider id from `agent_sandbox.default_provider`. The settings\nUI uses this to highlight which card is the active one."},"providers":{"type":"array","items":{"$ref":"#/components/schemas/ProviderCatalogDto"}}}},"ProviderConfig":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/StripeConfig"},{"type":"object","required":["provider"],"properties":{"provider":{"type":"string","enum":["stripe"]}}}]},{"allOf":[{"$ref":"#/components/schemas/LemonSqueezyConfig"},{"type":"object","required":["provider"],"properties":{"provider":{"type":"string","enum":["lemon_squeezy"]}}}]}],"description":"Provider-specific integration settings persisted in\n`revenue_integrations.config`.\n\nThe tag is the lowercase provider name, so adding a new provider\nmeans adding a new variant and the existing rows are untouched.\nOld rows (pre-config) and rows with `NULL` config are treated as\n\"accept all events, no filtering\" via [`ProviderConfig::default_for`]."},"ProviderConfigMasked":{"type":"object","required":["auth_type","credential_saved","extra"],"properties":{"auth_type":{"type":"string"},"credential_saved":{"type":"boolean","description":"True if a credential is stored for this provider. The encrypted blob\nis never returned over HTTP."},"default_model":{"type":["string","null"]},"extra":{}}},"ProviderDeletionCheckResponse":{"type":"object","required":["can_delete","projects_in_use","message"],"properties":{"can_delete":{"type":"boolean"},"message":{"type":"string"},"projects_in_use":{"type":"array","items":{"$ref":"#/components/schemas/ProjectUsageInfoResponse"}}}},"ProviderDescriptor":{"type":"object","required":["name","display_name","recommended_events"],"properties":{"display_name":{"type":"string"},"name":{"type":"string"},"recommended_events":{"type":"array","items":{"type":"string"}}}},"ProviderKeyResponse":{"type":"object","required":["id","provider","display_name","api_key_masked","is_active","created_at","updated_at"],"properties":{"api_key_masked":{"type":"string","description":"Masked API key (only last 4 chars visible)"},"base_url":{"type":["string","null"]},"created_at":{"type":"string"},"default_model":{"type":["string","null"],"description":"Model id this provider serves (NULL → per-provider default)."},"display_name":{"type":"string"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"provider":{"type":"string"},"updated_at":{"type":"string"}}},"ProviderMetadata":{"type":"object","required":["service_type","display_name","description","icon_url","color"],"properties":{"color":{"type":"string","example":"#336791"},"description":{"type":"string","example":"Relational database management system"},"display_name":{"type":"string","example":"PostgreSQL"},"icon_url":{"type":"string","example":"https://cdn.simpleicons.org/postgresql"},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute"}}},"ProviderResponse":{"type":"object","required":["id","name","provider_type","auth_method","is_active","is_default","created_at","updated_at"],"properties":{"auth_method":{"type":"string"},"base_url":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"is_default":{"type":"boolean"},"name":{"type":"string"},"provider_type":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}},"ProviderUsage":{"type":"object","required":["provider","request_count","input_tokens","output_tokens","avg_latency_ms","error_count"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"error_count":{"type":"integer","format":"int64"},"input_tokens":{"type":"integer","format":"int64"},"output_tokens":{"type":"integer","format":"int64"},"provider":{"type":"string"},"request_count":{"type":"integer","format":"int64"}}},"ProvisionResponse":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/DomainError"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["error"]}}}]},{"allOf":[{"$ref":"#/components/schemas/DomainResponse"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["complete"]}}}]},{"allOf":[{"$ref":"#/components/schemas/DomainChallengeResponse"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["pending"]}}}]}]},"ProxyLogResponse":{"type":"object","description":"Response model for proxy logs","required":["id","timestamp","method","path","host","status_code","request_source","is_system_request","routing_status","request_id"],"properties":{"bot_name":{"type":["string","null"]},"browser":{"type":["string","null"]},"browser_version":{"type":["string","null"]},"cache_status":{"type":["string","null"]},"client_ip":{"type":["string","null"]},"container_id":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"device_type":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"error_message":{"type":["string","null"]},"host":{"type":"string"},"id":{"type":"integer","format":"int32"},"ip_geolocation_id":{"type":["integer","null"],"format":"int32"},"is_bot":{"type":["boolean","null"]},"is_system_request":{"type":"boolean"},"method":{"type":"string"},"operating_system":{"type":["string","null"]},"path":{"type":"string"},"project_id":{"type":["integer","null"],"format":"int32"},"query_string":{"type":["string","null"]},"referrer":{"type":["string","null"]},"request_id":{"type":"string"},"request_size_bytes":{"type":["integer","null"],"format":"int64"},"request_source":{"type":"string"},"response_size_bytes":{"type":["integer","null"],"format":"int64"},"response_time_ms":{"type":["integer","null"],"format":"int32"},"routing_status":{"type":"string"},"session_id":{"type":["integer","null"],"format":"int32"},"status_code":{"type":"integer","format":"int32"},"timestamp":{"type":"string"},"upstream_host":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":["integer","null"],"format":"int32"}}},"ProxyLogsPaginatedResponse":{"type":"object","description":"Paginated response for proxy logs","required":["logs","total","page","page_size","total_pages"],"properties":{"logs":{"type":"array","items":{"$ref":"#/components/schemas/ProxyLogResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0},"total_pages":{"type":"integer","format":"int64","minimum":0}}},"PublicHostnameStrategy":{"type":"string","description":"Public hostname generation mode for Temps-managed preview routes.\n\nThe mode is stored per managed domain (`dns_managed_domains.generated_hostname_mode`)\nrather than globally, so a provider such as Cloudflare can offer the flat layout\nrequired by its Universal SSL wildcard cert without changing every domain's behaviour.","enum":["standard","flat"]},"PublicPresetResponse":{"type":"object","description":"Response for preset detection","required":["branch","presets"],"properties":{"branch":{"type":"string","description":"Branch name where presets were detected"},"presets":{"type":"array","items":{"$ref":"#/components/schemas/PresetInfo"},"description":"List of detected presets"}}},"PublicRepositoryInfo":{"type":"object","description":"Public repository information","required":["owner","name","full_name","default_branch","stars","forks"],"properties":{"default_branch":{"type":"string","description":"Default branch name"},"description":{"type":["string","null"],"description":"Repository description"},"forks":{"type":"integer","format":"int32","description":"Fork count"},"full_name":{"type":"string","description":"Full repository name (owner/repo)"},"language":{"type":["string","null"],"description":"Primary programming language"},"name":{"type":"string","description":"Repository name"},"owner":{"type":"string","description":"Repository owner"},"stars":{"type":"integer","format":"int32","description":"Star count"}}},"PurgeLogsRequest":{"type":"object","required":["before"],"properties":{"before":{"type":"string","description":"Delete all logs before this timestamp (ISO 8601)"}}},"PushImageRequest":{"type":"object","description":"Request to push an external image","required":["image_ref"],"properties":{"image_ref":{"type":"string"},"metadata":{}}},"PushedExternalImageResponse":{"type":"object","description":"Response for in-memory external image operations (legacy push flow).\n\nRenamed to avoid shadowing the richer database-backed `ExternalImageResponse`\nin `handlers/remote_deployments.rs`. The two types serve different routes\n(`/images` ephemeral push vs `/external-images` registered images).","required":["id","image_ref","pushed_at"],"properties":{"digest":{"type":["string","null"]},"id":{"type":"string"},"image_ref":{"type":"string"},"pushed_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"size":{"type":["integer","null"],"format":"int64","minimum":0}}},"QueryDataRequest":{"type":"object","properties":{"filters":{"description":"JSON filters (backend-specific format)"},"limit":{"type":"integer","description":"Maximum number of rows to return","example":100,"minimum":0},"offset":{"type":"integer","description":"Number of rows to skip","example":0,"minimum":0},"sort_by":{"type":["string","null"],"description":"Sort by field name"},"sort_order":{"type":["string","null"],"description":"Sort order (asc/desc)"}}},"QueryDataResponse":{"type":"object","required":["fields","rows","total_count","returned_count","execution_time_ms"],"properties":{"execution_time_ms":{"type":"integer","format":"int64","description":"Query execution time in milliseconds","example":45,"minimum":0},"fields":{"type":"array","items":{"$ref":"#/components/schemas/FieldResponse"},"description":"Field definitions"},"returned_count":{"type":"integer","description":"Number of rows returned in this response","example":100,"minimum":0},"rows":{"type":"array","items":{},"description":"Data rows (array of JSON objects)"},"total_count":{"type":"integer","format":"int64","description":"Total number of rows matching the query (before limit/offset)","example":1234,"minimum":0}}},"QuotaResponse":{"type":"object","required":["quota"],"properties":{"quota":{"$ref":"#/components/schemas/StorageQuota"}}},"RateLimitConfig":{"type":"object","description":"Rate limiting configuration (subset of global RateLimitSettings)","properties":{"blacklistIps":{"type":"array","items":{"type":"string"},"description":"Blacklist specific IPs for this project/environment"},"maxRequestsPerHour":{"type":["integer","null"],"format":"int32","description":"Override rate limit per hour","minimum":0},"maxRequestsPerMinute":{"type":["integer","null"],"format":"int32","description":"Override rate limit per minute","minimum":0},"whitelistIps":{"type":"array","items":{"type":"string"},"description":"Whitelist specific IPs for this project/environment"}}},"RateLimitSettings":{"type":"object","properties":{"blacklist_ips":{"type":"array","items":{"type":"string"},"default":[]},"enabled":{"type":"boolean","default":false},"max_requests_per_hour":{"type":"integer","format":"int32","default":1000,"minimum":0},"max_requests_per_minute":{"type":"integer","format":"int32","default":60,"minimum":0},"whitelist_ips":{"type":"array","items":{"type":"string"},"default":[]}}},"ReachabilityStatus":{"type":"string","description":"Email reachability status","enum":["safe","risky","invalid","unknown"]},"ReadFileResponse":{"type":"object","required":["path","contents_b64","size"],"properties":{"contents_b64":{"type":"string","description":"File contents, base64-encoded. Symmetric with `WriteFileBody`."},"path":{"type":"string"},"size":{"type":"integer","format":"int64","minimum":0}}},"RecentActivityQuery":{"type":"object","description":"Query parameters for recent activity endpoint","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32","description":"Environment ID (optional)"},"limit":{"type":["integer","null"],"format":"int32","description":"Max number of events to return (default: 50, max: 100)"},"project_id":{"type":"integer","format":"int32","description":"Project ID"},"since_id":{"type":["integer","null"],"format":"int64","description":"Return events with ID greater than this (for cursor-based polling)"}}},"RecentActivityResponse":{"type":"object","description":"Response for recent activity events endpoint","required":["events","count"],"properties":{"count":{"type":"integer","description":"Total events returned","minimum":0},"events":{"type":"array","items":{"$ref":"#/components/schemas/ActivityEvent"},"description":"Recent events, newest first"}}},"RecentEventResponse":{"type":"object","required":["occurred_at","event_type"],"properties":{"amount_minor":{"type":["integer","null"],"format":"int64"},"currency":{"type":["string","null"]},"customer_ref":{"type":["string","null"]},"event_type":{"type":"string"},"mrr_minor":{"type":["integer","null"],"format":"int64"},"occurred_at":{"type":"string","format":"date-time"}}},"RecentQueryParams":{"type":"object","properties":{"conversation_id":{"type":["string","null"],"description":"Filter by conversation ID"},"cost_gt":{"type":["integer","null"],"format":"int64","description":"Cost strictly greater-than, in microcents"},"cost_gte":{"type":["integer","null"],"format":"int64","description":"Cost greater-than-or-equal, in microcents"},"cost_lt":{"type":["integer","null"],"format":"int64","description":"Cost strictly less-than, in microcents"},"cost_lte":{"type":["integer","null"],"format":"int64","description":"Cost less-than-or-equal, in microcents"},"limit":{"type":["integer","null"],"format":"int64","description":"Page size (defaults to 20, max 50)","minimum":0},"model":{"type":["string","null"],"description":"Filter by model name"},"offset":{"type":["integer","null"],"format":"int64","description":"Number of results to skip for pagination (defaults to 0)","minimum":0},"provider":{"type":["string","null"],"description":"Filter by provider name"},"status":{"type":["integer","null"],"format":"int32","description":"Filter by HTTP status code (exact match)"},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"tokens_gt":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) strictly greater-than"},"tokens_gte":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) greater-than-or-equal"},"tokens_lt":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) strictly less-than"},"tokens_lte":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) less-than-or-equal"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"RecordExposureRequest":{"type":"object","description":"Keys a running app actually evaluated since its last report.","required":["keys"],"properties":{"keys":{"type":"array","items":{"type":"string"},"description":"Flag keys evaluated since the last report. Unknown keys are ignored.","example":["checkout.v2","api.rate_limit"]}}},"RecordExposureResponse":{"type":"object","required":["recorded"],"properties":{"recorded":{"type":"integer","format":"int64","description":"How many keys were accepted for processing.\n\nDeliberately not the number of rows updated: echoing that back would\nlet a caller post a single candidate key and read the result as \"this\nflag exists\", turning the endpoint into an existence oracle.","minimum":0}}},"RecordListResponse":{"type":"object","description":"Record list response","required":["records"],"properties":{"records":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecord"}}}},"RecoveryTarget":{"oneOf":[{"type":"object","description":"Recover to a specific timestamp.","required":["time","kind"],"properties":{"kind":{"type":"string","enum":["time"]},"time":{"type":"string","format":"date-time"}}},{"type":"object","description":"Recover to a specific transaction id (Postgres).","required":["xid","kind"],"properties":{"kind":{"type":"string","enum":["xid"]},"xid":{"type":"string"}}},{"type":"object","description":"Recover to a specific log sequence number (Postgres).","required":["lsn","kind"],"properties":{"kind":{"type":"string","enum":["lsn"]},"lsn":{"type":"string"}}},{"type":"object","description":"Recover to a named restore point created via `pg_create_restore_point` (Postgres).","required":["name","kind"],"properties":{"kind":{"type":"string","enum":["name"]},"name":{"type":"string"}}}],"description":"Engine-specific recovery target for PITR.\n\nPostgres honors all variants; Redis/Mongo/S3 will likely reject non-Time\nvariants or define their own semantics when they grow PITR support."},"ReferrerCount":{"type":"object","required":["referrer","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"percentage":{"type":"number","format":"double"},"referrer":{"type":"string"}}},"ReferrersAnalyticsQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"RegenerateDSNRequest":{"type":"object","properties":{"base_url":{"type":["string","null"]}}},"RegisterImageRequest":{"type":"object","required":["image_ref"],"properties":{"digest":{"type":["string","null"],"description":"Image digest (sha256:...)","example":"sha256:abc123def456"},"image_ref":{"type":"string","description":"Docker image reference (e.g., \"ghcr.io/org/app:v1.0\")","example":"ghcr.io/myorg/myapp:v1.0"},"metadata":{"description":"Additional metadata"},"tag":{"type":["string","null"],"description":"Image tag","example":"v1.0"}}},"RegisterNodeApiRequest":{"type":"object","required":["name","token","address","private_address"],"properties":{"address":{"type":"string","description":"Node's reachable address (e.g., \"10.100.0.2\" or \"192.168.1.50\")"},"architecture":{"type":["string","null"],"description":"Container platform of this node's Docker daemon (`linux/amd64`,\n`linux/arm64`). Optional: agents older than multi-arch support omit it\nand the value is learned from the first heartbeat instead."},"csr_pem":{"type":["string","null"],"description":"Node-generated certificate signing request (PEM) for multi-node mTLS\n(ADR-020 WS-2.1). When present, the control plane signs it with the\ncluster CA and returns the leaf + CA cert. Optional — token-only nodes\n(legacy / edge) still register without one."},"edge_public_key":{"type":["string","null"],"description":"X25519 public key for ECIES certificate encryption (base64-encoded, edge nodes only)"},"join_token":{"type":["string","null"],"description":"Join token to authorize this registration (must match the token generated in Settings)"},"labels":{"description":"Labels for scheduling (e.g., {\"region\": \"us-east\", \"gpu\": \"true\"})"},"name":{"type":"string","description":"Unique name for this node"},"prior_token":{"type":["string","null"],"description":"The node's *current* token, supplied to prove possession when\nre-registering (changing the identity of) a node that already exists.\nOptional; only needed to rebind a still-live node. (ADR-020 WS-1.2.)"},"private_address":{"type":"string","description":"Private/WireGuard address for inter-node communication"},"public_endpoint":{"type":["string","null"],"description":"Public endpoint for WireGuard (e.g., \"203.0.113.1:51820\")"},"role":{"type":["string","null"],"description":"Node role (default: \"worker\")"},"token":{"type":"string","description":"Registration token (plaintext, will be hashed before storage)"},"wg_public_key":{"type":["string","null"],"description":"WireGuard public key"}}},"RegisterNodeResponse":{"type":"object","required":["id","name","status","message"],"properties":{"ca_cert_pem":{"type":["string","null"],"description":"The cluster CA certificate (PEM) the node pins as its trust root.\nPresent only when a `csr_pem` was supplied. (ADR-020 WS-2.1.)"},"cert_pem":{"type":["string","null"],"description":"The signed per-node leaf certificate (PEM) the agent serves as its TLS\nserver cert. Present only when a `csr_pem` was supplied. (ADR-020 WS-2.1.)"},"id":{"type":"integer","format":"int32"},"message":{"type":"string"},"name":{"type":"string"},"status":{"type":"string"}}},"RegisterRequest":{"type":"object","required":["email","password","name"],"properties":{"email":{"type":"string"},"name":{"type":"string"},"password":{"type":"string"}}},"ReinstallWebhookResponse":{"type":"object","description":"Response for `POST /projects/{project_id}/gitlab/reinstall-webhook`","required":["hook_id","message"],"properties":{"hook_id":{"type":"integer","format":"int32","description":"The new GitLab hook ID that was installed."},"message":{"type":"string","description":"Human-readable status message."}}},"ReleaseListResponse":{"type":"object","required":["releases"],"properties":{"releases":{"type":"array","items":{"type":"string"}}}},"ReloadResponse":{"type":"object","description":"Response from the reload endpoint.","required":["loaded","plugins","message"],"properties":{"loaded":{"type":"integer","description":"Number of plugins successfully loaded after reload","minimum":0},"message":{"type":"string","description":"Human-readable status message"},"plugins":{"type":"array","items":{"type":"string"},"description":"Names of loaded plugins"}}},"RemoteDeploymentResponse":{"type":"object","required":["id","project_id","environment_id","slug","state","source_type","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"environment_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"slug":{"type":"string"},"source_type":{"type":"string"},"state":{"type":"string"}}},"RemoveNodeResponse":{"type":"object","required":["id","message"],"properties":{"id":{"type":"integer","format":"int32"},"message":{"type":"string"}}},"RenameConversationRequest":{"type":"object","required":["title"],"properties":{"title":{"type":"string","description":"New human-facing title. Trimmed; must be non-empty after trimming."}}},"RepositoryListQuery":{"type":"object","properties":{"direction":{"type":["string","null"]},"language":{"type":["string","null"]},"owner":{"type":["string","null"]},"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0},"private":{"type":["boolean","null"]},"search":{"type":["string","null"]},"sort":{"type":["string","null"]}}},"RepositoryListResponse":{"type":"object","required":["repositories","total_count"],"properties":{"repositories":{"type":"array","items":{"$ref":"#/components/schemas/RepositoryResponse"}},"total_count":{"type":"integer","minimum":0}}},"RepositoryPresetResponse":{"type":"object","required":["repository_id","owner","name","presets","calculated_at"],"properties":{"calculated_at":{"type":"string","format":"date-time"},"name":{"type":"string"},"owner":{"type":"string"},"presets":{"type":"array","items":{"$ref":"#/components/schemas/ProjectPresetResponse"}},"repository_id":{"type":"integer","format":"int32"}}},"RepositoryResponse":{"type":"object","required":["id","owner","name","full_name","private","default_branch","created_at","updated_at","pushed_at","git_provider_connection_id"],"properties":{"clone_url":{"type":["string","null"],"description":"HTTPS clone URL (e.g., https://github.com/owner/repo.git)"},"created_at":{"type":"string","format":"date-time"},"default_branch":{"type":"string"},"description":{"type":["string","null"]},"full_name":{"type":"string"},"git_provider_connection_id":{"type":"integer","format":"int32","description":"ID of the git provider connection this repository was synced from."},"id":{"type":"integer","format":"int32"},"language":{"type":["string","null"]},"name":{"type":"string"},"owner":{"type":"string"},"preset":{"type":["array","null"],"items":{"$ref":"#/components/schemas/ProjectPresetResponse"}},"private":{"type":"boolean"},"pushed_at":{"type":"string","format":"date-time"},"ssh_url":{"type":["string","null"],"description":"SSH clone URL (e.g., git@github.com:owner/repo.git)"},"updated_at":{"type":"string","format":"date-time"}}},"RepositorySyncStartedResponse":{"type":"object","description":"Returned by `POST /git-connections/{id}/sync` to acknowledge that a\nsync has been kicked off in the background. Clients should poll the\nconnection's `syncing` and `synced_repository_count` fields to track\nprogress rather than waiting on this response.","required":["connection_id","syncing","started_at"],"properties":{"connection_id":{"type":"integer","format":"int32"},"started_at":{"type":"string","format":"date-time"},"syncing":{"type":"boolean"}}},"RequestRow":{"type":"object","required":["id","ts","method","host","path","status","request_headers","response_headers","headers_truncated"],"properties":{"client_ip":{"type":["string","null"]},"country":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_group_id":{"type":["integer","null"],"format":"int32"},"headers_truncated":{"type":"boolean"},"host":{"type":"string"},"id":{"type":"string","description":"The request's unique `request_id` (assigned by the proxy). Used as the\nrow identity instead of the storage PK because the ClickHouse backend\nhas no serial id (rows come back with `id = 0`) while `request_id` is\nunique and present on both backends."},"latency_ms":{"type":["integer","null"],"format":"int32"},"method":{"type":"string"},"path":{"type":"string"},"query_string":{"type":["string","null"]},"referrer":{"type":["string","null"]},"request_headers":{},"response_headers":{},"status":{"type":"integer","format":"int32"},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"},"user_agent":{"type":["string","null"]}}},"ResetPasswordRequest":{"type":"object","required":["token","new_password"],"properties":{"new_password":{"type":"string"},"token":{"type":"string"}}},"ResetPgStatStatementsRequest":{"type":"object","description":"Explicit confirmation required for the destructive statistics reset.\n\nRequiring JSON makes the endpoint non-simple for browsers, preventing a\ndeployed same-site application from triggering it with a plain HTML form.","required":["confirm"],"properties":{"confirm":{"type":"boolean","description":"Must be `true` to acknowledge the global, irreversible reset."}}},"ResetPgStatStatementsResponse":{"type":"object","description":"Response for the pg_stat_statements reset endpoint.","required":["message"],"properties":{"message":{"type":"string","description":"Human-readable message confirming the destructive action."}}},"ResizeSandboxBody":{"type":"object","required":["disk_size_mb"],"properties":{"disk_size_mb":{"type":"integer","format":"int64","description":"New root disk size in MB. Grow-only; must exceed the current size.","minimum":0}},"additionalProperties":false},"ResolvedEnvVarResponse":{"type":"object","description":"One entry in the computed env-var view that merges manual and integration\nsources and tags each result with its origin. `value_preview` is always\nmasked — plaintext must be fetched per-key via the existing reveal endpoint,\nwhich is audit-logged.","required":["key","value_preview","source","environments","include_in_preview"],"properties":{"environments":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentInfo"},"description":"Environments this var applies to. For integration-sourced vars this\nreflects every environment of the project (integrations are global)."},"include_in_preview":{"type":"boolean","description":"Whether the var would be auto-applied to preview environments.\nIntegration vars always surface in preview; manual vars follow the flag."},"key":{"type":"string"},"source":{"$ref":"#/components/schemas/ResolvedEnvVarSource"},"value_preview":{"type":"string","description":"Masked or truncated preview. Never the raw value."}}},"ResolvedEnvVarSource":{"oneOf":[{"type":"object","description":"Manually-defined env var. If `overrides_service` is set, this key would\notherwise have been supplied by an integration — the UI should show the\nintegration icon plus an \"overridden\" indicator.","required":["var_id","type"],"properties":{"overrides_service":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/EnvVarIntegrationInfo"}]},"type":{"type":"string","enum":["manual"]},"var_id":{"type":"integer","format":"int32"}}},{"type":"object","description":"Supplied by a linked external service (Postgres, Redis, S3, etc.).","required":["service","type"],"properties":{"service":{"$ref":"#/components/schemas/EnvVarIntegrationInfo"},"type":{"type":"string","enum":["integration"]}}}],"description":"Where a resolved env var comes from. Integration-sourced vars may be\n\"shadowed\" by a manual entry with the same key, in which case the response\ncarries `Manual` with `overrides_service` populated so the UI can still show\nthe integration icon."},"ResourceCounts":{"type":"object","description":"Quick count of resources involved in the migration","required":["projects","environments","deployments","environment_variables","services","domains"],"properties":{"deployments":{"type":"integer","minimum":0},"domains":{"type":"integer","minimum":0},"environment_variables":{"type":"integer","minimum":0},"environments":{"type":"integer","minimum":0},"projects":{"type":"integer","minimum":0},"services":{"type":"integer","minimum":0}}},"ResourceFootprint":{"type":"object","description":"A CPU + memory footprint (requests or measured usage)","required":["cpu_millis","memory_mb"],"properties":{"cpu_millis":{"type":"integer","format":"int64","description":"CPU in millicores"},"memory_mb":{"type":"integer","format":"int64","description":"Memory in MB"}}},"ResourceInfo":{"type":"object","description":"Resource attributes extracted from OTel resource descriptors.","required":["service_name","attributes"],"properties":{"attributes":{"type":"object"},"deployment_environment":{"type":["string","null"]},"service_name":{"type":"string"},"service_version":{"type":["string","null"]}}},"ResourceLimitApplyResult":{"type":"object","description":"Per-container outcome of a live `docker update` call. Surfaced from the\nPATCH /resources endpoint so the UI can tell the operator whether the\nnew caps are already in effect or whether they only apply on next\nrecreate (e.g., container was missing).","required":["role","container_name","outcome"],"properties":{"container_name":{"type":"string"},"error":{"type":["string","null"],"description":"Populated only when `outcome == \"failed\"`."},"outcome":{"type":"string","description":"One of:\n- \"applied\" — Docker accepted the update; caps are live now.\n- \"missing\" — container does not exist; caps stored, will apply on next start.\n- \"stopped\" — container exists but isn't running; Docker still\n accepts the update (the new caps apply on next start).\n- \"failed\" — `docker update` returned an error (see `error`)."},"role":{"type":"string","description":"`service_members.role` for cluster members; \"standalone\" otherwise."}}},"ResourceLimits":{"type":"object","description":"Resource limits and requests","properties":{"cpu_limit":{"type":["integer","null"],"format":"int32","description":"CPU limit (millicores)"},"cpu_request":{"type":["integer","null"],"format":"int32","description":"CPU request (millicores)"},"memory_limit":{"type":["integer","null"],"format":"int32","description":"Memory limit (MB)"},"memory_request":{"type":["integer","null"],"format":"int32","description":"Memory request (MB)"}}},"ResourceLimitsResponse":{"type":"object","description":"Container resource limits","properties":{"cpu_limit":{"type":["integer","null"],"format":"int32"},"cpu_request":{"type":["integer","null"],"format":"int32"},"memory_limit":{"type":["integer","null"],"format":"int32"},"memory_request":{"type":["integer","null"],"format":"int32"}}},"ResourceLimitsUpdateResponse":{"type":"object","description":"Response from PATCH /external-services/{id}/resources.","required":["limits","applied"],"properties":{"applied":{"type":"array","items":{"$ref":"#/components/schemas/ResourceLimitApplyResult"},"description":"Per-container result of trying to apply the limits live."},"limits":{"$ref":"#/components/schemas/ServiceResourceLimits","description":"The limits that were persisted to the encrypted config."}}},"ResourcesBody":{"type":"object","description":"Nested `resources: { memory, vcpus }` as sent by `@vercel/sandbox`.\n`memory` is in MB, `vcpus` is fractional CPU count.","properties":{"memory":{"type":["integer","null"],"format":"int64","minimum":0},"vcpus":{"type":["number","null"],"format":"double"}}},"RestoreCapabilities":{"type":"object","description":"Capabilities a service exposes for the generic restore framework.\n\nEach engine overrides `ExternalService::restore_capabilities` to declare\nwhat it supports. The handler layer uses this to validate requests and\nthe UI uses it to conditionally show options (e.g., PITR picker).","required":["restore_in_place","restore_to_new_service","pitr"],"properties":{"earliest_pitr_time":{"type":["string","null"],"format":"date-time","description":"Earliest recoverable timestamp, if `pitr` is true. Derived from\nengine-specific archive metadata (e.g., `pg_stat_archiver`)."},"latest_pitr_time":{"type":["string","null"],"format":"date-time","description":"Latest recoverable timestamp, if `pitr` is true."},"pitr":{"type":"boolean","description":"Point-in-time recovery using engine-specific continuous archives\n(WAL for Postgres, AOF for Redis, oplog for MongoDB, object versions for S3)."},"restore_in_place":{"type":"boolean","description":"Restore a backup onto the same running service (destructive)."},"restore_to_new_service":{"type":"boolean","description":"Restore a backup into a freshly provisioned service."}}},"RestoreCapabilitiesResponse":{"allOf":[{"$ref":"#/components/schemas/RestoreCapabilities","description":"Trait-declared capabilities."},{"type":"object","required":["suggested_new_service_name"],"properties":{"suggested_new_service_name":{"type":"string","description":"Suggested name for the new service when creating a clone. Safe to\npre-fill into the UI dialog; the user can edit before submitting."}}}]},"RestorePlan":{"type":"object","description":"Preview of a restore operation. Answers \"what will happen if I click\nstart?\" with engine-level specificity so the user can confirm before\ncommitting to a destructive action.","required":["engine","target_service","source_backup","strategy","steps","warnings","errors","destructive","mode"],"properties":{"destructive":{"type":"boolean","description":"Whether any step overwrites existing data on the target service."},"engine":{"type":"string","description":"Target engine (\"postgres\", etc.)."},"errors":{"type":"array","items":{"type":"string"},"description":"Blocking problems. The UI disables the Start button when non-empty."},"mode":{"type":"string","description":"Echo of the requested mode for the UI."},"source_backup":{"$ref":"#/components/schemas/PlanSourceBackup","description":"Backup we'll read from."},"steps":{"type":"array","items":{"type":"string"},"description":"Ordered list of human-readable actions the orchestrator will take."},"strategy":{"type":"string","description":"How the restore will be performed: \"walg_restore\", \"pg_dump_restore\",\nor \"unsupported\"."},"target_service":{"$ref":"#/components/schemas/PlanTarget","description":"Service we'll operate on (or provision a sibling of)."},"warnings":{"type":"array","items":{"type":"string"},"description":"Non-blocking caveats the user should see (cross-service, empty\nlocation that will be auto-resolved, missing engine metadata, ...)."}}},"RestoreRequestMode":{"oneOf":[{"type":"object","description":"Restore the backup onto the existing service (destructive).","required":["mode"],"properties":{"mode":{"type":"string","enum":["in_place"]}}},{"type":"object","description":"Provision a new service and restore into it.","required":["name","mode"],"properties":{"mode":{"type":"string","enum":["new_service"]},"name":{"type":"string","description":"Name for the new service. Orchestrator auto-suggests\n`{source}-restore-{yyyymmdd-hhmm}` if caller omits, but we require\nan explicit value at the API boundary."},"parameter_overrides":{"description":"Optional parameter overrides (port, docker_image, database)."}}},{"type":"object","description":"Point-in-time recovery. Only valid on WAL-G backups (Postgres).","required":["to_new_service","target","mode"],"properties":{"mode":{"type":"string","enum":["pitr"]},"new_service_name":{"type":["string","null"],"description":"Required when `to_new_service` is true."},"target":{"$ref":"#/components/schemas/RecoveryTarget","description":"Recovery target kind + value."},"to_new_service":{"type":"boolean","description":"Whether PITR restores in place or creates a new service."}}}],"description":"What the caller wants to do. Mirrors `externalsvc::RestoreMode` but\nflattened for JSON over the wire."},"RestoreRunView":{"type":"object","required":["id","source_backup_id","source_service_id","mode","status","phase","created_at"],"properties":{"created_at":{"type":"string"},"error_message":{"type":["string","null"]},"finished_at":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"mode":{"type":"string"},"phase":{"type":"string"},"recovery_target":{},"source_backup_id":{"type":"integer","format":"int32"},"source_service_id":{"type":"integer","format":"int32"},"started_at":{"type":["string","null"]},"status":{"type":"string"},"target_service_id":{"type":["integer","null"],"format":"int32"},"target_service_name":{"type":["string","null"]}}},"RetentionCleanupFailure":{"type":"object","required":["backup_id","reason","partial","deleted_objects"],"properties":{"backup_id":{"type":"string"},"deleted_objects":{"type":"integer","format":"int64","minimum":0},"partial":{"type":"boolean"},"reason":{"type":"string"}}},"RetentionCleanupReport":{"type":"object","required":["dry_run","expired","deleted","failed","failures","deleted_backup_ids","deleted_backup_ids_truncated","partially_deleted_backup_ids","partially_deleted_backup_ids_truncated","candidate_backup_ids","candidate_backup_ids_truncated"],"properties":{"candidate_backup_ids":{"type":"array","items":{"type":"string"},"description":"Capped sample of backups selected by the retention policy."},"candidate_backup_ids_truncated":{"type":"boolean"},"deleted":{"type":"integer","format":"int64","minimum":0},"deleted_backup_ids":{"type":"array","items":{"type":"string"},"description":"Capped sample of deleted backup UUIDs for audit attribution."},"deleted_backup_ids_truncated":{"type":"boolean"},"dry_run":{"type":"boolean","description":"True when this report is a non-destructive preview."},"expired":{"type":"integer","format":"int64","minimum":0},"failed":{"type":"integer","format":"int64","minimum":0},"failures":{"type":"array","items":{"$ref":"#/components/schemas/RetentionCleanupFailure"},"description":"Capped diagnostic sample; `failed` remains the authoritative total."},"partially_deleted_backup_ids":{"type":"array","items":{"type":"string"}},"partially_deleted_backup_ids_truncated":{"type":"boolean"},"schedule_id":{"type":["integer","null"],"format":"int32","description":"Schedule scope, or `None` when every schedule was considered."}}},"RetryClusterRequest":{"type":"object","description":"Request body for retrying a failed cluster initialization.","properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/ClusterMemberRequest"},"description":"Cluster member specifications (same format as create).\nIf omitted, the original member configuration is reconstructed from\nthe preserved service_members records."}}},"RevenueRow":{"type":"object","required":["id","ts","provider","event_type"],"properties":{"amount_minor":{"type":["integer","null"],"format":"int64"},"currency":{"type":["string","null"]},"customer_ref":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_type":{"type":"string"},"id":{"type":"integer","format":"int64"},"provider":{"type":"string"},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"}}},"RiskLevel":{"type":"string","description":"Risk level for a migration step","enum":["none","low","medium","high","critical"]},"RoleInfo":{"type":"object","description":"Information about a role","required":["name","description","permissions"],"properties":{"description":{"type":"string","description":"Human-readable description of the role"},"name":{"type":"string","description":"The role identifier (e.g., \"admin\")"},"permissions":{"type":"array","items":{"type":"string"},"description":"Permissions included in this role"}}},"RootfsCacheEntry":{"type":"object","description":"A cached rootfs image (Firecracker backend). Digest-keyed build artifact\nshared by all VMs created from the same image.","required":["digest","bytes","referenced_by"],"properties":{"bytes":{"type":"integer","format":"int64","description":"Actual on-disk size in bytes (sparse-aware).","minimum":0},"digest":{"type":"string","description":"Image digest this rootfs was built from (the cache key)."},"referenced_by":{"type":"array","items":{"type":"string"},"description":"IDs of live sandboxes whose per-VM disk was cloned from this entry.\nEmpty means the entry is reclaimable — no sandbox needs it."}}},"RootfsGcReport":{"type":"object","description":"Outcome of a rootfs garbage-collection pass.","required":["removed_digests","freed_bytes"],"properties":{"freed_bytes":{"type":"integer","format":"int64","minimum":0},"removed_digests":{"type":"array","items":{"type":"string"},"description":"Digests of cache entries removed because no sandbox referenced them."}}},"RootfsReport":{"type":"object","description":"Snapshot of a backend's rootfs storage for the management API. Backends\nwithout a rootfs concept (Docker, local) return an empty report.","required":["cache_bytes","cache","vm_bytes","vms"],"properties":{"cache":{"type":"array","items":{"$ref":"#/components/schemas/RootfsCacheEntry"}},"cache_bytes":{"type":"integer","format":"int64","minimum":0},"vm_bytes":{"type":"integer","format":"int64","minimum":0},"vms":{"type":"array","items":{"$ref":"#/components/schemas/RootfsVmEntry"}}}},"RootfsVmEntry":{"type":"object","description":"A per-sandbox rootfs disk (Firecracker backend). One per non-destroyed\nsandbox — the authoritative storage, independent of the cache.","required":["sandbox_name","bytes","running"],"properties":{"bytes":{"type":"integer","format":"int64","minimum":0},"running":{"type":"boolean"},"sandbox_name":{"type":"string"}}},"RouteRefreshResponse":{"type":"object","required":["route_count","message"],"properties":{"message":{"type":"string","description":"Human-readable message"},"route_count":{"type":"integer","description":"Number of routes loaded","minimum":0}}},"RouteResponse":{"type":"object","required":["id","domain","host","port","enabled","route_type","created_at","updated_at"],"properties":{"created_at":{"type":"integer","format":"int64"},"domain":{"type":"string"},"enabled":{"type":"boolean"},"host":{"type":"string"},"id":{"type":"integer","format":"int32"},"port":{"type":"integer","format":"int32"},"route_type":{"type":"string","description":"Route type: \"http\" or \"tls\""},"updated_at":{"type":"integer","format":"int64"}}},"RouteRole":{"type":"object","required":["id","name","created_at","updated_at"],"properties":{"created_at":{"type":"integer","format":"int64","example":"1683900000000"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"updated_at":{"type":"integer","format":"int64","example":"1683900000000"}}},"RouteUser":{"type":"object","required":["id","name","username","email","image","mfa_enabled","email_verified","created_at","updated_at"],"properties":{"created_at":{"type":"integer","format":"int64","example":"1683900000000"},"deleted_at":{"type":["integer","null"],"format":"int64"},"email":{"type":"string"},"email_verified":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"image":{"type":"string"},"mfa_enabled":{"type":"boolean"},"name":{"type":"string"},"updated_at":{"type":"integer","format":"int64","example":"1683900000000"},"username":{"type":"string"}}},"RouteUserWithRoles":{"type":"object","required":["user","roles"],"properties":{"roles":{"type":"array","items":{"$ref":"#/components/schemas/RouteRole"}},"user":{"$ref":"#/components/schemas/RouteUser"}}},"RunBackupRequest":{"type":"object","required":["backup_type"],"properties":{"backup_type":{"type":"string","description":"Type of backup to perform","example":"full"}}},"RunExternalServiceBackupRequest":{"type":"object","properties":{"backup_type":{"type":["string","null"],"description":"Type of backup to perform (e.g., \"full\", \"incremental\")","example":"full"},"s3_source_id":{"type":["integer","null"],"format":"int32","description":"ID of the S3 source to store the backup. If omitted, the current default S3 source is used.","example":1}}},"S3ConnectionTestResponse":{"type":"object","description":"Response body for an S3 connection test.","required":["ok","message"],"properties":{"message":{"type":"string","description":"Human-readable message (success confirmation or error detail)."},"ok":{"type":"boolean","description":"Whether the connection and credentials worked."}}},"S3CredentialsResponse":{"type":"object","description":"S3 credentials distributed to agents for backup/restore operations.","required":["access_key_id","secret_key","region","bucket_name","force_path_style"],"properties":{"access_key_id":{"type":"string"},"bucket_name":{"type":"string"},"endpoint":{"type":["string","null"]},"force_path_style":{"type":"boolean"},"region":{"type":"string"},"secret_key":{"type":"string"}}},"S3SourceResponse":{"type":"object","description":"Response type for S3 source","required":["id","name","bucket_name","bucket_path","access_key_id","secret_key","region","is_default","created_at","updated_at"],"properties":{"access_key_id":{"type":"string","example":"AKIAXXXXXXXXXXXXXXXX"},"bucket_name":{"type":"string"},"bucket_path":{"type":"string"},"created_at":{"type":"integer","format":"int64"},"endpoint":{"type":["string","null"],"example":"http://minio.example.com:9000"},"force_path_style":{"type":["boolean","null"]},"id":{"type":"integer","format":"int32"},"is_default":{"type":"boolean"},"name":{"type":"string"},"region":{"type":"string"},"secret_key":{"type":"string","writeOnly":true},"updated_at":{"type":"integer","format":"int64"}}},"SandboxDomainResponse":{"type":"object","required":["url"],"properties":{"url":{"type":"string"}}},"SandboxEvent":{"type":"object","description":"One entry in a sandbox's operations timeline.","required":["event_type","at"],"properties":{"at":{"type":"integer","format":"int64","description":"Unix epoch milliseconds."},"detail":{"description":"Optional structured context (shape depends on `event_type`)."},"event_type":{"type":"string","description":"Machine-readable operation (`created`, `stopped`, `resumed`,\n`restarted`, `timeout_extended`, `resized`, `preview_password_set`,\n`preview_password_cleared`, `preview_share_link_created`, `source_seeded`,\n`destroyed`)."}}},"SandboxEventsResponse":{"type":"object","required":["events"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/SandboxEvent"}}}},"SandboxInner":{"type":"object","description":"Inner `sandbox` object in `@vercel/sandbox` responses. Strict shape —\nthe SDK's zod validator rejects missing required fields.","required":["id","memory","vcpus","region","runtime","timeout","status","requestedAt","createdAt","updatedAt","cwd","name","preview_url_template"],"properties":{"agent_run_id":{"type":["integer","null"],"format":"int32","description":"Agent run this sandbox executes (autofixer / workflow agent).\n`None` for sandboxes created via this API."},"backend":{"type":["string","null"],"description":"Isolation backend: \"docker\" | \"firecracker\". `None` on legacy rows\ncreated before the backend was recorded."},"createdAt":{"type":"integer","format":"int64"},"cwd":{"type":"string"},"disk_size_mb":{"type":["integer","null"],"format":"int64","description":"Configured root disk size in MB (Firecracker). `None` when unknown or\nthe default.","minimum":0},"id":{"type":"string"},"image":{"type":["string","null"]},"memory":{"type":"integer","format":"int64","minimum":0},"name":{"type":"string"},"preview_password_hint":{"type":["string","null"]},"preview_url_template":{"type":"string"},"region":{"type":"string"},"requestedAt":{"type":"integer","format":"int64","description":"Creation time as Unix epoch milliseconds."},"runtime":{"type":"string"},"status":{"type":"string"},"timeout":{"type":"integer","format":"int64","description":"Idle timeout in milliseconds (SDK convention).","minimum":0},"updatedAt":{"type":"integer","format":"int64"},"vcpus":{"type":"number","format":"double"}}},"SandboxResponse":{"type":"object","description":"`@vercel/sandbox` wraps every single-sandbox response as\n`{ sandbox: {...}, routes: [...] }`. The SDK reads both.","required":["sandbox","routes"],"properties":{"routes":{"type":"array","items":{"$ref":"#/components/schemas/SandboxRoute"}},"sandbox":{"$ref":"#/components/schemas/SandboxInner"}}},"SandboxRoute":{"type":"object","description":"A single preview route, one per declared port. We don't know ports\nupfront, so we surface an empty array by default — SDK clients use\ntheir own port when calling `sandbox.domain(port)`.","required":["url","subdomain","port"],"properties":{"port":{"type":"integer","format":"int32","minimum":0},"subdomain":{"type":"string"},"url":{"type":"string"}}},"SandboxStatusResponse":{"type":"object","required":["docker_available","image_ready","image_name","firecracker_available"],"properties":{"docker_available":{"type":"boolean"},"error":{"type":["string","null"]},"firecracker_available":{"type":"boolean"},"image_name":{"type":"string"},"image_ready":{"type":"boolean"}}},"SaveAgentTokenRequest":{"type":"object","required":["token"],"properties":{"token":{"type":"string","description":"The OAuth token from `claude setup-token` or an API key.\nWill be encrypted before storage."}}},"SaveAgentTokenResponse":{"type":"object","required":["saved"],"properties":{"saved":{"type":"boolean"}}},"SaveCredentialRequest":{"type":"object","required":["auth_type","credential"],"properties":{"auth_type":{"type":"string","description":"Auth flavor id (must match one of the provider's catalog entries)."},"credential":{"type":"string","description":"Plaintext credential body (API key, OAuth token, or full config file\ncontents). Encrypted with `EncryptionService` before being persisted\ninside the `agent_sandbox.providers` JSON map."}}},"SaveCredentialResponse":{"type":"object","required":["saved","provider_id","auth_type"],"properties":{"auth_type":{"type":"string"},"provider_id":{"type":"string"},"saved":{"type":"boolean"}}},"ScalewayCredentialsRequest":{"type":"object","required":["api_key","project_id"],"properties":{"api_key":{"type":"string","example":"scw-secret-key-12345"},"project_id":{"type":"string","example":"12345678-1234-1234-1234-123456789012"}}},"ScanResponse":{"type":"object","required":["id","project_id","scanner_type","status","total_count","critical_count","high_count","medium_count","low_count","unknown_count","started_at","created_at","updated_at"],"properties":{"branch":{"type":["string","null"]},"commit_hash":{"type":["string","null"]},"completed_at":{"type":["string","null"],"example":"2025-12-08T12:15:47.609192Z"},"created_at":{"type":"string","example":"2025-12-08T12:15:47.609192Z"},"critical_count":{"type":"integer","format":"int32"},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_message":{"type":["string","null"]},"high_count":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"low_count":{"type":"integer","format":"int32"},"medium_count":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"scanner_type":{"type":"string"},"scanner_version":{"type":["string","null"]},"started_at":{"type":"string","example":"2025-12-08T12:15:47.609192Z"},"status":{"type":"string"},"total_count":{"type":"integer","format":"int32"},"unknown_count":{"type":"integer","format":"int32"},"updated_at":{"type":"string","example":"2025-12-08T12:15:47.609192Z"}}},"ScheduleRunEntry":{"type":"object","description":"A single run-history entry for the schedule detail page (deliverable 1).\n\nCombines one `backups` row with the most-recent `backup_jobs` row for that\nbackup via a lateral JOIN. Fields from `backup_jobs` are `None` for legacy\nbackup rows that pre-date ADR-014.","required":["backup_id","backup_uuid","state","started_at","s3_location"],"properties":{"attempts":{"type":["integer","null"],"format":"int32","description":"Number of claim-and-run attempts so far. `None` for legacy rows."},"backup_id":{"type":"integer","format":"int32","description":"DB id of the `backups` row."},"backup_uuid":{"type":"string","description":"UUID string (`backups.backup_id`)."},"current_step":{"type":["string","null"],"description":"Last completed step reported by the engine (e.g. `\"upload\"`).\n`None` when no step has been persisted yet."},"error_message":{"type":["string","null"],"description":"Engine-reported error message when `state = \"failed\"`."},"finished_at":{"type":["string","null"],"description":"When the backup finished, if known."},"job_id":{"type":["integer","null"],"format":"int64","description":"Most recent `backup_jobs.id` for this backup. `None` for legacy rows."},"s3_location":{"type":"string","description":"S3 object key or URL where the backup data lives."},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Final size in bytes once completed. `None` while running."},"started_at":{"type":"string","description":"When the backup was started (ISO 8601 / RFC 3339)."},"state":{"type":"string","description":"Current state: `\"pending\"`, `\"running\"`, `\"completed\"`, `\"failed\"`."}}},"ScheduleRunJobEntry":{"type":"object","description":"A single job entry inside an expanded schedule run, returned by\n[`BackupService::list_schedule_run_jobs`].","required":["backup_id","backup_uuid","engine","service_name","state","started_at","s3_source_id"],"properties":{"backup_id":{"type":"integer","format":"int32","description":"`backups.id` for this job."},"backup_uuid":{"type":"string","description":"`backups.backup_id` UUID string."},"engine":{"type":"string","description":"Engine key (e.g. `\"control_plane\"`, `\"redis\"`)."},"error_message":{"type":["string","null"],"description":"Engine-reported error message when `state = \"failed\"`."},"finished_at":{"type":["string","null"],"description":"When this child backup finished, if known."},"s3_source_id":{"type":"integer","format":"int32","description":"FK to `s3_sources.id` — needed for the backup detail link."},"service_id":{"type":["integer","null"],"format":"int32","description":"`external_services.id` — `NULL` for the control-plane job."},"service_name":{"type":"string","description":"Name of the external service, or `\"control plane\"` for the\ncontrol-plane job."},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size in bytes once completed; `None` while running."},"started_at":{"type":"string","description":"When this child backup started (ISO 8601 / RFC 3339)."},"state":{"type":"string","description":"Current state of this child backup."}}},"ScheduleRunListResponse":{"type":"object","description":"Paginated run-history response for a backup schedule (deliverable 1).","required":["runs","total","page","page_size"],"properties":{"page":{"type":"integer","format":"int64","description":"Current page (1-based)."},"page_size":{"type":"integer","format":"int64","description":"Number of items per page (clamped to 1–100)."},"runs":{"type":"array","items":{"$ref":"#/components/schemas/ScheduleRunEntry"},"description":"Run entries, newest first."},"total":{"type":"integer","format":"int64","description":"Total number of runs across all pages."}}},"ScheduleRunResponse":{"type":"object","description":"HTTP response body for `POST /api/backups/schedules/{id}/run` (fan-out).","required":["schedule_run_id","jobs"],"properties":{"jobs":{"type":"array","items":{"$ref":"#/components/schemas/EnqueuedJob"},"description":"All jobs that were enqueued in this fan-out."},"schedule_run_id":{"type":"integer","format":"int64","description":"The `schedule_runs.id` of the newly created run."}}},"ScheduleRunSummary":{"type":"object","description":"Summary of one scheduler tick (or one \"Run now\" click), returned by\n[`BackupService::list_schedule_runs`].\n\nThe `aggregate_state` is computed at read time from child backup counts:\n- `\"running\"` — at least one child is `\"pending\"` or `\"running\"`.\n- `\"failed\"` — at least one child is `\"failed\"` and none are running.\n- `\"completed\"` — all children are `\"completed\"`.","required":["run_id","schedule_id","triggered_by","started_at","aggregate_state","total_jobs","completed_jobs","failed_jobs","running_jobs","pending_jobs"],"properties":{"aggregate_state":{"type":"string","description":"Aggregate state computed from child counts (see struct docs)."},"completed_jobs":{"type":"integer","format":"int64","description":"Number of children in `state = \"completed\"`."},"failed_jobs":{"type":"integer","format":"int64","description":"Number of children in `state = \"failed\"`."},"finished_at":{"type":["string","null"],"description":"When all children reached a terminal state. `None` while any child is\nstill `\"pending\"` or `\"running\"`."},"pending_jobs":{"type":"integer","format":"int64","description":"Number of children in `state = \"pending\"`."},"run_id":{"type":"integer","format":"int64","description":"`schedule_runs.id` for this tick."},"running_jobs":{"type":"integer","format":"int64","description":"Number of children in `state = \"running\"`."},"schedule_id":{"type":"integer","format":"int32","description":"FK to `backup_schedules.id`."},"started_at":{"type":"string","description":"When the fan-out started (ISO 8601 / RFC 3339)."},"total_jobs":{"type":"integer","format":"int64","description":"Total number of child backup jobs in this run."},"triggered_by":{"type":"string","description":"How the run was triggered: `\"cron\"` or `\"manual\"`."}}},"ScheduleRunSummaryList":{"type":"object","description":"Paginated list of schedule run summaries returned by the new\n[`BackupService::list_schedule_runs`].","required":["runs","total","page","page_size"],"properties":{"page":{"type":"integer","format":"int64","description":"Current page (1-based)."},"page_size":{"type":"integer","format":"int64","description":"Number of items per page."},"runs":{"type":"array","items":{"$ref":"#/components/schemas/ScheduleRunSummary"},"description":"Run summaries, newest first. Includes synthetic single-job rows for\nlegacy `backups` rows that have `schedule_id` set but no\n`schedule_run_id` (pre-fan-out history)."},"total":{"type":"integer","format":"int64","description":"Total number of run entries across all pages."}}},"ScreenshotSettings":{"type":"object","properties":{"enabled":{"type":"boolean","default":false},"provider":{"type":"string","default":"local"},"url":{"type":"string","default":""}}},"SearchLogsRequest":{"type":"object","required":["project_id"],"properties":{"container_ids":{"type":"array","items":{"type":"string"},"description":"Filter to specific containers (Docker container IDs). Empty = all\ncontainers. Drives \"filter by container / show all\" in a project's\nhistory, which spans multiple deployments and containers."},"context_lines":{"type":["integer","null"],"format":"int32","description":"grep -C: number of raw context lines to include before and after each\nmatch (0 = none, default). Clamped to 50 server-side. The surrounding\nlines ignore the level/text filters — they are the actual adjacent log\nlines, merged across overlapping matches.","minimum":0},"cursor":{"type":["string","null"],"description":"Pagination cursor"},"deploy_id":{"type":["integer","null"],"format":"int32","description":"Filter by deployment ID (deployments.id)"},"end_time":{"type":["string","null"],"description":"End of time range (ISO 8601). Defaults to now."},"envs":{"type":"array","items":{"type":"string"},"description":"Filter by environments"},"external_service_id":{"type":["integer","null"],"format":"int32","description":"When set, search an imported/managed external service's logs instead\nof a project's. `project_id` is ignored in this mode."},"levels":{"type":"array","items":{"type":"string"},"description":"Filter by log levels"},"node_ids":{"type":"array","items":{"type":"integer","format":"int32"},"description":"Filter to specific worker nodes (node_id). Empty = all nodes, including\ncontrol-plane-local logs."},"page_size":{"type":["integer","null"],"format":"int32","description":"Page size (default: 100, max: 500)","minimum":0},"project_id":{"type":"integer","format":"int32","description":"Project ID (integer, as used by the rest of the platform)"},"services":{"type":"array","items":{"type":"string"},"description":"Filter by services"},"start_time":{"type":["string","null"],"description":"Start of time range (ISO 8601). Defaults to 1 hour ago."},"text":{"type":["string","null"],"description":"Full text search query"}}},"SearchLogsResponse":{"type":"object","required":["lines","search_mode","total_scanned"],"properties":{"available_sources":{"type":"array","items":{"$ref":"#/components/schemas/LogSource"},"description":"Distinct containers/nodes/services available in the queried scope, for\nthe filter dropdowns. Populated on the first page (no cursor)."},"lines":{"type":"array","items":{"$ref":"#/components/schemas/LogSearchLine"}},"next_cursor":{"type":["string","null"]},"search_mode":{"$ref":"#/components/schemas/SearchMode"},"total_scanned":{"type":"integer","format":"int64","minimum":0}}},"SearchMode":{"type":"string","description":"Search execution mode","enum":["index","archive"]},"Seasonality":{"type":"string","description":"Seasonality model for an anomaly baseline.","enum":["none","hourly","daily","weekly"]},"SecretResponse":{"type":"object","required":["id","name","secret_type","value","created_at","updated_at"],"properties":{"created_at":{"type":"string"},"description":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"mount_path":{"type":["string","null"]},"name":{"type":"string"},"secret_type":{"type":"string"},"updated_at":{"type":"string"},"value":{"type":"string","description":"Always masked in responses"}}},"SecurityConfig":{"type":"object","description":"Security configuration for projects and environments\n\nThis configuration can be set at three levels:\n1. Global (in settings table) - applies to all projects\n2. Project level - overrides global settings for specific project\n3. Environment level - overrides project settings for specific environment\n\nThe inheritance chain: Environment > Project > Global","properties":{"attackMode":{"type":["string","null"],"description":"Attack mode configuration (future: \"off\", \"challenge\", \"block\")\nPlaceholder for DDoS protection, bot detection, etc."},"challengeConfig":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ChallengeConfig","description":"Challenge configuration (future: CAPTCHA, JS challenge, etc.)"}]},"enabled":{"type":["boolean","null"],"description":"Enable/disable security features at this level\nIf None, inherits from parent level"},"geoRestrictions":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/GeoRestrictionsConfig","description":"Geographic restrictions (future: country blocking, etc.)"}]},"headers":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SecurityHeadersConfig","description":"Security headers configuration"}]},"passwordProtection":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PasswordProtectionConfig","description":"Password protection: shows an HTML password form before allowing access"}]},"rateLimiting":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/RateLimitConfig","description":"Rate limiting configuration"}]}}},"SecurityHeadersConfig":{"type":"object","description":"Security headers configuration (subset of global SecurityHeadersSettings)","properties":{"contentSecurityPolicy":{"type":["string","null"],"description":"Custom CSP (only used if preset is \"custom\")"},"preset":{"type":["string","null"],"description":"Use a preset: \"strict\", \"moderate\", \"permissive\", \"disabled\", \"custom\""},"referrerPolicy":{"type":["string","null"],"description":"Referrer-Policy override"},"strictTransportSecurity":{"type":["string","null"],"description":"HSTS override"},"xFrameOptions":{"type":["string","null"],"description":"X-Frame-Options override"}}},"SecurityHeadersSettings":{"type":"object","properties":{"content_security_policy":{"type":["string","null"],"default":"default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'self'"},"enabled":{"type":"boolean","default":false},"permissions_policy":{"type":["string","null"],"default":"geolocation=(), microphone=(), camera=()"},"preset":{"type":"string","default":"moderate"},"referrer_policy":{"type":"string","default":"strict-origin-when-cross-origin"},"strict_transport_security":{"type":"string","default":"max-age=31536000; includeSubDomains"},"x_content_type_options":{"type":"string","default":"nosniff"},"x_frame_options":{"type":"string","default":"SAMEORIGIN"},"x_xss_protection":{"type":"string","default":"1; mode=block"}}},"SendEmailRequestBody":{"type":"object","required":["from","to","subject"],"properties":{"bcc":{"type":["array","null"],"items":{"type":"string"},"description":"BCC recipients"},"cc":{"type":["array","null"],"items":{"type":"string"},"description":"CC recipients"},"from":{"type":"string","description":"Sender email address (domain will be auto-extracted for lookup)","example":"hello@updates.example.com"},"from_name":{"type":["string","null"],"description":"Sender display name","example":"My App"},"headers":{"type":["object","null"],"description":"Custom headers","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"html":{"type":["string","null"],"description":"HTML body content","example":"

Hello World

"},"reply_to":{"type":["string","null"],"description":"Reply-to address"},"subject":{"type":"string","description":"Email subject","example":"Welcome to our platform!"},"tags":{"type":["array","null"],"items":{"type":"string"},"description":"Tags for categorization","example":["welcome","onboarding"]},"text":{"type":["string","null"],"description":"Plain text body content","example":"Hello World"},"to":{"type":"array","items":{"type":"string"},"description":"Recipient email addresses","example":["user@example.com"]},"track_clicks":{"type":["boolean","null"],"description":"Enable click tracking (link rewriting). Defaults to false."},"track_opens":{"type":["boolean","null"],"description":"Enable open tracking (tracking pixel injection). Defaults to false."}}},"SendEmailResponseBody":{"type":"object","required":["id","status"],"properties":{"id":{"type":"string","description":"Email ID","example":"550e8400-e29b-41d4-a716-446655440000"},"provider_message_id":{"type":["string","null"],"description":"Provider message ID"},"status":{"type":"string","description":"Email status","example":"sent"}}},"SendMessageRequest":{"type":"object","required":["content"],"properties":{"content":{"type":"string"},"page_context":{"type":["string","null"],"description":"Optional, client-supplied description of the page/entity the user is\ncurrently viewing (e.g. a trace in a project). Injected into the model's\nview of this turn only — never stored or shown in history. Capped server\nside; oversized values are ignored rather than rejected."}}},"SensitiveConfigValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"SensitiveMcpConfigValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"SensitiveValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"SentryChunkUploadResponse":{"type":"object","required":["url","chunkSize","chunksPerRequest","maxFileSize","maxRequestSize","concurrency","hashAlgorithm","compression","accept"],"properties":{"accept":{"type":"array","items":{"type":"string"}},"chunkSize":{"type":"integer","format":"int64","minimum":0},"chunksPerRequest":{"type":"integer","format":"int32","minimum":0},"compression":{"type":"array","items":{"type":"string"}},"concurrency":{"type":"integer","format":"int32","minimum":0},"hashAlgorithm":{"type":"string"},"maxFileSize":{"type":"integer","format":"int64","minimum":0},"maxRequestSize":{"type":"integer","format":"int64","minimum":0},"url":{"type":"string"}}},"SentryCreateReleaseRequest":{"type":"object","required":["version"],"properties":{"projects":{"type":"array","items":{"type":"string"},"description":"Project slugs this release belongs to"},"version":{"type":"string","description":"Release version identifier"}}},"SentryEventRequest":{"type":"object","properties":{"event_id":{"type":["string","null"]},"message":{"type":["string","null"]},"platform":{"type":["string","null"]},"timestamp":{"type":["string","null"]}}},"SentryEventResponse":{"type":"object","required":["id"],"properties":{"id":{"type":"string"}}},"SentryReleaseFileResponse":{"type":"object","required":["id","name","headers","size","sha1","dateCreated"],"properties":{"dateCreated":{"type":"string"},"dist":{"type":["string","null"]},"headers":{},"id":{"type":"string"},"name":{"type":"string"},"sha1":{"type":"string"},"size":{"type":"integer","format":"int64"}}},"SentryReleaseProjectRef":{"type":"object","required":["name","slug"],"properties":{"name":{"type":"string"},"slug":{"type":"string"}}},"SentryReleaseResponse":{"type":"object","required":["version","dateCreated","shortVersion","projects"],"properties":{"dateCreated":{"type":"string"},"dateReleased":{"type":["string","null"]},"projects":{"type":"array","items":{"$ref":"#/components/schemas/SentryReleaseProjectRef"}},"shortVersion":{"type":"string"},"version":{"type":"string"}}},"SeriesStateEntry":{"type":"object","description":"One series' persisted state snapshot for a dynamic rule (ADR-026 follow-up):\nthe state after the latest tick, the value evaluated this tick, and the open\nalarm id (when firing). Serialized into the `series_states` jsonb column keyed\nby the human-readable [`series_label`]; the alert response decodes it back.","required":["state","value"],"properties":{"alarm_id":{"type":["integer","null"],"format":"int32","description":"The open alarm's id when the series is firing; `null` when ok."},"state":{"type":"string","description":"`firing` or `ok` for this series after the latest tick."},"value":{"type":"number","format":"double","description":"The value the rule evaluated for this series this tick."}}},"ServiceAccessInfo":{"type":"object","description":"Response containing information about how the service is being accessed","required":["access_mode","can_create_domains"],"properties":{"access_mode":{"type":"string","description":"Mode of access: \"local\", \"direct\", \"nat\", or \"cloudflare_tunnel\""},"can_create_domains":{"type":"boolean","description":"Whether domain creation is allowed in this mode"},"domain_creation_error":{"type":["string","null"],"description":"Error message if domain creation is not allowed"},"private_ip":{"type":["string","null"],"description":"Server's private/local IP address (always returned if available)"},"public_ip":{"type":["string","null"],"description":"Server's public IP address (always returned if available)"}}},"ServiceAction":{"type":"string","description":"What to do with a service during migration","enum":["create","link-external","skip"]},"ServiceAlertRuleResponse":{"type":"object","description":"Wire representation of a monitoring alert rule.\n\nRegistered under a domain-prefixed OpenAPI schema name to avoid colliding\nwith `temps-error-tracking`'s unrelated `AlertRuleResponse` (utoipa keys\nschemas by their bare struct name, so without `as = ...` the last crate to\nregister would silently shadow this one in the merged spec / generated SDK).","required":["id","name","metric_name","threshold","comparator","severity","for_duration_secs","enabled"],"properties":{"comparator":{"type":"string"},"deployment_id":{"type":["integer","null"],"format":"int32"},"enabled":{"type":"boolean"},"for_duration_secs":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"metric_name":{"type":"string"},"name":{"type":"string"},"service_id":{"type":["integer","null"],"format":"int32"},"severity":{"type":"string"},"silenced_until":{"type":["string","null"]},"threshold":{"type":"number","format":"double"}}},"ServiceBackupEntryResponse":{"type":"object","description":"A single backup entry in the per-service backup list.","required":["id","backup_id","name","state","backup_type","started_at","s3_location","compression_type","s3_source_id","s3_source_name","external_service_backup_id"],"properties":{"backup_id":{"type":"string","description":"UUID string assigned at backup creation time."},"backup_type":{"type":"string","description":"Backup variant (e.g. \"full\", \"incremental\")."},"compression_type":{"type":"string","description":"Compression algorithm used (e.g. \"gzip\")."},"error_message":{"type":["string","null"],"description":"Engine-reported error message, populated when `state = \"failed\"`."},"external_service_backup_id":{"type":"integer","format":"int32","description":"Row ID from `external_service_backups`."},"finished_at":{"type":["string","null"],"description":"ISO 8601 timestamp when the backup finished, if known.","example":"2025-01-15T14:35:00Z"},"id":{"type":"integer","format":"int32","description":"Row ID from the `backups` table."},"name":{"type":"string","description":"Human-friendly display name."},"s3_location":{"type":"string","description":"Object key or `s3://` URL for the backup data."},"s3_source_id":{"type":"integer","format":"int32","description":"FK to `s3_sources.id`."},"s3_source_name":{"type":"string","description":"Human-readable name of the S3 source."},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size of the backup in bytes, if available."},"started_at":{"type":"string","description":"ISO 8601 timestamp when the backup started.","example":"2025-01-15T14:30:00Z"},"state":{"type":"string","description":"Current state: \"completed\", \"running\", \"failed\"."}}},"ServiceBackupListResponse":{"type":"object","description":"Paginated list of backups for a specific external service.\n\nReturned by `GET /backups/external-services/{service_id}/backups`.","required":["backups","total","page","page_size"],"properties":{"backups":{"type":"array","items":{"$ref":"#/components/schemas/ServiceBackupEntryResponse"},"description":"Backups belonging to this service, newest first."},"page":{"type":"integer","format":"int64","description":"Current page (1-based)."},"page_size":{"type":"integer","format":"int64","description":"Number of items per page."},"total":{"type":"integer","format":"int64","description":"Total number of backups for this service across all pages."}}},"ServiceCreateAlertRuleRequest":{"type":"object","description":"Request body for creating an alert rule on an external service.\n\nDomain-prefixed schema name — see [`AlertRuleResponse`] for why.","required":["name","metric_name","threshold","comparator","severity"],"properties":{"comparator":{"type":"string","description":"One of `>`, `<`, `>=`, `<=`."},"enabled":{"type":"boolean"},"for_duration_secs":{"type":"integer","format":"int32","description":"Seconds the breach must persist before the alarm fires (0 = immediate)."},"metric_name":{"type":"string"},"name":{"type":"string"},"severity":{"type":"string","description":"`\"warning\"` or `\"critical\"`."},"threshold":{"type":"number","format":"double"}}},"ServiceHealthResponse":{"type":"object","required":["service_id","consecutive_failures","recent_checks"],"properties":{"consecutive_failures":{"type":"integer","format":"int32","description":"Consecutive failed probes. Alert fires at 3."},"last_checked_at":{"type":["string","null"]},"last_error":{"type":["string","null"]},"recent_checks":{"type":"array","items":{"$ref":"#/components/schemas/HealthCheckEntryResponse"},"description":"Most recent checks, newest-first (capped at `limit`)."},"response_time_ms":{"type":["integer","null"],"format":"int32"},"service_id":{"type":"integer","format":"int32"},"status":{"type":["string","null"],"description":"Current health. `null` if the service has not been probed yet.","example":"operational"},"uptime_24h_percent":{"type":["number","null"],"format":"double","description":"Uptime percentage over the last 24 hours (0.0 — 100.0).\n`null` when there is not enough history."}}},"ServiceHealthStatusBatchResponse":{"type":"object","required":["statuses"],"properties":{"statuses":{"type":"array","items":{"$ref":"#/components/schemas/ServiceHealthStatusEntryResponse"}}}},"ServiceHealthStatusEntryResponse":{"type":"object","required":["service_id","consecutive_failures"],"properties":{"consecutive_failures":{"type":"integer","format":"int32"},"last_checked_at":{"type":["string","null"]},"service_id":{"type":"integer","format":"int32"},"status":{"type":["string","null"],"description":"\"operational\" | \"degraded\" | \"down\". `null` when the service has not\nbeen probed yet.","example":"operational"}}},"ServiceMemberInfo":{"type":"object","description":"Public info about a cluster member.","required":["id","role","container_name","status","ordinal"],"properties":{"compute_ip":{"type":["string","null"],"description":"Container's IP on the `temps-overlay` multi-host network. Populated\nby the lifecycle hook (ADR-011 Phase 3); `None` on single-host\nclusters where the overlay isn't attached."},"container_name":{"type":"string"},"hostname":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"live_state":{"type":["string","null"],"description":"Live FSM state from the pg_auto_failover monitor (`primary`,\n`secondary`, `catchingup`, `report_lsn`, …). `None` when the\nmonitor is unreachable, the service is not a cluster, or the row\nis the monitor itself.\n\n**The UI must render the role badge from this field**, falling\nback to `role` only when `live_state` is null. `role` is now\nconfig-only (`monitor` or `replica`); flipping the badge to\n\"primary\" when the monitor elects a new one used to require a\nreconciler that lagged ~5s behind real failovers — and during\nthat window the UI showed two primaries. `live_state` is read\ndirectly from the monitor on every list, so it can never lag."},"node_id":{"type":["integer","null"],"format":"int32"},"ordinal":{"type":"integer","format":"int32"},"port":{"type":["integer","null"],"format":"int32"},"provisioning_error":{"type":["string","null"],"description":"Most recent provisioning failure message, when `status='failed'`.\nSet by the background task so the UI can show *why* the new\nreplica didn't come up."},"provisioning_step":{"type":["string","null"],"description":"Last-attempted phase of the async `add_cluster_member` background\ntask (e.g. `validating`, `provisioning_container`, `done`,\n`failed`). `None` for members not created through that flow —\nthe UI falls back to the `status` column for those."},"role":{"type":"string"},"status":{"type":"string"}}},"ServiceParameter":{"type":"object","required":["name","required","encrypted","description"],"properties":{"choices":{"type":["array","null"],"items":{"type":"string"}},"default_value":{"type":["string","null"]},"description":{"type":"string"},"encrypted":{"type":"boolean"},"name":{"type":"string"},"required":{"type":"boolean"},"validation_pattern":{"type":["string","null"]}}},"ServicePlan":{"type":"object","description":"Plan for migrating a single service (database, cache, etc.)","required":["name","service_type","action","action_description"],"properties":{"action":{"$ref":"#/components/schemas/ServiceAction","description":"What to do with this service"},"action_description":{"type":"string","description":"Human-readable explanation of what this action means"},"data_implications":{"type":"array","items":{"$ref":"#/components/schemas/DataImplication"},"description":"Data implications specific to this service"},"env_var_mappings":{"type":"object","description":"Environment variable key mappings: source_key -> temps_key\n\nFor example, Vercel's `POSTGRES_URL` might map to Temps' `DATABASE_URL`.\nBoth keys will be set during migration so the app works with either.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":"string","description":"Human-readable service name"},"parameters":{"type":"object","description":"Parameters for creating the service in Temps","additionalProperties":{},"propertyNames":{"type":"string"}},"service_type":{"type":"string","description":"Service type (maps to temps-providers ServiceType)"},"version":{"type":["string","null"],"description":"Service version to create (e.g., \"16\" for Postgres 16)"}}},"ServiceResourceLimits":{"type":"object","description":"Optional cgroup resource limits applied to a service container.\n\nAll fields are `Option`: `None` means \"no limit\" (the kernel default),\nmatching Docker's behavior when the corresponding `HostConfig` field is\nleft at zero. Operators opt in to limits explicitly through the\n`PATCH /external-services/{id}/resources` endpoint or by writing the\n`resources` block into `ServiceConfig::parameters` at create time.\n\nThese map directly onto bollard fields:\n- `memory_mb` → `HostConfig.memory` (bytes)\n- `memory_swap_mb`→ `HostConfig.memory_swap` (bytes; ≥ memory)\n- `nano_cpus` → `HostConfig.nano_cpus` (1e9 = 1 full CPU)\n- `cpu_shares` → `HostConfig.cpu_shares` (relative weight, default 1024)\n- `shm_size_mb` → `HostConfig.shm_size` (bytes; default 64 MiB)\n\nIMPORTANT: enabling hard memory limits causes the kernel OOM killer to\nterminate the container when the working set exceeds the limit. The\ncontainer will restart (RestartPolicy::ALWAYS) but in-flight queries\nfail. Surface this clearly in any UI that lets users set limits.","properties":{"cpu_shares":{"type":["integer","null"],"format":"int64","description":"Relative CPU weight (default 1024). Only used when `nano_cpus` is None."},"memory_mb":{"type":["integer","null"],"format":"int64","description":"Hard memory limit in MiB. None = unlimited."},"memory_swap_mb":{"type":["integer","null"],"format":"int64","description":"Memory + swap limit in MiB. None = unlimited.\nMUST be >= memory_mb when both are set; Docker rejects the request otherwise.\nSet equal to `memory_mb` to disable swap entirely."},"nano_cpus":{"type":["integer","null"],"format":"int64","description":"CPU quota in nano-cpus. 1_000_000_000 = 1 full CPU core. None = unlimited."},"shm_size_mb":{"type":["integer","null"],"format":"int64","description":"Shared memory (/dev/shm) size in MiB. None = Docker default (64 MiB).\nMaps to HostConfig.shm_size (bytes). PostgreSQL uses /dev/shm for parallel\nquery workers and large work_mem; the 64 MiB default causes \"could not\nresize shared memory segment ... No space left on device\" under load.\nNOTE: shm_size is fixed at container-create time — Docker's live update\nAPI cannot change it, so changing this value recreates the container."}}},"ServiceRuntimeReport":{"type":"object","description":"Aggregate runtime info for an external service. For standalone services,\n`members` has exactly one entry. For clusters, one entry per member.","required":["service_id","topology","members"],"properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/ContainerRuntimeInfo"}},"service_id":{"type":"integer","format":"int32"},"topology":{"type":"string"}}},"ServiceStatsReport":{"type":"object","required":["service_id","topology","members"],"properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/ContainerStatsSample"}},"service_id":{"type":"integer","format":"int32"},"topology":{"type":"string"}}},"ServiceTypeInfo":{"type":"object","required":["service_type","parameters"],"properties":{"parameters":{"type":"array","items":{"$ref":"#/components/schemas/ServiceParameter"},"example":"[{\"name\": \"host\", \"required\": true, \"encrypted\": false, \"description\": \"Database host\"}]"},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute"}}},"ServiceTypeRoute":{"type":"string","enum":["mariadb","mongodb","postgres","redis","s3","kv","blob","rustfs","minio"]},"ServiceUpdateAlertRuleRequest":{"type":"object","description":"Request body for updating an existing alert rule.\n\nDomain-prefixed schema name — see [`AlertRuleResponse`] for why.","properties":{"comparator":{"type":["string","null"]},"enabled":{"type":["boolean","null"]},"for_duration_secs":{"type":["integer","null"],"format":"int32"},"metric_name":{"type":["string","null"]},"name":{"type":["string","null"]},"severity":{"type":["string","null"]},"threshold":{"type":["number","null"],"format":"double"}}},"SesCredentialsRequest":{"type":"object","required":["access_key_id","secret_access_key"],"properties":{"access_key_id":{"type":"string","example":"AKIAIOSFODNN7EXAMPLE"},"secret_access_key":{"type":"string","example":"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"}}},"SessionDetails":{"type":"object","required":["session_id","visitor_id","started_at","duration_seconds","is_bounced","is_engaged","page_views"],"properties":{"duration_seconds":{"type":"integer","format":"int64"},"ended_at":{"type":["string","null"],"format":"date-time","example":"2024-01-01T00:00:00"},"entry_path":{"type":["string","null"]},"exit_path":{"type":["string","null"]},"is_bounced":{"type":"boolean"},"is_engaged":{"type":"boolean"},"page_views":{"type":"integer","format":"int64"},"referrer":{"type":["string","null"]},"session_id":{"type":"integer","format":"int32"},"started_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"visitor_id":{"type":"string"}}},"SessionDetailsQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"SessionEvent":{"type":"object","required":["id","timestamp"],"properties":{"event_data":{},"event_name":{"type":["string","null"]},"event_type":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"page_title":{"type":["string","null"]},"page_url":{"type":["string","null"]},"timestamp":{"type":"string"}}},"SessionEventDto":{"type":"object","required":["id","session_id","data","timestamp"],"properties":{"data":{},"event_type":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"session_id":{"type":"integer","format":"int32"},"timestamp":{"type":"integer","format":"int64"}}},"SessionEventsQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"SessionEventsResponse":{"type":"object","required":["session_id","events","total_count","offset","limit"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/SessionEvent"}},"limit":{"type":"integer","format":"int32"},"offset":{"type":"integer","format":"int32"},"session_id":{"type":"integer","format":"int32"},"total_count":{"type":"integer","format":"int64"}}},"SessionLogsQuery":{"type":"object","required":["project_id"],"properties":{"end_date":{"type":["string","null"],"format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"offset":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"sort_order":{"type":["string","null"]},"start_date":{"type":["string","null"],"format":"date-time"},"visitor_id":{"type":["integer","null"],"format":"int32"}}},"SessionLogsResponse":{"type":"object","required":["session_id","logs","total_count","offset","limit"],"properties":{"limit":{"type":"integer","format":"int32"},"logs":{"type":"array","items":{"$ref":"#/components/schemas/SessionRequestLog"}},"offset":{"type":"integer","format":"int32"},"session_id":{"type":"integer","format":"int32"},"total_count":{"type":"integer","format":"int64"}}},"SessionReplayEventsRequest":{"type":"object","required":["sessionId","events"],"properties":{"events":{"type":"string"},"sessionId":{"type":"string"}}},"SessionReplayInfoDto":{"type":"object","required":["id","visitor_id"],"properties":{"created_at":{"type":["string","null"]},"duration":{"type":["integer","null"],"format":"int32"},"id":{"type":"string"},"language":{"type":["string","null"]},"screen_height":{"type":["integer","null"],"format":"int32"},"screen_width":{"type":["integer","null"],"format":"int32"},"timezone":{"type":["string","null"]},"url":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"viewport_height":{"type":["integer","null"],"format":"int32"},"viewport_width":{"type":["integer","null"],"format":"int32"},"visitor_id":{"type":"integer","format":"int32"}}},"SessionReplayInitRequest":{"type":"object","required":["sessionId"],"properties":{"colorDepth":{"type":["integer","null"],"format":"int32","minimum":0},"language":{"type":["string","null"]},"screenHeight":{"type":["integer","null"],"format":"int32","minimum":0},"screenWidth":{"type":["integer","null"],"format":"int32","minimum":0},"sessionId":{"type":"string"},"timestamp":{"type":["string","null"]},"timezone":{"type":["string","null"]},"url":{"type":["string","null"]},"userAgent":{"type":["string","null"]},"viewportHeight":{"type":["integer","null"],"format":"int32","minimum":0},"viewportWidth":{"type":["integer","null"],"format":"int32","minimum":0}}},"SessionReplayInitResponse":{"type":"object","required":["session_id","message"],"properties":{"message":{"type":"string"},"session_id":{"type":"string"}}},"SessionReplayWithEventsDto":{"type":"object","required":["session","events"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/SessionEventDto"}},"session":{"$ref":"#/components/schemas/SessionReplayWithVisitorDto"}}},"SessionReplayWithVisitorDto":{"type":"object","required":["id","session_replay_id","visitor_id","visitor_uuid","visitor_project_id","visitor_environment_id","visitor_first_seen","visitor_last_seen","visitor_is_crawler"],"properties":{"browser":{"type":["string","null"]},"browser_version":{"type":["string","null"]},"created_at":{"type":["string","null"]},"device_type":{"type":["string","null"]},"duration":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"language":{"type":["string","null"]},"operating_system":{"type":["string","null"]},"operating_system_version":{"type":["string","null"]},"screen_height":{"type":["integer","null"],"format":"int32"},"screen_width":{"type":["integer","null"],"format":"int32"},"session_replay_id":{"type":"string"},"timezone":{"type":["string","null"]},"url":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"viewport_height":{"type":["integer","null"],"format":"int32"},"viewport_width":{"type":["integer","null"],"format":"int32"},"visitor_city":{"type":["string","null"]},"visitor_country":{"type":["string","null"]},"visitor_country_code":{"type":["string","null"]},"visitor_crawler_name":{"type":["string","null"]},"visitor_custom_data":{},"visitor_environment_id":{"type":"integer","format":"int32"},"visitor_first_seen":{"type":"string"},"visitor_id":{"type":"integer","format":"int32"},"visitor_is_crawler":{"type":"boolean"},"visitor_last_seen":{"type":"string"},"visitor_project_id":{"type":"integer","format":"int32"},"visitor_region":{"type":["string","null"]},"visitor_uuid":{"type":"string"}}},"SessionRequestLog":{"type":"object","required":["id","method","path","status_code","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"method":{"type":"string"},"path":{"type":"string"},"referrer":{"type":["string","null"]},"request_headers":{"type":["string","null"]},"response_headers":{"type":["string","null"]},"response_time_ms":{"type":["integer","null"],"format":"int32"},"status_code":{"type":"integer","format":"int32"},"user_agent":{"type":["string","null"]}}},"SessionSummary":{"type":"object","required":["session_id","started_at","duration_seconds","page_views","events_count","requests_count","is_bounced","is_engaged"],"properties":{"duration_seconds":{"type":"integer","format":"int64"},"ended_at":{"type":["string","null"],"format":"date-time","example":"2024-01-01T00:00:00"},"entry_path":{"type":["string","null"]},"events_count":{"type":"integer","format":"int64"},"exit_path":{"type":["string","null"]},"is_bounced":{"type":"boolean"},"is_engaged":{"type":"boolean"},"page_views":{"type":"integer","format":"int64"},"referrer":{"type":["string","null"]},"requests_count":{"type":"integer","format":"int64"},"session_id":{"type":"integer","format":"int32"},"started_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"}}},"SetFlagEnvironmentRequest":{"type":"object","properties":{"enabled":{"type":["boolean","null"],"description":"The kill switch. `false` makes the flag serve its default regardless of\nany override — and, once targeting exists, regardless of any rule."},"value":{"description":"Tri-state: absent leaves the override, `null` clears it (inherit the\nflag default), anything else sets it. Must match `value_type`."}}},"SetPreviewPasswordBody":{"type":"object","required":["password"],"properties":{"password":{"type":"string","description":"Plaintext password to protect the sandbox's preview URLs. Hashed\nserver-side with argon2id — we never persist or echo this back.\nMust be between 8 and 256 characters."}}},"SetPreviewPasswordResponse":{"type":"object","required":["preview_password_hint"],"properties":{"preview_password_hint":{"type":"string","description":"Last 4 chars of the password we just stored. Surface in the UI so\nusers can confirm which password is live without re-entering it."}}},"SetRequest":{"type":"object","description":"Request to set a value","required":["key","value"],"properties":{"ex":{"type":["integer","null"],"format":"int64","description":"Expire in seconds","example":3600},"key":{"type":"string","description":"The key to set","example":"user:123"},"nx":{"type":"boolean","description":"Only set if key does not exist"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1},"px":{"type":["integer","null"],"format":"int64","description":"Expire in milliseconds"},"value":{"description":"The value to store (can be any JSON value)"},"xx":{"type":"boolean","description":"Only set if key exists"}}},"SetResponse":{"type":"object","description":"Response for set operation","required":["result"],"properties":{"result":{"type":"string","description":"Always \"OK\" on success","example":"OK"}}},"SettingsUpdateResponse":{"type":"object","description":"Response for successful settings update","required":["message"],"properties":{"message":{"type":"string"}}},"SetupDnsChallengeRequest":{"type":"object","description":"Request to setup DNS challenge records using a configured DNS provider","required":["dns_provider_id"],"properties":{"dns_provider_id":{"type":"integer","format":"int32","description":"The ID of the DNS provider to use for creating the TXT records"}}},"SetupDnsChallengeResponse":{"type":"object","description":"Response from DNS challenge setup operation","required":["success","records_created","total_records","results","message"],"properties":{"message":{"type":"string","description":"Human-readable summary message"},"records_created":{"type":"integer","format":"int32","description":"Number of TXT records that were successfully created","minimum":0},"results":{"type":"array","items":{"$ref":"#/components/schemas/DnsChallengeRecordResult"},"description":"Results for each individual TXT record"},"success":{"type":"boolean","description":"Overall success status (true if all records were created)"},"total_records":{"type":"integer","format":"int32","description":"Total number of TXT records required for the challenge","minimum":0}}},"SetupDnsRequest":{"type":"object","description":"Request to setup DNS records using a configured DNS provider","required":["dns_provider_id"],"properties":{"dns_provider_id":{"type":"integer","format":"int32","description":"The ID of the DNS provider to use for creating records"}}},"SetupDnsResponse":{"type":"object","description":"Response from DNS setup operation","required":["success","records_created","total_records","results","message"],"properties":{"message":{"type":"string","description":"Human-readable summary message"},"records_created":{"type":"integer","format":"int32","description":"Number of records that were successfully created","minimum":0},"results":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecordSetupResult"},"description":"Results for each individual record"},"success":{"type":"boolean","description":"Overall success status"},"total_records":{"type":"integer","format":"int32","description":"Total number of records attempted","minimum":0}}},"SiblingRef":{"type":"object","description":"A sibling project that shares the same `trace_id` and has opted in to\ncross-project trace sharing (`cross_project_trace_sharing = TRUE`).\n\nReturned by `CrossProjectTraceService::find_sibling_projects` and exposed\nby the Phase 1 `GET /otel/traces/cross-project/{trace_id}` endpoint.","required":["project_id","project_name","project_slug","first_seen"],"properties":{"first_seen":{"type":"string","format":"date-time"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"project_slug":{"type":"string","description":"URL slug used to link into the sibling project's single-project trace view."}}},"SkillDefinitionResponse":{"type":"object","required":["id","slug","name","content","has_archive","created_at","updated_at"],"properties":{"content":{"type":"string"},"created_at":{"type":"string"},"description":{"type":["string","null"]},"has_archive":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"project_id":{"type":["integer","null"],"format":"int32"},"slug":{"type":"string"},"updated_at":{"type":"string"}}},"SlackConfig":{"type":"object","required":["webhook_url"],"properties":{"channel":{"type":["string","null"]},"webhook_url":{"type":"string"}}},"SlowQueriesResponse":{"type":"object","description":"Response envelope for the slow-queries list endpoint.","required":["queries","page","page_size","total_count"],"properties":{"page":{"type":"integer","format":"int32","description":"Current page number (1-based).","minimum":0},"page_size":{"type":"integer","format":"int32","description":"Number of rows per page used for this request.","minimum":0},"queries":{"type":"array","items":{"$ref":"#/components/schemas/SlowQueryRow"},"description":"Ordered list of query stats, slowest first by mean_exec_time_ms."},"total_count":{"type":"integer","format":"int64","description":"Total number of qualifying rows across all pages.","minimum":0}}},"SlowQueryRow":{"type":"object","description":"A single entry from `pg_stat_statements`, representing one normalized\nquery fingerprint and its aggregate execution stats.","required":["query","database","calls","total_exec_time_ms","mean_exec_time_ms","rows"],"properties":{"cache_hit_ratio":{"type":["number","null"],"format":"double","description":"Shared block cache hit ratio (0.0–1.0).\n`None` when total block accesses are zero (e.g. function-only queries)."},"calls":{"type":"integer","format":"int64","description":"Number of times this query was executed."},"database":{"type":"string","description":"Name of the database this query ran against. `(dropped database)`\nwhen the originating database no longer exists but\n`pg_stat_statements` still holds stats for it."},"mean_exec_time_ms":{"type":"number","format":"double","description":"Average wall-clock time per execution, in milliseconds."},"query":{"type":"string","description":"Normalized query text (parameter literals replaced with `$N`)."},"rows":{"type":"integer","format":"int64","description":"Total number of rows returned or affected."},"total_exec_time_ms":{"type":"number","format":"double","description":"Total wall-clock time spent executing this query, in milliseconds."}}},"SmartFilter":{"oneOf":[{"type":"object","description":"Match specific page path","required":["value","type"],"properties":{"type":{"type":"string","enum":["page_path"]},"value":{"type":"string","description":"Match specific page path"}}},{"type":"object","description":"Match specific hostname","required":["value","type"],"properties":{"type":{"type":"string","enum":["hostname"]},"value":{"type":"string","description":"Match specific hostname"}}},{"type":"object","description":"Match UTM source","required":["value","type"],"properties":{"type":{"type":"string","enum":["utm_source"]},"value":{"type":"string","description":"Match UTM source"}}},{"type":"object","description":"Match UTM campaign","required":["value","type"],"properties":{"type":{"type":"string","enum":["utm_campaign"]},"value":{"type":"string","description":"Match UTM campaign"}}},{"type":"object","description":"Match UTM medium","required":["value","type"],"properties":{"type":{"type":"string","enum":["utm_medium"]},"value":{"type":"string","description":"Match UTM medium"}}},{"type":"object","description":"Match referrer hostname","required":["value","type"],"properties":{"type":{"type":"string","enum":["referrer_hostname"]},"value":{"type":"string","description":"Match referrer hostname"}}},{"type":"object","description":"Match specific channel (organic, paid, direct, referral, etc.)","required":["value","type"],"properties":{"type":{"type":"string","enum":["channel"]},"value":{"type":"string","description":"Match specific channel (organic, paid, direct, referral, etc.)"}}},{"type":"object","description":"Match device type (mobile, desktop, tablet)","required":["value","type"],"properties":{"type":{"type":"string","enum":["device_type"]},"value":{"type":"string","description":"Match device type (mobile, desktop, tablet)"}}},{"type":"object","description":"Match browser","required":["value","type"],"properties":{"type":{"type":"string","enum":["browser"]},"value":{"type":"string","description":"Match browser"}}},{"type":"object","description":"Match operating system","required":["value","type"],"properties":{"type":{"type":"string","enum":["operating_system"]},"value":{"type":"string","description":"Match operating system"}}},{"type":"object","description":"Match language","required":["value","type"],"properties":{"type":{"type":"string","enum":["language"]},"value":{"type":"string","description":"Match language"}}},{"type":"object","description":"Match custom event_data by JSON path\nFormat: {\"path\": \"user.plan\", \"value\": \"premium\"}\nThis will match events where event_data->'user'->>'plan' = 'premium'","required":["value","type"],"properties":{"type":{"type":"string","enum":["custom_data"]},"value":{"type":"object","description":"Match custom event_data by JSON path\nFormat: {\"path\": \"user.plan\", \"value\": \"premium\"}\nThis will match events where event_data->'user'->>'plan' = 'premium'","required":["path","value"],"properties":{"path":{"type":"string"},"value":{"type":"string"}}}}}],"description":"Smart filter presets for common funnel patterns"},"SmokeTestResponse":{"type":"object","required":["passed","environment","cli_installed","cli_authenticated"],"properties":{"auth_info":{"type":["string","null"],"description":"Auth email / method"},"cli_authenticated":{"type":"boolean","description":"Claude CLI authenticated?"},"cli_installed":{"type":"boolean","description":"Claude CLI installed?"},"cli_version":{"type":["string","null"],"description":"Claude CLI version"},"detail":{"type":["string","null"],"description":"Full output for debugging"},"environment":{"type":"string","description":"Where the test ran: \"host\" or \"sandbox\""},"passed":{"type":"boolean","description":"Whether the smoke test passed"},"setup_hint":{"type":["string","null"],"description":"What the user needs to do if the test failed"}}},"SmtpCredentialsRequest":{"type":"object","description":"Generic SMTP credentials request body.\n\nWorks with any SMTP relay — AWS SES SMTP endpoints, Sendgrid, Mailgun,\nPostmark, or a self-hosted Postfix. Use this when you only have SMTP\ncredentials (i.e. you cannot create identities via the upstream API).","required":["host","port"],"properties":{"accept_invalid_certs":{"type":"boolean","description":"Accept self-signed certificates. Only safe for local testing."},"encryption":{"$ref":"#/components/schemas/SmtpEncryptionRoute","description":"TLS mode. Defaults to STARTTLS."},"host":{"type":"string","description":"SMTP host, e.g. `email-smtp.eu-west-1.amazonaws.com`.","example":"email-smtp.eu-west-1.amazonaws.com"},"password":{"type":["string","null"],"description":"SMTP password / API token. Required when `username` is set."},"port":{"type":"integer","format":"int32","description":"SMTP port (587 for STARTTLS, 465 for implicit TLS, 25/1025 for plain).","example":587,"minimum":0},"username":{"type":["string","null"],"description":"SMTP username. Leave empty for unauthenticated relays.","example":"AKIAIOSFODNN7EXAMPLE"}}},"SmtpEncryptionRoute":{"type":"string","description":"TLS mode for the SMTP relay.","enum":["starttls","tls","none"]},"SmtpResult":{"type":"object","description":"SMTP validation result","required":["can_connect_smtp","has_full_inbox","is_catch_all","is_deliverable","is_disabled"],"properties":{"can_connect_smtp":{"type":"boolean","description":"Whether we could connect to the SMTP server"},"error":{"type":["string","null"],"description":"Error message if SMTP check failed"},"has_full_inbox":{"type":"boolean","description":"Whether the mailbox appears to have a full inbox"},"is_catch_all":{"type":"boolean","description":"Whether this is a catch-all domain"},"is_deliverable":{"type":"boolean","description":"Whether the email is deliverable"},"is_disabled":{"type":"boolean","description":"Whether the mailbox is disabled"}}},"SourceArchiveUpload":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary"}}},"SourceBackupEntry":{"type":"object","description":"Entry in the source backup index. Covers both DB-tracked backups\n(have a row in `backups`) and S3-scan discoveries (raw S3 objects with\nno DB row — used for disaster-recovery from another Temps instance).","required":["id","backup_id","name","backup_type","created_at","location","metadata_location","source","state"],"properties":{"backup_id":{"type":"string","description":"UUID identifier from the DB row. Empty for S3-scan entries.","example":"550e8400-e29b-41d4-a716-446655440000"},"backup_type":{"type":"string","description":"Backup variant as recorded by the backup pipeline (e.g. \"full\").","example":"full"},"created_at":{"type":"string","description":"When the backup was created. For S3-scan entries this is the\nobject's LastModified time.","example":"2024-01-15T14:30:00.123Z"},"engine":{"type":["string","null"],"description":"Engine that produced the backup (\"postgres\", \"redis\", \"mongodb\",\n\"s3\", \"rustfs\"). Used by the UI to mark engine-compat with the\ntarget service.","example":"postgres"},"format":{"type":["string","null"],"description":"Storage format: \"walg\" for continuous-archive (PITR-capable),\n\"pg_dump\" for point-in-time dumps, \"\" for non-postgres.","example":"walg"},"id":{"type":"integer","format":"int32","description":"DB row id. Zero for S3-scan entries that have no DB row.","example":1},"location":{"type":"string","description":"Raw S3 URL / key where the backup sits. For Postgres WAL-G backups\nthis starts with `s3://`; for pg_dump-style backups it's the\nrelative object key.","example":"s3://bucket/external_services/postgres/svc-name/walg"},"metadata_location":{"type":"string","description":"Sidecar metadata.json location, if any. Empty when none.","example":""},"name":{"type":"string","description":"Human-friendly display name (\"postgres backup (svc-name)\" for DB\nrows, or a synthesized label derived from the S3 path for scans).","example":"postgres backup (postgres-n4ea)"},"origin_service_name":{"type":["string","null"],"description":"Name of the service that produced the backup. For S3-scan entries\nthis is parsed from the S3 path.","example":"postgres-n4ea"},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size of the backup in bytes, if known.","example":1024000},"source":{"type":"string","description":"Provenance: \"db\" for rows in this Temps, \"s3_scan\" for objects\ndiscovered by the S3 bucket walk (e.g., backups made by another\nTemps instance).","example":"db"},"state":{"type":"string","description":"Observed state (\"completed\", \"running\", \"failed\") — DB only.\nEmpty string for S3-scan entries.","example":"completed"}}},"SourceBackupIndexResponse":{"type":"object","description":"Response type for source backup index","required":["backups","last_updated"],"properties":{"backups":{"type":"array","items":{"$ref":"#/components/schemas/SourceBackupEntry"},"description":"List of backups in the source"},"last_updated":{"type":"string","description":"When the index was last updated","example":"2024-01-15T14:30:00.123Z"}}},"SourceBody":{"oneOf":[{"type":"object","required":["url","type"],"properties":{"depth":{"type":["integer","null"],"format":"int32","minimum":0},"git_connection_id":{"type":["integer","null"],"format":"int32"},"password":{"type":["string","null"]},"revision":{"type":["string","null"]},"type":{"type":"string","enum":["git"]},"url":{"type":"string"},"username":{"type":["string","null"]}}},{"type":"object","required":["url","type"],"properties":{"type":{"type":"string","enum":["tarball"]},"url":{"type":"string"}}}],"description":"Initial content to seed into the sandbox work dir. Mirrors the\n`@vercel/sandbox` `source` option. `type` is one of:\n- `git` — clone `url`; optionally check out `revision`\n- `tarball` — download `url` (must be tar or tar.gz) and extract\n\nFor private git repos, pass credentials one of two ways:\n1. **Inline (SDK-compatible):** `username` + `password`. GitHub\n tokens use `username: \"x-access-token\"`.\n2. **Stored connection (temps-native):** `git_connection_id`\n references a row in the caller's git provider connections. Temps\n resolves the token server-side and injects it safely.\n\n`git_connection_id` is mutually exclusive with `username`/`password`."},"SourceFileListResponse":{"type":"object","required":["source_files","total"],"properties":{"source_files":{"type":"array","items":{"$ref":"#/components/schemas/SourceFileResponse"}},"total":{"type":"integer","minimum":0}}},"SourceFileResponse":{"type":"object","required":["id","project_id","release","file_path","size_bytes","created_at"],"properties":{"checksum":{"type":["string","null"]},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"file_path":{"type":"string"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"release":{"type":"string"},"size_bytes":{"type":"integer","format":"int64"}}},"SourceMapListResponse":{"type":"object","required":["source_maps","total"],"properties":{"source_maps":{"type":"array","items":{"$ref":"#/components/schemas/SourceMapResponse"}},"total":{"type":"integer","minimum":0}}},"SourceMapResponse":{"type":"object","required":["id","project_id","release","file_path","size_bytes","created_at"],"properties":{"checksum":{"type":["string","null"]},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"dist":{"type":["string","null"]},"file_path":{"type":"string"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"release":{"type":"string"},"size_bytes":{"type":"integer","format":"int64"}}},"SourceType":{"type":"string","description":"Source type for project deployments\n\nDetermines where the deployment artifacts come from:\n- `Git`: Source code from a Git repository (traditional flow)\n- `DockerImage`: Pre-built Docker image from external registry\n- `StaticFiles`: Pre-built static files uploaded as a bundle\n- `UploadedSource`: Source archive uploaded without a Git repository\n- `Manual`: Flexible type that accepts any deployment method","enum":["git","docker_image","static_files","uploaded_source","manual"]},"SpanEvent":{"type":"object","description":"A span event (log-like annotation on a span).","required":["timestamp","name","attributes"],"properties":{"attributes":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":"string"},"timestamp":{"type":"string","format":"date-time"}}},"SpanKind":{"type":"string","description":"Span kind.","enum":["UNSPECIFIED","INTERNAL","SERVER","CLIENT","PRODUCER","CONSUMER"]},"SpanRecord":{"type":"object","description":"A single trace span ready for storage.","required":["project_id","resource","trace_id","span_id","name","kind","start_time","end_time","duration_ms","status_code","status_message","attributes","events"],"properties":{"attributes":{"type":"object","description":"Raw key/value pairs exactly as reported by the instrumenting library.\nNumeric values are NOT guaranteed to share `duration_ms`'s unit — they\nmay be seconds, milliseconds, microseconds, or nanoseconds depending on\nthe exporter's own convention, and the unit is not labeled here.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"deployment_id":{"type":["integer","null"],"format":"int32"},"duration_ms":{"type":"number","format":"double","description":"Span duration in milliseconds. The only field on this struct guaranteed\nto be in milliseconds."},"end_time":{"type":"string","format":"date-time"},"events":{"type":"array","items":{"$ref":"#/components/schemas/SpanEvent"}},"kind":{"$ref":"#/components/schemas/SpanKind"},"name":{"type":"string"},"parent_span_id":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"resource":{"$ref":"#/components/schemas/ResourceInfo"},"span_id":{"type":"string"},"start_time":{"type":"string","format":"date-time"},"status_code":{"$ref":"#/components/schemas/SpanStatusCode"},"status_message":{"type":"string"},"trace_id":{"type":"string"}}},"SpanRow":{"type":"object","required":["id","ts","trace_id","span_id","service","operation","attributes","attributes_truncated"],"properties":{"attributes":{},"attributes_truncated":{"type":"boolean"},"deployment_id":{"type":["integer","null"],"format":"int32"},"duration_ms":{"type":["number","null"],"format":"double"},"environment_id":{"type":["integer","null"],"format":"int32"},"id":{"type":"string"},"operation":{"type":"string"},"parent_span_id":{"type":["string","null"]},"service":{"type":"string"},"span_id":{"type":"string"},"status":{"type":["string","null"]},"trace_id":{"type":"string"},"ts":{"type":"string","format":"date-time"}}},"SpanStatusCode":{"type":"string","description":"Span status code.","enum":["UNSET","OK","ERROR"]},"SpeedMetricsPayload":{"type":"object","description":"Speed metrics payload for recording web vitals","properties":{"cls":{"type":["number","null"],"format":"float","description":"Cumulative Layout Shift (score)"},"fcp":{"type":["number","null"],"format":"float","description":"First Contentful Paint (milliseconds)"},"fid":{"type":["number","null"],"format":"float","description":"First Input Delay (milliseconds)"},"inp":{"type":["number","null"],"format":"float","description":"Interaction to Next Paint (milliseconds)"},"language":{"type":["string","null"],"description":"Browser language"},"lcp":{"type":["number","null"],"format":"float","description":"Largest Contentful Paint (milliseconds)"},"pathname":{"type":["string","null"],"description":"Page pathname"},"query":{"type":["string","null"],"description":"Query string"},"screenHeight":{"type":["integer","null"],"format":"int32","description":"Screen height in pixels"},"screenWidth":{"type":["integer","null"],"format":"int32","description":"Screen width in pixels"},"ttfb":{"type":["number","null"],"format":"float","description":"Time to First Byte (milliseconds)"},"viewportHeight":{"type":["integer","null"],"format":"int32","description":"Viewport height in pixels"},"viewportWidth":{"type":["integer","null"],"format":"int32","description":"Viewport width in pixels"}}},"SpeedSegmentFilters":{"type":"object","description":"Optional segment filters for the performance read endpoints, mirroring\nanalytics' `VisitorSegmentFilters`. Each filter narrows results to samples\nmatching the dimension value, so metrics can be scoped to e.g. one page,\none browser, or one country. Geographic filters resolve via\n`ip_geolocations`; the rest live directly on `performance_metrics`.","properties":{"filter_browser":{"type":["string","null"],"description":"Browser name (matches `performance_metrics.browser`)"},"filter_city":{"type":["string","null"],"description":"Geolocation city (matches `ip_geolocations.city`)"},"filter_country":{"type":["string","null"],"description":"Geolocation country (matches `ip_geolocations.country`)"},"filter_operating_system":{"type":["string","null"],"description":"Operating system (matches `performance_metrics.operating_system`)"},"filter_path":{"type":["string","null"],"description":"Page pathname (matches `performance_metrics.pathname`)"},"filter_region":{"type":["string","null"],"description":"Geolocation region (matches `ip_geolocations.region`)"}}},"StaleSlot":{"type":"object","required":["slot_name","active","retained_bytes"],"properties":{"active":{"type":"boolean"},"retained_bytes":{"type":"integer","format":"int64"},"slot_name":{"type":"string"}}},"StartAnalysisRequest":{"type":"object","required":["error_group_id"],"properties":{"branch":{"type":["string","null"],"description":"Branch to clone instead of the project's main branch."},"error_group_id":{"type":"integer","format":"int32"},"max_turns":{"type":["integer","null"],"format":"int32","description":"Per-run turn cap applied to every phase (1–200). Only enforced for\nCLIs with a turn flag (Claude Code). `None` uses the provider's\nconfigured defaults."},"model":{"type":["string","null"],"description":"Model id for the chosen provider. `None` uses the provider's saved\ndefault model."},"provider":{"type":["string","null"],"description":"AI provider id (\"claude_cli\", \"codex_cli\", \"opencode\"). `None` uses\nthe platform default provider."},"user_context":{"type":["string","null"],"description":"Free-text notes for the model (extra context about the error, retry\nguidance, constraints). Included verbatim in the analysis prompt."}}},"StartPgUpgradeRequest":{"type":"object","required":["from_version","to_version","from_image","to_image"],"properties":{"from_image":{"type":"string","example":"postgres:16-bookworm"},"from_version":{"type":"string","example":"16"},"to_image":{"type":"string","example":"postgres:17-bookworm"},"to_version":{"type":"string","example":"17"}}},"StartRestoreRequest":{"allOf":[{"$ref":"#/components/schemas/RestoreRequestMode","description":"Requested restore mode. See `RestoreRequestMode`."},{"type":"object","properties":{"backup_engine":{"type":["string","null"],"description":"Engine of the backup when specified by `backup_location`\n(\"postgres\", \"redis\", \"mongodb\", \"s3\"). Ignored when `backup_id`\nis used — we infer from the DB row."},"backup_id":{"type":["integer","null"],"format":"int32","description":"DB id of the backup to restore from. Either `backup_id` or\n`backup_location` MUST be provided. Use `backup_id` when restoring\na backup this Temps instance recorded."},"backup_location":{"type":["string","null"],"description":"Raw S3 URL / key of the backup — used when restoring a backup\ndiscovered by S3 scan (i.e., produced by another Temps instance).\nRequires `backup_engine` and `s3_source_id` to also be set."},"s3_source_id":{"type":["integer","null"],"format":"int32","description":"S3 source the `backup_location` lives in. Ignored when `backup_id`\nis used."}}}]},"StatResponse":{"type":"object","required":["path","exists","is_dir","is_file","size"],"properties":{"exists":{"type":"boolean"},"is_dir":{"type":"boolean"},"is_file":{"type":"boolean"},"path":{"type":"string"},"size":{"type":"integer","format":"int64","minimum":0}}},"StaticBundleResponse":{"type":"object","required":["id","project_id","blob_path","content_type","size_bytes","uploaded_at","created_at"],"properties":{"blob_path":{"type":"string"},"checksum":{"type":["string","null"]},"content_type":{"type":"string"},"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"format":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"metadata":{},"original_filename":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"size_bytes":{"type":"integer","format":"int64"},"uploaded_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"}}},"StaticParams":{"type":"object","description":"Static threshold detector: compare the aggregated `value` against `threshold`.","required":["comparator","threshold"],"properties":{"comparator":{"$ref":"#/components/schemas/Comparator","description":"How `value` is compared against `threshold`."},"threshold":{"type":"number","format":"double","description":"The threshold the aggregated value is compared against."}}},"StaticPresetConfig":{"type":"object","description":"Configuration for static site presets (Vite, Next.js, Docusaurus, etc.)\nThese presets build static sites that are served via a web server","properties":{"buildCommand":{"type":["string","null"],"description":"Custom build command (overrides preset default)","example":"npm run build:production"},"buildContext":{"type":["string","null"],"description":"Custom build context path (relative to repository root)\nUseful for monorepo setups where the app is in a subdirectory","example":"./apps/frontend"},"installCommand":{"type":["string","null"],"description":"Custom install command (overrides auto-detected package manager)","example":"npm ci"},"outputDir":{"type":["string","null"],"description":"Custom output directory (overrides preset default)\nCommon values: \"dist\", \"build\", \".next\", \"out\"","example":"dist"}}},"StatsFilters":{"type":"object","description":"Filters for statistics queries","properties":{"client_ip":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"device_type":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"has_project":{"type":["boolean","null"],"description":"When true, only count requests that matched a project (project_id IS NOT NULL).\nUsed by the health dashboard so totals match the per-project cards."},"host":{"type":["string","null"]},"is_bot":{"type":["boolean","null"]},"method":{"type":["string","null"]},"project_id":{"type":["integer","null"],"format":"int32"},"request_source":{"type":["string","null"]},"routing_status":{"type":["string","null"]},"status_code":{"type":["integer","null"],"format":"int32"},"status_code_class":{"type":["string","null"],"description":"Filter by status code class (e.g. \"2xx\", \"3xx\", \"4xx\", \"5xx\")"}}},"StatusBucket":{"type":"object","required":["bucket_start","status","total_checks","operational_count","degraded_count","down_count","uptime_percentage"],"properties":{"avg_response_time_ms":{"type":["number","null"],"format":"double"},"bucket_start":{"type":"string","format":"date-time"},"degraded_count":{"type":"integer","format":"int64"},"down_count":{"type":"integer","format":"int64"},"max_response_time_ms":{"type":["number","null"],"format":"double"},"min_response_time_ms":{"type":["number","null"],"format":"double"},"operational_count":{"type":"integer","format":"int64"},"p50_response_time_ms":{"type":["number","null"],"format":"double"},"p95_response_time_ms":{"type":["number","null"],"format":"double"},"p99_response_time_ms":{"type":["number","null"],"format":"double"},"status":{"type":"string"},"total_checks":{"type":"integer","format":"int64"},"uptime_percentage":{"type":"number","format":"double"}}},"StatusBucketedResponse":{"type":"object","required":["monitor_id","interval","buckets"],"properties":{"buckets":{"type":"array","items":{"$ref":"#/components/schemas/StatusBucket"}},"interval":{"type":"string"},"monitor_id":{"type":"integer","format":"int32"}}},"StatusCodeCount":{"type":"object","required":["status_code","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"percentage":{"type":"number","format":"double"},"status_code":{"type":"integer","format":"int32"}}},"StatusCodesQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"StatusPageOverview":{"type":"object","required":["status","monitors","recent_incidents"],"properties":{"monitors":{"type":"array","items":{"$ref":"#/components/schemas/MonitorStatus"}},"recent_incidents":{"type":"array","items":{"$ref":"#/components/schemas/IncidentResponse"}},"status":{"type":"string"}}},"StepConversionResponse":{"type":"object","required":["step_id","step_name","step_order","completions","conversion_rate","drop_off_rate","average_time_to_complete_seconds"],"properties":{"average_time_to_complete_seconds":{"type":"number","format":"double"},"completions":{"type":"integer","format":"int64","minimum":0},"conversion_rate":{"type":"number","format":"double"},"drop_off_rate":{"type":"number","format":"double"},"step_id":{"type":"integer","format":"int32"},"step_name":{"type":"string"},"step_order":{"type":"integer","format":"int32"}}},"StepResourceType":{"type":"string","description":"What kind of resource a migration step operates on","enum":["project","environment","deployment","environment-variable","service","domain","git-link","other"]},"StepResult":{"type":"object","description":"Result of executing a single migration step","required":["step_id","step_title","success","skipped","message","created_resources","duration_seconds"],"properties":{"created_resources":{"type":"array","items":{"$ref":"#/components/schemas/CreatedResource"},"description":"Resources created by this step"},"duration_seconds":{"type":"number","format":"double","description":"Duration of this step"},"message":{"type":"string","description":"Human-readable message about what happened"},"skipped":{"type":"boolean","description":"Whether this step was skipped"},"step_id":{"type":"string","description":"Step ID (matches `MigrationStep.id`)"},"step_title":{"type":"string","description":"Step title (for display)"},"success":{"type":"boolean","description":"Whether this step succeeded"}}},"StepUpResponse":{"type":"object","required":["expires_at"],"properties":{"expires_at":{"type":"string","format":"date-time","description":"ISO 8601 timestamp after which sensitive actions require verification\nagain."}}},"StopSequence":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"StorageQuota":{"type":"object","description":"Quota usage information for a project.","required":["project_id","metrics_bytes","traces_bytes","logs_bytes","total_bytes","limit_bytes","usage_pct"],"properties":{"limit_bytes":{"type":"integer","format":"int64","minimum":0},"logs_bytes":{"type":"integer","format":"int64","minimum":0},"metrics_bytes":{"type":"integer","format":"int64","minimum":0},"project_id":{"type":"integer","format":"int32"},"total_bytes":{"type":"integer","format":"int64","minimum":0},"traces_bytes":{"type":"integer","format":"int64","minimum":0},"usage_pct":{"type":"number","format":"double"}}},"StripeConfig":{"type":"object","properties":{"include_unpriced_charges":{"type":"boolean","description":"When an allowlist is set, should we still ingest charges that\nlack a price reference (e.g. standalone `charge.succeeded` without\na subscription)? Default true — charges don't belong to a SKU."},"metered_mode":{"$ref":"#/components/schemas/MeteredMode","description":"How to compute MRR for metered / tiered / hybrid subscriptions."},"price_allowlist":{"type":"array","items":{"type":"string"},"description":"Only events tagged with one of these Stripe price IDs are ingested.\nEmpty = accept all prices."},"product_allowlist":{"type":"array","items":{"type":"string"},"description":"Only events tagged with one of these Stripe product IDs are\ningested. Empty = accept all products. Combined with\n`price_allowlist` via OR — if either list has a match, accept."}}},"SyncedRepositoryListQuery":{"type":"object","properties":{"direction":{"type":["string","null"]},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"language":{"type":["string","null"]},"owner":{"type":["string","null"]},"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0},"private":{"type":["boolean","null"]},"search":{"type":["string","null"]},"sort":{"type":["string","null"]}}},"SyntaxResult":{"type":"object","description":"Syntax validation result","required":["is_valid_syntax"],"properties":{"domain":{"type":["string","null"],"description":"The domain part of the email","example":"gmail.com"},"is_valid_syntax":{"type":"boolean","description":"Whether the email syntax is valid"},"suggestion":{"type":["string","null"],"description":"Suggested email correction if available"},"username":{"type":["string","null"],"description":"The username part of the email","example":"someone"}}},"TagInfo":{"type":"object","required":["name","commit_sha"],"properties":{"commit_sha":{"type":"string"},"name":{"type":"string"}}},"TagListResponse":{"type":"object","required":["tags"],"properties":{"tags":{"type":"array","items":{"$ref":"#/components/schemas/TagInfo"}}}},"TailLogsRequest":{"type":"object","required":["project_id","service","env"],"properties":{"env":{"type":"string"},"external_service_id":{"type":["integer","null"],"format":"int32","description":"When set, tail an imported/managed external service's logs instead of\na project's (`project_id` is ignored in this mode)."},"levels":{"type":"array","items":{"type":"string"}},"project_id":{"type":"integer","format":"int32","description":"Project ID (integer, as used by the rest of the platform)"},"service":{"type":"string"},"text":{"type":["string","null"]}}},"TargetRecommendation":{"type":"object","description":"The temps/Hetzner target sizing and savings estimate","required":["server_type","vcpus","memory_gb","monthly_eur","fits_single_node","sizing_basis","rationale"],"properties":{"fits_single_node":{"type":"boolean","description":"Whether the workloads fit a single recommended server. When `false`,\nthe rationale explains the multi-node option (temps worker nodes)."},"memory_gb":{"type":"integer","format":"int32","description":"Memory (GB) of the recommended server"},"monthly_eur":{"type":"number","format":"double","description":"Estimated monthly price of the recommended server in EUR"},"monthly_savings_usd":{"type":["number","null"],"format":"double","description":"Estimated monthly savings in USD (current cost minus target cost,\ntreating EUR≈USD for the rough comparison — disclaimed in `notes`).\n`None` when the current cost is unknown."},"rationale":{"type":"string","description":"Human-readable recommendation summary"},"server_type":{"type":"string","description":"Recommended Hetzner server type (e.g. \"cpx32\")"},"sizing_basis":{"type":"string","description":"What the sizing was based on, e.g. \"2× measured usage + temps\nplatform overhead\" or \"resource requests (no metrics available)\""},"vcpus":{"type":"integer","format":"int32","description":"vCPUs of the recommended server"},"yearly_savings_usd":{"type":["number","null"],"format":"double","description":"`monthly_savings_usd × 12`"}}},"TeamListResponse":{"type":"object","required":["teams","total","page","page_size"],"properties":{"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"teams":{"type":"array","items":{"$ref":"#/components/schemas/TeamResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"TeamMemberResponse":{"type":"object","required":["id","team_id","user_id","role","added_by","created_at","updated_at"],"properties":{"added_by":{"type":"integer","format":"int32"},"created_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"},"id":{"type":"integer","format":"int32"},"role":{"$ref":"#/components/schemas/TeamRole","description":"The source of this member's project-scoped permissions, intersected\nwith `project_team_access.role`."},"team_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"},"user_email":{"type":["string","null"],"description":"The member's email, joined from `users`."},"user_id":{"type":"integer","format":"int32"},"user_name":{"type":["string","null"],"description":"The member's display name, joined from `users`. `None` if the\nreferenced user no longer exists."}}},"TeamResponse":{"type":"object","required":["id","name","slug","created_by","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"},"created_by":{"type":"integer","format":"int32"},"description":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"slug":{"type":"string"},"updated_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"}}},"TeamRole":{"type":"string","description":"Role a user holds within a team, or that a team holds on a project.\n\nNamed `TeamRole` rather than `Role` to keep it distinct from\n`temps_auth::permissions::Role`, which is the instance-wide role\n(Admin/User/…) attached to a session. The two are orthogonal: the\ninstance-wide role decides whether you may touch a resource *kind* at\nall, `TeamRole` decides what you may do *within a project* you have\nteam access to. See `temps_teams::fixed_role_permissions` for the\nproject-scoped permission set each variant maps to.\n\nStored as a `varchar(32)` rather than a Postgres enum so the role set\ncan evolve in pure migration code without a schema-level enum\nalteration blocking a downgrade.","enum":["owner","admin","deployer","viewer"]},"TemplateResponse":{"type":"object","description":"Response type for a single template","required":["slug","name","git","preset","tags","features","services","env_vars","is_featured"],"properties":{"description":{"type":["string","null"],"description":"Short description"},"env_vars":{"type":"array","items":{"$ref":"#/components/schemas/EnvVarTemplateResponse"},"description":"Environment variables template"},"exposed_port":{"type":["integer","null"],"format":"int32","description":"Container port the prebuilt image listens on (image deploys only)."},"features":{"type":"array","items":{"type":"string"},"description":"Feature highlights"},"git":{"$ref":"#/components/schemas/GitRefResponse","description":"Git repository reference"},"health_check_path":{"type":["string","null"],"description":"HTTP health-check path probed after the container starts (image deploys)."},"image":{"type":["string","null"],"description":"Prebuilt Docker image reference. When set, the one-click deploy pulls and\nruns this image directly (no build); when absent it builds from `git`."},"image_url":{"type":["string","null"],"description":"URL to template image/icon"},"is_featured":{"type":"boolean","description":"Whether the template is featured/promoted"},"name":{"type":"string","description":"Display name"},"preset":{"type":"string","description":"Framework/preset to use"},"screenshot_url":{"type":["string","null"],"description":"URL to a wide screenshot/banner preview of the deployed template.\nAbsent for templates that don't have one captured yet."},"services":{"type":"array","items":{"type":"string"},"description":"Required external services"},"slug":{"type":"string","description":"Unique identifier for the template (used in URLs)"},"tags":{"type":"array","items":{"type":"string"},"description":"Tags/categories for filtering"}}},"TestEmailRequest":{"type":"object","description":"Request body for testing an email provider","required":["from"],"properties":{"from":{"type":"string","description":"Sender email address (must be verified with the provider)","example":"test@example.com"},"from_name":{"type":["string","null"],"description":"Sender display name","example":"My App"}}},"TestEmailResponse":{"type":"object","description":"Response for test email endpoint","required":["success","sent_to"],"properties":{"error":{"type":["string","null"],"description":"Error message if the test failed"},"provider_message_id":{"type":["string","null"],"description":"Provider message ID if successful"},"sent_to":{"type":"string","description":"The email address the test was sent to","example":"user@example.com"},"success":{"type":"boolean","description":"Whether the test email was sent successfully"}}},"TestProviderKeyRequest":{"type":"object","required":["provider","api_key"],"properties":{"api_key":{"type":"string","description":"The raw API key to test"},"base_url":{"type":["string","null"],"description":"Optional custom base URL"},"provider":{"type":"string","description":"Provider ID: \"openai\", \"anthropic\", \"xai\", \"gemini\""}}},"TestProviderKeyResponse":{"type":"object","required":["success","provider","latency_ms"],"properties":{"error":{"type":["string","null"],"description":"Error message if the test failed"},"latency_ms":{"type":"integer","format":"int64","description":"Response time in milliseconds","minimum":0},"provider":{"type":"string"},"success":{"type":"boolean"}}},"TestProviderResponse":{"type":"object","required":["success"],"properties":{"message":{"type":["string","null"]},"success":{"type":"boolean"}}},"TimeBucketStats":{"type":"object","description":"Time bucket statistics response","required":["bucket","request_count","avg_response_time_ms","error_count","total_request_bytes","total_response_bytes"],"properties":{"avg_response_time_ms":{"type":"number","format":"double","description":"Average response time in milliseconds"},"bucket":{"type":"string","description":"Bucket timestamp in RFC3339 format","example":"2025-10-23T12:00:00Z"},"error_count":{"type":"integer","format":"int64","description":"Number of errors (status >= 400)"},"request_count":{"type":"integer","format":"int64","description":"Total number of requests in this bucket"},"total_request_bytes":{"type":"integer","format":"int64","description":"Total request bytes"},"total_response_bytes":{"type":"integer","format":"int64","description":"Total response bytes"}}},"TimeBucketStatsResponse":{"type":"object","description":"Response for time bucket stats","required":["stats","start_time","end_time","bucket_interval"],"properties":{"bucket_interval":{"type":"string"},"end_time":{"type":"string"},"start_time":{"type":"string"},"stats":{"type":"array","items":{"$ref":"#/components/schemas/TimeBucketStats"}}}},"TimeseriesBucket":{"type":"object","required":["bucket","request_count","input_tokens","output_tokens","avg_latency_ms"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"bucket":{"type":"string","description":"ISO 8601 timestamp"},"input_tokens":{"type":"integer","format":"int64"},"output_tokens":{"type":"integer","format":"int64"},"request_count":{"type":"integer","format":"int64"}}},"TimeseriesQueryParams":{"type":"object","properties":{"bucket":{"type":["string","null"],"description":"Bucket size: \"hour\", \"day\", \"week\" (defaults to \"day\")"},"conversation_id":{"type":["string","null"],"description":"Filter by conversation ID"},"from":{"type":["string","null"],"description":"ISO 8601 start time (defaults to 24h ago)"},"model":{"type":["string","null"],"description":"Filter by model name"},"provider":{"type":["string","null"],"description":"Filter by provider name"},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"to":{"type":["string","null"],"description":"ISO 8601 end time (defaults to now)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"TlsMode":{"type":"string","enum":["None","Starttls","Tls"]},"TodayStatsResponse":{"type":"object","description":"Today's stats response","required":["total_requests","date"],"properties":{"date":{"type":"string","description":"Date for which stats are returned","example":"2025-10-23"},"total_requests":{"type":"integer","format":"int64","description":"Total requests today"}}},"ToggleDeploymentMetricsRequest":{"type":"object","description":"Request body to toggle OTLP metric ingestion for a deployment.","required":["enabled"],"properties":{"enabled":{"type":"boolean","description":"Whether to enable (`true`) or disable (`false`) metric ingestion."},"path":{"type":["string","null"],"description":"Prometheus scrape path (optional, defaults to `/metrics`)."},"port":{"type":["integer","null"],"format":"int32","description":"Prometheus scrape port (optional).","minimum":0}}},"ToggleServiceMetricsRequest":{"type":"object","description":"Request body to toggle metric collection for an external service.","required":["enabled"],"properties":{"enabled":{"type":"boolean","description":"Whether to enable (`true`) or disable (`false`) metric collection."}}},"TokenRenewalRequest":{"type":"object","required":["refresh_token"],"properties":{"refresh_token":{"type":"string"}}},"ToolCallEvent":{"type":"object","description":"Payload for the `tool_call` SSE event: the model is about to run a tool.\nSerialized as compact single-line JSON onto one `data:` line.","required":["id","name","arguments"],"properties":{"arguments":{"type":"string","description":"The raw JSON-args string the model emitted."},"id":{"type":"string"},"name":{"type":"string"}}},"ToolInfo":{"type":"object","description":"One persisted tool invocation + its result, attached to an assistant message.","required":["id","name","arguments"],"properties":{"arguments":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"result":{"type":["string","null"]}}},"ToolResultEvent":{"type":"object","description":"Payload for the `tool_result` SSE event: a tool finished running. Serialized\nas compact single-line JSON; `content` is JSON-string-escaped so it stays on\none `data:` line even when long.","required":["id","name","content"],"properties":{"content":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"}}},"TopModelsQueryParams":{"type":"object","properties":{"from":{"type":["string","null"],"description":"ISO 8601 start time (defaults to 24h ago)"},"limit":{"type":["integer","null"],"format":"int64","description":"Max results (defaults to 10)","minimum":0},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"to":{"type":["string","null"],"description":"ISO 8601 end time (defaults to now)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"TraceProjectRef":{"type":"object","description":"All projects that contributed spans to a trace, including their sharing flag.\n\nReturned by `CrossProjectTraceService::find_trace_projects`.","required":["project_id","project_name","project_slug","first_seen","sharing"],"properties":{"first_seen":{"type":"string","format":"date-time"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"project_slug":{"type":"string","description":"URL slug used to link into the project's single-project trace view."},"sharing":{"type":"boolean","description":"Whether this project has `cross_project_trace_sharing = true`."}}},"TraceSummariesResponse":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TraceSummary"}},"total":{"type":["integer","null"],"format":"int64","description":"Total traces matching the filters, ignoring pagination. Omitted when\nthe request passed `include_total=false`, in which case the caller\nasked not to pay for the count — treat its absence as \"unknown\", not\nas zero.","minimum":0}}},"TraceSummary":{"type":"object","description":"A trace summary for the list view — one row per trace, aggregated from spans.","required":["trace_id","root_span_name","service_name","kind","status_code","start_time","duration_ms","span_count","error_count"],"properties":{"deployment_environment":{"type":["string","null"],"description":"The deployment environment from the root span's resource attributes (e.g. \"production\")."},"duration_ms":{"type":"number","format":"double"},"error_count":{"type":"integer","format":"int64"},"kind":{"$ref":"#/components/schemas/SpanKind"},"root_span_name":{"type":"string"},"service_name":{"type":"string"},"span_count":{"type":"integer","format":"int64"},"start_time":{"type":"string","format":"date-time"},"status_code":{"$ref":"#/components/schemas/SpanStatusCode"},"trace_id":{"type":"string"}}},"TracesResponse":{"type":"object","required":["data","count"],"properties":{"count":{"type":"integer","minimum":0},"data":{"type":"array","items":{"$ref":"#/components/schemas/SpanRecord"}}}},"TrackedLinkResponse":{"type":"object","description":"Tracked link with click count","required":["link_index","original_url","click_count"],"properties":{"click_count":{"type":"integer","format":"int32"},"link_index":{"type":"integer","format":"int32"},"original_url":{"type":"string"}}},"TrackingEventResponse":{"type":"object","description":"Email tracking event","required":["id","email_id","event_type","created_at"],"properties":{"created_at":{"type":"string"},"email_id":{"type":"string"},"event_type":{"type":"string"},"id":{"type":"integer","format":"int64"},"ip_address":{"type":["string","null"]},"link_index":{"type":["integer","null"],"format":"int32"},"link_url":{"type":["string","null"]},"user_agent":{"type":["string","null"]}}},"TriggerAgentRequest":{"type":"object","properties":{"trigger_source_id":{"type":["integer","null"],"format":"int32"},"trigger_source_type":{"type":["string","null"]},"user_context":{"type":["string","null"],"description":"Optional context from the user (e.g. a research topic, bug description, or instructions)."}}},"TriggerDigestResponse":{"type":"object","required":["success","message"],"properties":{"message":{"type":"string"},"success":{"type":"boolean"}}},"TriggerPipelinePayload":{"type":"object","properties":{"branch":{"type":["string","null"]},"commit":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment ID - if not provided, will use the project's preview environment"},"tag":{"type":["string","null"]}}},"TriggerPipelineResponse":{"type":"object","required":["message","project_id","environment_id"],"properties":{"branch":{"type":["string","null"]},"commit":{"type":["string","null"]},"environment_id":{"type":"integer","format":"int32"},"message":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"tag":{"type":["string","null"]}}},"TriggerScanRequest":{"type":"object","required":["environment_id"],"properties":{"environment_id":{"type":"integer","format":"int32","description":"Environment ID to scan (uses the current deployment for this environment)","example":1}}},"TriggerScanResponse":{"type":"object","required":["scan_id","status","message"],"properties":{"message":{"type":"string"},"scan_id":{"type":"integer","format":"int32"},"status":{"type":"string"}}},"TtlRequest":{"type":"object","description":"Request to get TTL for a key","required":["key"],"properties":{"key":{"type":"string","description":"The key to check TTL for","example":"session:abc"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"TtlResponse":{"type":"object","description":"Response for TTL operation","required":["ttl"],"properties":{"ttl":{"type":"integer","format":"int64","description":"TTL in seconds, -1 if no expiration, -2 if key doesn't exist","example":3600}}},"TxtRecord":{"type":"object","required":["name","value"],"properties":{"name":{"type":"string"},"value":{"type":"string"}}},"UiManifest":{"type":"object","description":"Describes the plugin's embedded UI bundle.","required":["entry_js"],"properties":{"css":{"type":"array","items":{"type":"string"},"description":"CSS files to load"},"entry_js":{"type":"string","description":"JavaScript entry point filename relative to the bundle root"},"routes":{"type":"array","items":{"$ref":"#/components/schemas/UiRoute"},"description":"Client-side routes the plugin handles"}}},"UiRoute":{"type":"object","description":"A client-side route provided by the plugin UI.","required":["path","title"],"properties":{"path":{"type":"string","description":"Route path pattern (e.g., \"/my-plugin\", \"/my-plugin/:id\")"},"title":{"type":"string","description":"Page title for breadcrumbs"}}},"UndrainNodeResponse":{"type":"object","description":"Response after undraining (reactivating) a node.","required":["id","name","status","message"],"properties":{"id":{"type":"integer","format":"int32"},"message":{"type":"string"},"name":{"type":"string"},"status":{"type":"string"}}},"UnifiedTrace":{"type":"object","description":"Merged cross-project trace result (Phase 2 unified waterfall).\n\nSpans are sorted by `start_time ASC`. At most 20 projects and 10,000\nspans total are included; `truncated` / `truncated_projects` signal when\nthe caps were hit.","required":["trace_id","projects","spans","start_time","end_time","total_duration_ms","span_count","error_count","has_redacted_spans","truncated","truncated_projects"],"properties":{"end_time":{"type":"string","format":"date-time"},"error_count":{"type":"integer","minimum":0},"has_redacted_spans":{"type":"boolean","description":"`true` when at least one project has `cross_project_trace_sharing = false`\nand its spans were therefore excluded from the result set."},"projects":{"type":"array","items":{"$ref":"#/components/schemas/ProjectRef"},"description":"Projects that contributed spans to this result set."},"span_count":{"type":"integer","minimum":0},"spans":{"type":"array","items":{"$ref":"#/components/schemas/AnnotatedSpan"},"description":"Annotated, merged span list sorted by `start_time ASC`."},"start_time":{"type":"string","format":"date-time"},"total_duration_ms":{"type":"number","format":"double","description":"Trace wall-clock duration in milliseconds (`end_time – start_time`)."},"trace_id":{"type":"string"},"truncated":{"type":"boolean","description":"`true` when the 20-project or 10,000-span cap was hit."},"truncated_projects":{"type":"array","items":{"type":"integer","format":"int32"},"description":"project_ids excluded due to truncation (most-recent first_seen dropped first)."}}},"UniqueCountsQuery":{"type":"object","description":"Query parameters for unique counts over time frame","required":["start_date","end_date"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment filter"},"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment filter"},"metric":{"type":"string","description":"Metric to count: \"sessions\" (unique sessions), \"visitors\" (unique visitors),\n\"returning_visitors\" (visitors seen before the range), or \"page_views\"\n(total page views) (default: \"sessions\")"},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"UniqueCountsResponse":{"type":"object","required":["count"],"properties":{"count":{"type":"integer","format":"int64"}}},"UnsupportedFeature":{"type":"object","description":"A feature from the source platform that cannot be migrated","required":["feature","reason"],"properties":{"alternative":{"type":["string","null"],"description":"Suggested alternative in Temps (if any)"},"feature":{"type":"string","description":"Feature name (e.g., \"Edge Middleware\", \"Serverless Functions\", \"Cron Jobs\")"},"reason":{"type":"string","description":"Why it can't be migrated"}}},"UpdateAdminGateRequest":{"type":"object","required":["allowed_ips","allowed_hosts","trust_forwarded_for"],"properties":{"allowed_hosts":{"type":"array","items":{"type":"string"}},"allowed_ips":{"type":"array","items":{"type":"string"}},"trust_forwarded_for":{"type":"boolean"}}},"UpdateAiProviderRequest":{"type":"object","description":"Body for `PATCH /settings/ai-providers/{provider_id}` — updates\nprovider-scoped settings (just the default model for now) without\ntouching the credential. Keeping credentials out of this shape means\nthe UI can auto-save model changes on select, without forcing the user\nto re-paste their token or config file.\nName-spaced schema name avoids an OpenAPI collision with\n`temps-notifications::UpdateProviderRequest`, which has different fields.\nBoth are exposed as `utoipa::ToSchema`; without the override the merged\nOpenAPI doc would silently shadow one struct with the other and break\ngenerated CLI/web clients.","properties":{"default_model":{"type":["string","null"],"description":"New default model id. `None` or an empty string clears the stored\nvalue so the CLI falls back to its own default."},"max_turns_analysis":{"type":["integer","null"],"format":"int32","description":"Default max turns for the autofixer analysis phase (1–200). `0`\nclears the stored value (built-in default applies); omitted/`None`\nleaves the current value unchanged — so a PATCH that only updates\n`default_model` doesn't wipe the turn settings."},"max_turns_feedback":{"type":["integer","null"],"format":"int32","description":"Default max turns for autofixer feedback rounds (1–200). `0` clears;\nomitted leaves unchanged."},"max_turns_fix":{"type":["integer","null"],"format":"int32","description":"Default max turns for the autofixer fix phase (1–200). `0` clears;\nomitted leaves unchanged."}}},"UpdateAiProviderResponse":{"type":"object","required":["provider_id"],"properties":{"default_model":{"type":["string","null"]},"max_turns_analysis":{"type":["integer","null"],"format":"int32"},"max_turns_feedback":{"type":["integer","null"],"format":"int32"},"max_turns_fix":{"type":["integer","null"],"format":"int32"},"provider_id":{"type":"string"}}},"UpdateAlertRuleRequest":{"type":"object","properties":{"cooldown_minutes":{"type":["integer","null"],"format":"int32"},"enabled":{"type":["boolean","null"]},"environment_filter":{"type":["integer","null"],"format":"int32"},"error_level_filter":{"type":["string","null"]},"name":{"type":["string","null"]},"notification_priority":{"type":["string","null"]},"trigger_config":{},"trigger_type":{"type":["string","null"]}}},"UpdateApiKeyRequest":{"type":"object","properties":{"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"is_active":{"type":["boolean","null"]},"name":{"type":["string","null"]},"permissions":{"type":["array","null"],"items":{"type":"string"},"example":["projects:read","deployments:read"]}}},"UpdateAutomaticDeployRequest":{"type":"object","required":["automatic_deploy"],"properties":{"automatic_deploy":{"type":"boolean"}}},"UpdateBackupScheduleRequest":{"type":"object","description":"Request body for updating an existing backup schedule via `PATCH /api/backups/schedules/{id}`.\n\nAll fields are optional; only present fields are updated. Absent fields\nleave the corresponding column unchanged.","properties":{"description":{"type":["string","null"],"description":"New human-readable description. Pass an empty string `\"\"` to clear."},"enabled":{"type":["boolean","null"],"description":"Enable or disable the schedule. Skipped when `None`."},"include_control_plane":{"type":["boolean","null"],"description":"Toggle whether the control-plane backup is produced on every run."},"max_runtime_secs":{"type":["integer","null"],"format":"int64","description":"Per-schedule wall-clock timeout override (seconds).\n\n- `None` (field absent) — leave current value unchanged\n- `Some(None)` (field present, JSON `null`) — clear override; fall back to engine default\n- `Some(Some(n))` — set to `n` seconds (must be >= 60)"},"name":{"type":["string","null"],"description":"New schedule name. Skipped when `None`. Must not be empty if provided."},"retention_period":{"type":["integer","null"],"format":"int32","description":"Days to retain backups produced by this schedule. Must be >= 1."},"schedule_expression":{"type":["string","null"],"description":"New cron expression. When changed, `next_run` is recomputed."},"tags":{"type":["array","null"],"items":{"type":"string"},"description":"Replace the full tag list. Skipped when `None`."},"target_all_services":{"type":["boolean","null"],"description":"Toggle between \"back up every database\" (`true`) and \"back up only\nthe explicit list\" (`false`). When set to `true`, the server clears\nthe explicit membership rows for this schedule."}}},"UpdateBlobRequest":{"type":"object","description":"Request to update Blob service configuration","properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use (e.g., \"rustfs/rustfs:1.0.0-alpha.98\")","example":"rustfs/rustfs:1.0.0-alpha.98"}}},"UpdateBlobResponse":{"type":"object","description":"Response after updating Blob service","required":["success","message","status"],"properties":{"message":{"type":"string","description":"Human-readable message","example":"Blob service updated successfully"},"status":{"$ref":"#/components/schemas/BlobStatusResponse","description":"Current status"},"success":{"type":"boolean","description":"Whether the operation succeeded","example":true}}},"UpdateCloudflareProviderRequest":{"type":"object","required":["config"],"properties":{"config":{"$ref":"#/components/schemas/CloudflareConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateConfigBody":{"type":"object","properties":{"config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ProviderConfig","description":"Typed provider configuration. Setting `config` to `null` clears\nthe stored config back to the accept-everything default. The\nconfig's `provider` tag must match the integration's provider."}]}}},"UpdateCustomDomainRequest":{"type":"object","properties":{"branch":{"type":["string","null"]},"domain":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"redirect_to":{"type":["string","null"]},"service_name":{"type":["string","null"],"description":"Docker Compose service name this domain routes to (empty string clears it)"},"status_code":{"type":["integer","null"],"format":"int32"}}},"UpdateDashboardRequest":{"type":"object","properties":{"layout":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DashboardLayout"}]},"name":{"type":["string","null"]}}},"UpdateDeploymentConfigRequest":{"type":"object","properties":{"automaticDeploy":{"type":["boolean","null"]},"cpuLimit":{"type":["integer","null"],"format":"int32"},"cpuRequest":{"type":["integer","null"],"format":"int32"},"crossArchitectureBuilds":{"type":["boolean","null"],"description":"Build one image per architecture the eligible nodes run. Off by\ndefault; environments inherit this and may override it. Cross-builds\nare emulated on the control plane and substantially slower, so they are\nopted into rather than triggered by cluster topology."},"exposedPort":{"type":["integer","null"],"format":"int32"},"memoryLimit":{"type":["integer","null"],"format":"int32"},"memoryRequest":{"type":["integer","null"],"format":"int32"},"performanceMetricsEnabled":{"type":["boolean","null"]},"replicas":{"type":["integer","null"],"format":"int32"},"security":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SecurityConfig"}]},"sessionRecordingEnabled":{"type":["boolean","null"]}}},"UpdateDeploymentTokenRequest":{"type":"object","properties":{"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"is_active":{"type":["boolean","null"]},"name":{"type":["string","null"]},"permissions":{"type":["array","null"],"items":{"type":"string"},"example":["visitors:enrich","emails:send"]}}},"UpdateDnsProviderRequest":{"type":"object","description":"Request to update a DNS provider","properties":{"credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DnsProviderCredentials","description":"New credentials"}]},"description":{"type":["string","null"],"description":"New description"},"is_active":{"type":["boolean","null"],"description":"Active status"},"name":{"type":["string","null"],"description":"New name"}}},"UpdateEmailProviderRequest":{"type":"object","description":"Request body for `PATCH /email-providers/{id}`.\n\nAll fields are optional. Omit any field to leave it unchanged. The\n`provider_type` is immutable — to switch providers, delete the row and\ncreate a new one. For credentials, supplying any credential variant\nre-encrypts the stored blob; omitting them preserves the existing secret\n(so operators can rename without re-typing passwords).","properties":{"is_active":{"type":["boolean","null"]},"name":{"type":["string","null"],"example":"My AWS SES"},"region":{"type":["string","null"],"example":"us-east-1"},"scaleway_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ScalewayCredentialsRequest"}]},"ses_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SesCredentialsRequest"}]},"smtp_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SmtpCredentialsRequest"}]},"sns_topic_arn":{"type":["string","null"],"description":"Rotate or clear the exact SNS topic allowed for this SES provider.\nOmit to preserve it, send `null` to clear it, or send a string to set it."}}},"UpdateEnvironmentSettingsRequest":{"type":"object","properties":{"anti_affinity":{"type":["boolean","null"],"description":"Anti-affinity: spread replicas across different nodes.\nWhen enabled, the scheduler avoids placing two replicas of the same\nenvironment on the same node. Defaults to `true`."},"attack_mode":{"type":["boolean","null"],"description":"Per-environment CAPTCHA attack-mode override (tri-state):\n- absent → leave the current override unchanged\n- JSON `null` → clear the override (inherit the project-level setting)\n- `true`/`false` → override the project setting for this environment"},"automatic_deploy":{"type":["boolean","null"],"description":"Enable/disable automatic deployments for this environment"},"branch":{"type":["string","null"]},"cpu_limit":{"type":["integer","null"],"format":"int32","description":"Maximum (limit) CPU in microcores. Send JSON `null` to clear → \"no limit\".\nAbsent leaves the current value unchanged."},"cpu_request":{"type":["integer","null"],"format":"int32","description":"Minimum (request) CPU in microcores. Send JSON `null` to clear (no request).\nAbsent leaves the current value unchanged."},"cross_architecture_builds":{"type":["boolean","null"],"description":"Build one image per architecture the eligible nodes run (overrides the\nproject-level setting). Off by default: cross-architecture builds are\nemulated on the control plane and substantially slower, so they are\nopted into per environment rather than triggered by cluster topology."},"exposed_port":{"type":["integer","null"],"format":"int32","description":"Port exposed by the container (overrides project-level port for this environment)\n\nPriority order for port resolution:\n1. Image EXPOSE directive (auto-detected from built image)\n2. This environment-level exposed_port (overrides project setting)\n3. Project-level exposed_port (fallback)\n4. Default: 3000","example":8080},"force_https":{"type":["boolean","null"],"description":"Per-environment HTTP→HTTPS redirect override (tri-state):\n- absent → leave the current override unchanged\n- JSON `null` → clear the override (inherit the proxy default, which\n redirects only when the host has an active TLS certificate)\n- `true` → always redirect plain HTTP to HTTPS for this environment,\n even when no local certificate exists (TLS terminated upstream)\n- `false` → never redirect this environment, even when a certificate does\n exist\n\nRequests under `/.well-known/acme-challenge/` are never redirected\nregardless of this setting, so ACME HTTP-01 validation always completes."},"idle_timeout_seconds":{"type":["integer","null"],"format":"int32","description":"Seconds of inactivity before stopping containers (60-86400). Default: 300."},"memory_limit":{"type":["integer","null"],"format":"int32","description":"Maximum (limit) memory in MB. Send JSON `null` to clear → \"no limit\".\nAbsent leaves the current value unchanged."},"memory_request":{"type":["integer","null"],"format":"int32","description":"Minimum (request) memory in MB. Send JSON `null` to clear (no request).\nAbsent leaves the current value unchanged."},"on_demand":{"type":["boolean","null"],"description":"Enable on-demand mode (scale-to-zero). Containers are stopped after\nidle_timeout_seconds of no traffic and started on the next request."},"password":{"type":["string","null"],"description":"Set a password to protect this environment. The proxy will show an HTML\npassword form before allowing access. The password is bcrypt-hashed\nserver-side and never stored in plaintext.\nSend an empty string to remove password protection."},"performance_metrics_enabled":{"type":["boolean","null"],"description":"Enable/disable performance metrics collection"},"protected":{"type":["boolean","null"],"description":"When true, git pushes do NOT auto-deploy to this environment.\nDeployments must be promoted from another environment."},"replicas":{"type":["integer","null"],"format":"int32"},"security":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SecurityConfig","description":"Security configuration for this environment (overrides project-level settings)"}]},"session_recording_enabled":{"type":["boolean","null"],"description":"Enable/disable session recording"},"target_labels":{"description":"Label selector for node-based scheduling (overrides project-level setting).\nSame key with array value -> OR, different keys -> AND.\nExample: `{\"region\": [\"us\", \"asia\"], \"gpu\": \"true\"}`"},"target_nodes":{"type":["array","null"],"items":{"type":"integer","format":"int32"},"description":"Optional list of node IDs to deploy to (overrides project-level setting)"},"wake_timeout_seconds":{"type":["integer","null"],"format":"int32","description":"Max seconds to wait for containers to start on wake (5-120). Default: 30."}}},"UpdateEnvironmentSubdomainRequest":{"type":"object","description":"Request to rename an environment's auto-managed subdomain.\n\nThe subdomain is the host label inserted in front of the platform's\npreview domain (e.g. `myapp` in `myapp.preview.temps.sh`). Renaming\nreplaces the previous subdomain entirely — the old hostname stops\nresolving immediately after this request succeeds.","required":["subdomain"],"properties":{"subdomain":{"type":"string","description":"New subdomain label. Must be a DNS-safe slug (lowercase letters,\ndigits, and hyphens, 1-63 characters). The value is slugified\nserver-side, so casing and disallowed characters are normalized.","example":"myapp"}}},"UpdateEnvironmentVariableRequest":{"type":"object","required":["key","environment_ids"],"properties":{"environment_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"include_in_preview":{"type":"boolean"},"is_secret":{"type":["boolean","null"],"description":"Optional secret-flag transition.\n- `Some(true)` promotes a regular var to a secret.\n- `Some(false)` is rejected if the row is already secret (one-way flag).\n- `None` (omitted) leaves the flag unchanged."},"key":{"type":"string"},"value":{"type":["string","null"],"description":"New plaintext value. `None` (omitted) keeps the existing ciphertext,\nwhich is the only way to edit a secret env var without re-typing its\nvalue (e.g. changing which environments it applies to)."}}},"UpdateErrorGroupRequest":{"type":"object","required":["status"],"properties":{"assigned_to":{"type":["string","null"]},"status":{"type":"string"}}},"UpdateExternalServiceRequest":{"type":"object","required":["parameters"],"properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use for the service (e.g., \"gotempsh/postgres-walg:18-bookworm\", \"timescale/timescaledb-ha:pg18\")\nWhen provided, the service will be recreated with the new image while preserving data"},"parameters":{"type":"object","additionalProperties":{},"propertyNames":{"type":"string"}}}},"UpdateFlagRequest":{"type":"object","properties":{"client_visible":{"type":["boolean","null"]},"default_value":{"description":"Must match the flag's existing `value_type`."},"description":{"type":["string","null"],"description":"Tri-state: absent leaves it, `null` clears it, a string sets it."}}},"UpdateGitSettingsRequest":{"type":"object","required":["main_branch","repo_owner","repo_name","directory"],"properties":{"directory":{"type":"string"},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"git_url":{"type":["string","null"],"description":"Git clone URL for public repositories"},"is_public_repo":{"type":["boolean","null"],"description":"Whether this is a public repository (no git provider connection needed)"},"main_branch":{"type":"string"},"preset":{"type":["string","null"]},"preset_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PresetConfigSchema","description":"Preset-specific configuration (e.g., Dockerfile path for Docker preset)\n\nExample for Dockerfile preset:\n```json\n{\n \"dockerfilePath\": \"docker/Dockerfile\",\n \"buildContext\": \"./api\"\n}\n```"}]},"repo_name":{"type":"string"},"repo_owner":{"type":"string"}}},"UpdateIncidentStatusRequest":{"type":"object","required":["status","message"],"properties":{"message":{"type":"string"},"status":{"type":"string"}}},"UpdateIpAccessControlRequest":{"type":"object","description":"Request to update an IP access control rule","properties":{"action":{"type":["string","null"],"description":"Optional new action"},"ip_address":{"type":["string","null"],"description":"Optional new IP address"},"reason":{"type":["string","null"],"description":"Optional new reason"}}},"UpdateKvRequest":{"type":"object","description":"Request to update KV service configuration","properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use (e.g., \"gotempsh/redis-walg:8-bookworm\")","example":"gotempsh/redis-walg:8-bookworm"}}},"UpdateKvResponse":{"type":"object","description":"Response after updating KV service","required":["success","message","status"],"properties":{"message":{"type":"string","description":"Status message","example":"KV service updated successfully"},"status":{"$ref":"#/components/schemas/KvStatusResponse","description":"Current service status"},"success":{"type":"boolean","description":"Whether the operation succeeded"}}},"UpdateManagedDomainApiRequest":{"type":"object","description":"Request to update a managed domain's settings.","properties":{"auto_manage":{"type":["boolean","null"],"description":"Toggle automatic DNS management for this domain."},"generated_hostname_mode":{"type":["string","null"],"description":"`\"standard\"` or `\"flat\"`. Persisted as-is; switching to `\"flat\"` does not\nrecompute existing hostnames — use the apply endpoint for that."},"sync_generated_records":{"type":["boolean","null"],"description":"Toggle DNS record sync for this domain."}}},"UpdateMcpRequest":{"type":"object","required":["config"],"properties":{"config":{"type":"object"},"description":{"type":["string","null"]},"name":{"type":["string","null"]}}},"UpdateMemberRoleRequest":{"type":"object","description":"The new fixed role for an existing membership.","required":["role"],"properties":{"role":{"$ref":"#/components/schemas/TeamRole"}}},"UpdateMetricAlertRequest":{"type":"object","properties":{"aggregation":{"type":["string","null"]},"detection_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DetectionConfig","description":"Replaces the detector wholesale when present (absent = leave unchanged)."}]},"dynamic_alerts":{"type":["boolean","null"],"description":"Toggles per-series (\"dynamic\") alerting (absent = leave unchanged)."},"enabled":{"type":["boolean","null"]},"for_duration_secs":{"type":["integer","null"],"format":"int32"},"group_by":{"type":["array","null"],"items":{"type":"string"},"description":"Replaces the group_by keys wholesale when present (absent = leave unchanged)."},"grouped_notification_threshold":{"type":["integer","null"],"format":"int32","description":"Updates the notification-grouping threshold (absent = leave unchanged)."},"label_filters":{"type":["array","null"],"items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"Replaces the label filters wholesale when present (absent = leave unchanged)."},"max_series":{"type":["integer","null"],"format":"int32","description":"Updates the dynamic-alerting cardinality cap (absent = leave unchanged)."},"metric_name":{"type":["string","null"]},"name":{"type":["string","null"]},"severity":{"type":["string","null"]},"window_secs":{"type":["integer","null"],"format":"int32"}}},"UpdateNotificationEmailProviderRequest":{"type":"object","required":["config"],"properties":{"config":{"$ref":"#/components/schemas/EmailConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateOidcProviderRequest":{"type":"object","properties":{"client_id":{"type":["string","null"]},"client_secret":{"type":["string","null"]},"default_role":{"type":["string","null"]},"enabled":{"type":["boolean","null"]},"group_claim":{"type":["string","null"]},"issuer_url":{"type":["string","null"]},"jit_provisioning":{"type":["boolean","null"]},"name":{"type":["string","null"]},"role_claim":{"type":["string","null"]},"scopes":{"type":["string","null"]},"template":{"type":["string","null"]},"trust_idp_email":{"type":["boolean","null"]}}},"UpdatePreferencesRequest":{"type":"object","required":["preferences"],"properties":{"preferences":{"$ref":"#/components/schemas/NotificationPreferencesResponse"}}},"UpdateProjectSecretRequest":{"type":"object","description":"Request to update a project secret. The `value` field is optional — omit it\nto rotate only the environment scoping / preview flag without touching the\nciphertext.","properties":{"environment_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"include_in_preview":{"type":"boolean"},"value":{"type":["string","null"],"description":"New plaintext value, <= 1 MiB. Omit to keep the existing value."}}},"UpdateProjectSettingsRequest":{"type":"object","properties":{"ai_alert_summaries_enabled":{"type":["boolean","null"],"description":"Opt in to AI summarization of metric alert notifications (ADR-021)."},"ai_debug_chat_enabled":{"type":["boolean","null"],"description":"Opt in to AI debugging chat, e.g. on deployment failures (ADR-023)."},"ai_write_actions_enabled":{"type":["boolean","null"],"description":"Opt in to AI propose-then-confirm write capability."},"attack_mode":{"type":["boolean","null"],"description":"Enable/disable attack mode (CAPTCHA protection) for all project environments"},"cross_project_trace_sharing":{"type":["boolean","null"],"description":"ADR-027 Phase 3 opt-out: set to false to suppress this project's traces\nfrom appearing in cross-project discovery results. Default true (consistent\nwith the OSS global-observability model). Omit to leave unchanged."},"directory":{"type":["string","null"]},"enable_preview_environments":{"type":["boolean","null"],"description":"Enable automatic preview environment creation for each branch"},"error_source_context_enabled":{"type":["boolean","null"],"description":"Opt in to native error-tracking source context (source-file upload +\nsource code shown in stack traces)."},"error_source_root":{"type":["string","null"],"description":"Set the auto-capture source root (relative to the checkout). Send an\nempty string to clear it back to the build-context default. Omit to\nleave unchanged."},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"main_branch":{"type":["string","null"]},"preset":{"type":["string","null"]},"preset_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PresetConfigSchema","description":"Preset-specific configuration (e.g., Dockerfile path for Docker preset)\n\nExample for Dockerfile preset:\n```json\n{\n \"dockerfilePath\": \"docker/Dockerfile\",\n \"buildContext\": \"./api\"\n}\n```"}]},"preview_envs_idle_timeout_seconds":{"type":["integer","null"],"format":"int32","description":"Idle timeout (seconds, 60..=86400) for on-demand preview environments."},"preview_envs_on_demand":{"type":["boolean","null"],"description":"When true, newly-created preview environments default to on-demand mode."},"preview_envs_wake_timeout_seconds":{"type":["integer","null"],"format":"int32","description":"Wake timeout (seconds, 5..=120) for on-demand preview environments."},"repo_name":{"type":["string","null"]},"repo_owner":{"type":["string","null"]},"slug":{"type":["string","null"]}}},"UpdateProviderCredentialsRequest":{"type":"object","description":"Partial-update payload for provider credentials. Every field is optional;\nonly the fields the user re-enters are applied. The server validates that\nthe fields supplied make sense for the provider's current auth_method\n(e.g. `app_id` + `private_key` only apply to GitHub Apps).","properties":{"app_id":{"type":["string","null"],"description":"Application ID (GitHub App integer as string; GitLab App string)."},"app_secret":{"type":["string","null"],"description":"GitLab App secret (not used by GitHub App — use `client_secret`)."},"client_id":{"type":["string","null"],"description":"OAuth client ID (GitLab OAuth, GitHub App)."},"client_secret":{"type":["string","null"],"description":"OAuth client secret (GitLab OAuth, GitHub App)."},"private_key":{"type":["string","null"],"description":"GitHub App private key (PEM)."},"redirect_uri":{"type":["string","null"],"description":"OAuth redirect URI (GitLab OAuth / GitLab App)."},"token":{"type":["string","null"],"description":"PAT for PAT-type providers."},"webhook_secret":{"type":["string","null"],"description":"GitHub App webhook secret."}}},"UpdateProviderKeyRequest":{"type":"object","properties":{"api_key":{"type":["string","null"]},"base_url":{"type":["string","null"],"description":"Double-Option: absent = leave unchanged, present-null = clear (revert to\nthe provider's default endpoint), present-value = set."},"default_model":{"type":["string","null"],"description":"Double-Option: absent = leave unchanged, present-null = clear the pinned\nmodel (revert to the per-provider default), present-value = set."},"display_name":{"type":["string","null"]},"is_active":{"type":["boolean","null"]}}},"UpdateProviderRequest":{"type":"object","properties":{"config":{},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateRouteRequest":{"type":"object","required":["host","port","enabled"],"properties":{"enabled":{"type":"boolean"},"host":{"type":"string"},"port":{"type":"integer","format":"int32"},"route_type":{"type":["string","null"],"description":"Route type: \"http\" (default) matches on HTTP Host header,\n\"tls\" matches on TLS SNI hostname for TCP passthrough"}}},"UpdateS3SourceRequest":{"type":"object","properties":{"access_key_id":{"type":["string","null"],"description":"Optional new access key ID","example":"AKIAXXXXXXXXXXXXXXXX"},"bucket_name":{"type":["string","null"],"description":"Optional new bucket name"},"bucket_path":{"type":["string","null"],"description":"Optional new bucket path"},"endpoint":{"type":["string","null"],"description":"Optional new endpoint URL for S3-compatible services","example":"http://minio.example.com:9000"},"force_path_style":{"type":["boolean","null"],"description":"Optional new path-style addressing setting","example":true},"name":{"type":["string","null"],"description":"Optional new name for the source"},"region":{"type":["string","null"],"description":"Optional new region"},"secret_key":{"type":["string","null"],"description":"Optional new secret key"}}},"UpdateSecretBody":{"type":"object","required":["signing_secret"],"properties":{"signing_secret":{"type":"string","description":"New signing secret from the provider's dashboard. Encrypted at\nrest; never returned in any API response."}}},"UpdateSelfRequest":{"type":"object","properties":{"email":{"type":["string","null"],"example":"john.doe@example.com"},"name":{"type":["string","null"],"example":"John Doe"}}},"UpdateSessionDurationRequest":{"type":"object","required":["duration"],"properties":{"duration":{"type":"integer","format":"int32"}}},"UpdateSessionDurationResponse":{"type":"object","required":["message"],"properties":{"message":{"type":"string"}}},"UpdateSkillRequest":{"type":"object","properties":{"content":{"type":["string","null"]},"description":{"type":["string","null"]},"name":{"type":["string","null"]}}},"UpdateSlackProviderRequest":{"type":"object","required":["config"],"properties":{"config":{"$ref":"#/components/schemas/SlackConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateSpeedMetricsPayload":{"type":"object","description":"Update speed metrics payload for late-loading metrics","properties":{"cls":{"type":["number","null"],"format":"float","description":"Cumulative Layout Shift (score)"},"inp":{"type":["number","null"],"format":"float","description":"Interaction to Next Paint (milliseconds)"}}},"UpdateStatusResponse":{"type":"object","description":"Result of the background release-update check, driving the web console's\nupgrade banner. All optional fields are set together iff\n`update_available` is true.","required":["update_available","docs_url"],"properties":{"channel":{"type":["string","null"],"description":"Channel the install tracks: `stable` or `beta`."},"checked_at":{"type":["string","null"],"description":"When the check that found the update ran (ISO 8601, UTC)."},"current_version":{"type":["string","null"],"description":"Version tag of the running binary, e.g. `v0.1.0-beta.45`."},"docs_url":{"type":"string","description":"Docs page with upgrade instructions. Always present so the UI links\nthe same page regardless of update state."},"latest_version":{"type":["string","null"],"description":"Newest published tag on this install's channel."},"release_url":{"type":["string","null"],"description":"Release-notes page (GitHub release) for the newer version."},"update_available":{"type":"boolean","description":"True when a newer release than the running binary has been published\non this install's channel."}}},"UpdateTeamRequest":{"type":"object","properties":{"description":{"type":["string","null"]},"name":{"type":["string","null"]}}},"UpdateTokenRequest":{"type":"object","required":["access_token"],"properties":{"access_token":{"type":"string"},"refresh_token":{"type":["string","null"]}}},"UpdateTokenResponse":{"type":"object","required":["connection_id","message","is_active"],"properties":{"connection_id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"message":{"type":"string"}}},"UpdateUserRequest":{"type":"object","properties":{"email":{"type":["string","null"],"example":"john.doe@example.com"},"name":{"type":["string","null"],"example":"John Doe"}}},"UpdateWebhookProviderRequest":{"type":"object","required":["config"],"properties":{"config":{"$ref":"#/components/schemas/WebhookConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateWebhookRequestBody":{"type":"object","properties":{"enabled":{"type":["boolean","null"],"description":"Whether the webhook is enabled"},"events":{"type":["array","null"],"items":{"type":"string"},"description":"Event types to subscribe to"},"secret":{"type":["string","null"],"description":"Secret for HMAC signature verification"},"url":{"type":["string","null"],"description":"Target URL for webhook delivery"}}},"UpgradeExternalServiceRequest":{"type":"object","required":["docker_image"],"properties":{"docker_image":{"type":"string","description":"Docker image to upgrade to (e.g., \"gotempsh/postgres-walg:18-bookworm\")\nThis will trigger pg_upgrade for PostgreSQL or equivalent upgrade procedures for other services","example":"gotempsh/postgres-walg:18-bookworm"}}},"UpgradeRequest":{"type":"object","required":["image"],"properties":{"image":{"type":"string","description":"Image reference to pull and run (e.g.\n`ghcr.io/gotempsh/temps-preview-gateway:latest`). Empty resets to default."}}},"UpsertAgentRequest":{"type":"object","properties":{"ai_model":{"type":["string","null"],"description":"Preferred model identifier for the CLI. `Some(\"\")` clears the stored value."},"ai_provider":{"type":["string","null"]},"ai_provider_key_id":{"type":["integer","null"],"format":"int32"},"api_key":{"type":["string","null"],"description":"Plain-text API key — will be encrypted before storage"},"branch_prefix":{"type":["string","null"]},"config_repo_branch":{"type":["string","null"],"description":"Branch of the config repo to use (default: \"main\")."},"config_repo_url":{"type":["string","null"],"description":"Private config repo containing .claude/ directory (skills, MCP, plugins)."},"cooldown_minutes":{"type":["integer","null"],"format":"int32"},"daily_budget_cents":{"type":["integer","null"],"format":"int32"},"deliverable":{"type":["string","null"]},"description":{"type":["string","null"]},"enabled":{"type":["boolean","null"]},"max_turns":{"type":["integer","null"],"format":"int32"},"mcp_servers_config":{"description":"MCP servers config (Claude Code settings.json mcpServers format).\nCredential-bearing legacy inline objects are write-only: normal reads\nmask them, and updates must omit this field to preserve existing values."},"name":{"type":["string","null"]},"prompt":{"type":["string","null"]},"sandbox_enabled":{"type":["boolean","null"]},"skills_config":{"description":"Skills config as JSON array."},"slug":{"type":["string","null"]},"timeout_seconds":{"type":["integer","null"],"format":"int32"},"tools_config":{"description":"Tools config as JSON array. Custom-tool webhook URLs and headers are\nwrite-only; omit this field on update to preserve them."},"trigger_config":{"description":"Trigger configuration JSON: { \"error\": { \"new_issue\": true, \"regression\": true }, \"manual\": true }"}}},"UpsertSecretRequest":{"type":"object","required":["name","value"],"properties":{"description":{"type":["string","null"]},"mount_path":{"type":["string","null"],"description":"Required for \"file\" type secrets — absolute path inside the sandbox"},"name":{"type":"string"},"secret_type":{"type":"string","description":"\"env\" (environment variable) or \"file\" (written to mount_path)"},"value":{"type":"string"}}},"UptimeDataPoint":{"type":"object","required":["timestamp","status"],"properties":{"error_message":{"type":["string","null"]},"response_time_ms":{"type":["integer","null"],"format":"int32"},"status":{"type":"string"},"timestamp":{"type":"string","format":"date-time"}}},"UptimeHistoryResponse":{"type":"object","required":["monitor_id","uptime_data"],"properties":{"monitor_id":{"type":"integer","format":"int32"},"uptime_data":{"type":"array","items":{"$ref":"#/components/schemas/UptimeDataPoint"}}}},"UsageFilter":{"type":"object","description":"Filters for querying AI usage data.\n\nCost bounds are expressed in microcents (the unit stored in\n`estimated_cost_microcents`). At most one of `gte`/`gt` and one of\n`lte`/`lt` is meaningful per query; if both are set the stricter wins\nnaturally because they are ANDead together.","properties":{"conversation_id":{"type":["string","null"]},"cost_gt":{"type":["integer","null"],"format":"int64","description":"Cost strictly greater-than, in microcents."},"cost_gte":{"type":["integer","null"],"format":"int64","description":"Cost greater-than-or-equal, in microcents."},"cost_lt":{"type":["integer","null"],"format":"int64","description":"Cost strictly less-than, in microcents."},"cost_lte":{"type":["integer","null"],"format":"int64","description":"Cost less-than-or-equal, in microcents."},"model":{"type":["string","null"]},"provider":{"type":["string","null"]},"status":{"type":["integer","null"],"format":"int32","description":"Filter by HTTP status code (exact match)."},"tags":{"type":["string","null"],"description":"Comma-separated tags to filter by (AND logic)."},"tokens_gt":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) strictly greater-than."},"tokens_gte":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) greater-than-or-equal."},"tokens_lt":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) strictly less-than."},"tokens_lte":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) less-than-or-equal."},"user_id":{"type":["integer","null"],"format":"int32"}}},"UsageInfo":{"type":"object","required":["prompt_tokens","completion_tokens","total_tokens"],"properties":{"completion_tokens":{"type":"integer","format":"int64"},"prompt_tokens":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"UsageLogEntry":{"type":"object","required":["id","timestamp","provider","model","input_tokens","output_tokens","latency_ms","estimated_cost_microcents","status","is_streaming","is_byok","tags"],"properties":{"conversation_id":{"type":["string","null"]},"estimated_cost_microcents":{"type":"integer","format":"int64"},"id":{"type":"integer","format":"int64"},"input_tokens":{"type":"integer","format":"int64"},"is_byok":{"type":"boolean"},"is_streaming":{"type":"boolean"},"latency_ms":{"type":"integer","format":"int32"},"model":{"type":"string"},"output_tokens":{"type":"integer","format":"int64"},"provider":{"type":"string"},"request_id":{"type":["string","null"]},"status":{"type":"integer","format":"int32"},"tags":{"type":"array","items":{"type":"string"}},"timestamp":{"type":"string"},"trace_id":{"type":["string","null"]}}},"UsageLogPage":{"type":"object","description":"A page of recent usage log entries plus the total count for pagination.","required":["entries","total"],"properties":{"entries":{"type":"array","items":{"$ref":"#/components/schemas/UsageLogEntry"},"description":"The usage log entries for the requested page."},"total":{"type":"integer","format":"int64","description":"Total number of entries matching the filter (across all pages)."}}},"UsageQueryParams":{"type":"object","properties":{"conversation_id":{"type":["string","null"],"description":"Filter by conversation ID"},"from":{"type":["string","null"],"description":"ISO 8601 start time (defaults to 24h ago)"},"model":{"type":["string","null"],"description":"Filter by model name"},"provider":{"type":["string","null"],"description":"Filter by provider name"},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"to":{"type":["string","null"],"description":"ISO 8601 end time (defaults to now)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"UsageSource":{"type":"string","description":"How the \"actual usage\" numbers were obtained","enum":["metrics-api","requests-only","unavailable"]},"UsageSummary":{"type":"object","required":["total_requests","total_input_tokens","total_output_tokens","total_tokens","avg_latency_ms","total_cost_microcents","error_count","streaming_count","byok_count"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"byok_count":{"type":"integer","format":"int64"},"error_count":{"type":"integer","format":"int64"},"streaming_count":{"type":"integer","format":"int64"},"total_cost_microcents":{"type":"integer","format":"int64"},"total_input_tokens":{"type":"integer","format":"int64"},"total_output_tokens":{"type":"integer","format":"int64"},"total_requests":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"UserResponse":{"type":"object","required":["id","username","name","avatar_url","mfa_enabled","role"],"properties":{"avatar_url":{"type":"string"},"email":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"mfa_enabled":{"type":"boolean"},"name":{"type":"string"},"role":{"type":"string","description":"User's role (e.g., \"admin\", \"user\", \"demo\")"},"username":{"type":"string"}}},"ValidateEmailRequest":{"type":"object","description":"Request body for validating an email address","required":["email"],"properties":{"email":{"type":"string","description":"Email address to validate","example":"someone@gmail.com"}},"additionalProperties":false},"ValidateEmailResponse":{"type":"object","description":"Complete email validation response","required":["email","is_reachable","syntax","mx","misc","smtp"],"properties":{"email":{"type":"string","description":"The email address that was validated","example":"someone@gmail.com"},"is_reachable":{"$ref":"#/components/schemas/ReachabilityStatus","description":"Overall reachability status: safe, risky, invalid, or unknown"},"misc":{"$ref":"#/components/schemas/MiscResult","description":"Miscellaneous validation result"},"mx":{"$ref":"#/components/schemas/MxResult","description":"MX record validation result"},"smtp":{"$ref":"#/components/schemas/SmtpResult","description":"SMTP validation result"},"syntax":{"$ref":"#/components/schemas/SyntaxResult","description":"Syntax validation result"}}},"ValidationLevel":{"type":"string","description":"Validation severity level","enum":["info","warning","error","critical"]},"ValidationReport":{"type":"object","description":"Complete validation report","required":["results","overall_status","summary"],"properties":{"overall_status":{"$ref":"#/components/schemas/ValidationStatus","description":"Overall status"},"results":{"type":"array","items":{"$ref":"#/components/schemas/ValidationResult"},"description":"All validation results"},"summary":{"$ref":"#/components/schemas/ValidationSummary","description":"Summary statistics"}}},"ValidationResponse":{"type":"object","required":["connection_id","is_valid","message"],"properties":{"connection_id":{"type":"integer","format":"int32"},"is_valid":{"type":"boolean"},"message":{"type":"string"}}},"ValidationResult":{"type":"object","description":"Result of a validation check","required":["rule_id","rule_name","level","passed","message","affected_resources"],"properties":{"affected_resources":{"type":"array","items":{"type":"string"},"description":"Affected resources/fields"},"level":{"$ref":"#/components/schemas/ValidationLevel","description":"Validation level"},"message":{"type":"string","description":"Message describing the result"},"passed":{"type":"boolean","description":"Whether the validation passed"},"remediation":{"type":["string","null"],"description":"Suggested remediation (if failed)"},"rule_id":{"type":"string","description":"Rule that was checked"},"rule_name":{"type":"string","description":"Human-readable rule name"}}},"ValidationStatus":{"type":"string","description":"Overall validation status","enum":["passed","passed-with-warnings","failed-with-warnings","failed"]},"ValidationSummary":{"type":"object","description":"Validation summary statistics","required":["total_count","passed_count","failed_count","info_count","warning_count","error_count","critical_count"],"properties":{"critical_count":{"type":"integer","description":"Critical-level results","minimum":0},"error_count":{"type":"integer","description":"Error-level results","minimum":0},"failed_count":{"type":"integer","description":"Validations that failed","minimum":0},"info_count":{"type":"integer","description":"Info-level results","minimum":0},"passed_count":{"type":"integer","description":"Validations that passed","minimum":0},"total_count":{"type":"integer","description":"Total validations run","minimum":0},"warning_count":{"type":"integer","description":"Warning-level results","minimum":0}}},"VerifyMfaRequest":{"type":"object","required":["code"],"properties":{"code":{"type":"string"}}},"VerifyStepUpRequest":{"type":"object","required":["code"],"properties":{"code":{"type":"string","description":"Current TOTP value or an unused recovery code."}}},"ViewItem":{"type":"object","required":["label","value"],"properties":{"label":{"type":"string","format":"date-time"},"value":{"type":"integer","format":"int64"}}},"ViewsOverTime":{"type":"object","required":["items","metric","present_index"],"properties":{"comparison_labels":{"type":["array","null"],"items":{"type":"string"}},"comparison_plot":{"type":["array","null"],"items":{"type":"integer","format":"int64"}},"full_intervals":{"type":["array","null"],"items":{"type":"string"}},"items":{"type":"array","items":{"$ref":"#/components/schemas/ViewItem"}},"metric":{"type":"string"},"present_index":{"type":"integer","minimum":0}}},"ViewsOverTimeQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"VisitorDetails":{"type":"object","required":["id","visitor_id","project_id","environment_id","first_seen","last_seen","is_crawler"],"properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"crawler_name":{"type":["string","null"]},"custom_data":{},"environment_id":{"type":"integer","format":"int32"},"first_channel":{"type":["string","null"],"description":"Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")"},"first_referrer":{"type":["string","null"],"description":"Full referrer URL from the visitor's first session"},"first_referrer_hostname":{"type":["string","null"],"description":"Hostname extracted from first_referrer"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":["string","null"]},"ip_address_id":{"type":["integer","null"],"format":"int32"},"is_crawler":{"type":"boolean"},"is_eu":{"type":["boolean","null"]},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"latitude":{"type":["number","null"],"format":"double"},"longitude":{"type":["number","null"],"format":"double"},"project_id":{"type":"integer","format":"int32"},"region":{"type":["string","null"]},"timezone":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":"string"}}},"VisitorFacetValue":{"type":"object","description":"A single facet value with its visitor count. Used to populate filter\ndropdowns on the visitors page (e.g. \"Germany — 1,234 visitors\").","required":["value","count"],"properties":{"code":{"type":["string","null"],"description":"Optional secondary code for the value. Currently only populated for\nthe `country` facet, where it carries the 2-letter ISO country code\nso the UI can render a flag without re-mapping."},"count":{"type":"integer","format":"int64","description":"Distinct visitor count matching this value in the current segment."},"value":{"type":"string","description":"The dimension value (e.g. \"United States\", \"Chrome\", \"google.com\").\n`None` is encoded as the literal string \"Direct\" for referrer and as\nthe empty string for the rest."}}},"VisitorFacets":{"type":"object","description":"All filter dropdown contents in one response. Each list is the top N\nvalues for that dimension within the current date range and segment\n(excluding the dimension being queried so the dropdown still shows\nalternatives when a value is already selected).","required":["country","region","city","channel","referrer"],"properties":{"channel":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}},"city":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}},"country":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}},"referrer":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}},"region":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}}}},"VisitorFacetsQuery":{"allOf":[{"$ref":"#/components/schemas/VisitorSegmentFilters"},{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"has_activity_only":{"type":["boolean","null"]},"include_crawlers":{"type":["boolean","null"]},"per_facet_limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of values returned per dimension (default: 50, max: 200)."},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}}],"description":"Query parameters for the visitor-facets endpoint. Mirrors the shape of\n`VisitorsListQuery` so the same segment filters apply — facet counts are\nalways computed against the *currently filtered* visitor pool, minus the\ndimension being aggregated."},"VisitorInfo":{"type":"object","required":["id","visitor_id","project_id","environment_id","first_seen","last_seen","is_crawler"],"properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"crawler_name":{"type":["string","null"]},"current_page":{"type":["string","null"],"description":"Most recent page path visited by this visitor"},"custom_data":{},"environment_id":{"type":"integer","format":"int32"},"first_channel":{"type":["string","null"],"description":"Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")"},"first_referrer":{"type":["string","null"],"description":"Full referrer URL from the visitor's first session"},"first_referrer_hostname":{"type":["string","null"],"description":"Hostname extracted from first_referrer"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":["string","null"]},"ip_address_id":{"type":["integer","null"],"format":"int32"},"is_crawler":{"type":"boolean"},"is_eu":{"type":["boolean","null"]},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"latitude":{"type":["number","null"],"format":"double"},"longitude":{"type":["number","null"],"format":"double"},"project_id":{"type":"integer","format":"int32"},"region":{"type":["string","null"]},"timezone":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":"string"}}},"VisitorJourneyQuery":{"type":"object","required":["project_id"],"properties":{"limit_sessions":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"VisitorJourneyResponse":{"type":"object","description":"Complete visitor journey response","required":["visitor_id","total_sessions","total_events","sessions"],"properties":{"sessions":{"type":"array","items":{"$ref":"#/components/schemas/JourneySession"},"description":"Sessions with their events, ordered newest first"},"total_events":{"type":"integer","format":"int64","description":"Total number of events across all sessions"},"total_sessions":{"type":"integer","format":"int64","description":"Total number of sessions"},"visitor_id":{"type":"integer","format":"int32","description":"Visitor internal ID"}}},"VisitorLocationsQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"granularity":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/LocationGranularity"}]},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"VisitorRecord":{"type":"object","required":["id","visitor_id","project_id","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"custom_data":{},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"visitor_id":{"type":"string"}}},"VisitorSegmentFilters":{"type":"object","description":"Optional segment filters for [`VisitorsListQuery`]. Each filter narrows the\nresult set to visitors who match the given dimension value within the date\nrange. All filters resolve against `visitor` / `ip_geolocations` — by\ndesign we never touch the events hypertable here so filtering stays fast\nregardless of event volume.","properties":{"filter_channel":{"type":["string","null"],"description":"First-touch marketing channel (matches `visitor.first_channel`)"},"filter_city":{"type":["string","null"],"description":"Geolocation city (matches `ip_geolocations.city`)"},"filter_country":{"type":["string","null"],"description":"Geolocation country (matches `ip_geolocations.country`)"},"filter_referrer":{"type":["string","null"],"description":"First-touch referrer hostname (matches `visitor.first_referrer_hostname`)"},"filter_region":{"type":["string","null"],"description":"Geolocation region (matches `ip_geolocations.region`)"}}},"VisitorSessionsQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"VisitorSessionsResponse":{"type":"object","required":["visitor_id","sessions","total_sessions"],"properties":{"sessions":{"type":"array","items":{"$ref":"#/components/schemas/SessionSummary"}},"total_sessions":{"type":"integer","format":"int64"},"visitor_id":{"type":"string"}}},"VisitorStats":{"type":"object","required":["visitor_id","first_seen","last_seen","total_sessions","total_page_views","total_events","average_session_duration","bounce_rate","engagement_rate","top_pages","top_referrers","devices_used","locations"],"properties":{"average_session_duration":{"type":"number","format":"double"},"bounce_rate":{"type":"number","format":"double"},"devices_used":{"type":"array","items":{"type":"string"}},"engagement_rate":{"type":"number","format":"double"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"locations":{"type":"array","items":{"$ref":"#/components/schemas/LocationInfo"}},"top_pages":{"type":"array","items":{"$ref":"#/components/schemas/PageVisit"}},"top_referrers":{"type":"array","items":{"type":"string"}},"total_events":{"type":"integer","format":"int64"},"total_page_views":{"type":"integer","format":"int64"},"total_sessions":{"type":"integer","format":"int64"},"visitor_id":{"type":"integer","format":"int32"}}},"VisitorWithGeolocation":{"type":"object","required":["id","visitor_id","project_id","environment_id","first_seen","last_seen","is_crawler"],"properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"crawler_name":{"type":["string","null"]},"custom_data":{},"environment_id":{"type":"integer","format":"int32"},"first_channel":{"type":["string","null"],"description":"Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")"},"first_referrer":{"type":["string","null"],"description":"Full referrer URL from the visitor's first session"},"first_referrer_hostname":{"type":["string","null"],"description":"Hostname extracted from first_referrer"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":["string","null"]},"is_crawler":{"type":"boolean"},"is_eu":{"type":["boolean","null"]},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"latitude":{"type":["number","null"],"format":"double"},"longitude":{"type":["number","null"],"format":"double"},"project_id":{"type":"integer","format":"int32"},"region":{"type":["string","null"]},"timezone":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":"string"}}},"VisitorsListQuery":{"allOf":[{"$ref":"#/components/schemas/VisitorSegmentFilters"},{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"has_activity_only":{"type":["boolean","null"],"description":"Filter to only include visitors with recorded activity (events/sessions).\nWhen true, excludes \"ghost\" visitors that have no events."},"include_crawlers":{"type":["boolean","null"]},"limit":{"type":["integer","null"],"format":"int32"},"offset":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}}]},"VisitorsResponse":{"type":"object","required":["visitors","total_count","filtered_count"],"properties":{"filtered_count":{"type":"integer","format":"int64"},"total_count":{"type":"integer","format":"int64"},"visitors":{"type":"array","items":{"$ref":"#/components/schemas/VisitorInfo"}}}},"VolumeMount":{"type":"object","description":"Volume mount in deployment","required":["source","destination","read_only","type"],"properties":{"destination":{"type":"string","description":"Destination path in container"},"read_only":{"type":"boolean","description":"Read-only flag"},"source":{"type":"string","description":"Source (volume name or path)"},"type":{"$ref":"#/components/schemas/VolumeType","description":"Volume type"}}},"VolumeType":{"type":"string","description":"Volume type","enum":["bind","volume","tmpfs"]},"VulnerabilityResponse":{"type":"object","required":["id","scan_id","vulnerability_id","package_name","installed_version","severity","title","created_at"],"properties":{"class":{"type":["string","null"],"example":"os-pkgs"},"created_at":{"type":"string","example":"2025-12-08T12:15:47.609192Z"},"cvss_score":{"type":["number","null"],"format":"float"},"description":{"type":["string","null"]},"fixed_version":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"installed_version":{"type":"string"},"last_modified_date":{"type":["string","null"],"example":"2025-12-08T12:15:47.609192Z"},"package_name":{"type":"string"},"primary_url":{"type":["string","null"]},"published_date":{"type":["string","null"],"example":"2025-12-08T12:15:47.609192Z"},"references":{},"scan_id":{"type":"integer","format":"int32"},"severity":{"type":"string"},"target":{"type":["string","null"],"example":"alpine:3.18 (alpine 3.18.0)"},"title":{"type":"string"},"type":{"type":["string","null"],"example":"alpine"},"vulnerability_id":{"type":"string"}}},"WalWarning":{"oneOf":[{"type":"object","description":"`pg_wal` is significantly larger than `max_wal_size`.","required":["pg_wal_bytes","max_wal_size_bytes","ratio","kind"],"properties":{"kind":{"type":"string","enum":["wal_bloat"]},"max_wal_size_bytes":{"type":"integer","format":"int64"},"pg_wal_bytes":{"type":"integer","format":"int64"},"ratio":{"type":"number","format":"double"}}},{"type":"object","description":"A replication slot is holding WAL it's not consuming.","required":["slot_name","retained_bytes","active","kind"],"properties":{"active":{"type":"boolean"},"kind":{"type":"string","enum":["stale_slot"]},"retained_bytes":{"type":"integer","format":"int64"},"slot_name":{"type":"string"}}},{"type":"object","description":"`archive_status/*.ready` count exceeds threshold — `archive_command`\nis either failing or running slower than WAL generation.","required":["ready_count","kind"],"properties":{"kind":{"type":"string","enum":["archive_backlog"]},"ready_count":{"type":"integer","format":"int64"}}},{"type":"object","description":"`archive_mode = on` but `archive_command` is empty / `/bin/true`.\nWAL accumulates forever waiting for a destination that never accepts.","required":["kind"],"properties":{"kind":{"type":"string","enum":["archive_mode_without_command"]}}},{"type":"object","description":"Oldest WAL segment is older than `WAL_NOT_RECYCLED_AGE_SECS`.\nIndependent signal: something is blocking recycling even if total\nsize hasn't exploded yet.","required":["oldest_age_secs","kind"],"properties":{"kind":{"type":"string","enum":["wal_not_recycled"]},"oldest_age_secs":{"type":"integer","format":"int64"}}}],"description":"One actionable warning surfaced to the UI.\n\nEach variant carries the data needed to render a remediation hint without\nthe frontend re-querying anything."},"WalWarningSeverity":{"type":"string","enum":["warning","critical"]},"WebhookConfig":{"type":"object","description":"Configuration for a generic webhook notification provider","required":["url"],"properties":{"headers":{"type":"object","description":"Custom headers to include in the request (e.g., for authentication tokens)","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"},"example":{"Authorization":"Bearer your-token","X-Custom-Header":"custom-value"}},"method":{"type":"string","description":"HTTP method to use (POST, PUT, PATCH). Defaults to POST.","example":"POST"},"timeout_secs":{"type":"integer","format":"int64","description":"Request timeout in seconds. Defaults to 30.","example":30,"minimum":0},"url":{"type":"string","description":"The URL to send webhook requests to","example":"https://api.example.com/notifications"}}},"WebhookDeliveryResponse":{"type":"object","required":["id","webhook_id","event_type","event_id","payload","success","attempt_number","created_at"],"properties":{"attempt_number":{"type":"integer","format":"int32"},"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"delivered_at":{"type":["string","null"],"format":"date-time"},"error_message":{"type":["string","null"]},"event_id":{"type":"string"},"event_type":{"type":"string"},"id":{"type":"integer","format":"int32"},"payload":{"type":"string","description":"JSON payload that was sent to the webhook endpoint","example":{"event_type":"deployment.succeeded","data":{"deployment_id":123}}},"status_code":{"type":["integer","null"],"format":"int32"},"success":{"type":"boolean"},"webhook_id":{"type":"integer","format":"int32"}}},"WebhookResponse":{"type":"object","required":["id","project_id","url","events","enabled","has_secret","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"enabled":{"type":"boolean"},"events":{"type":"array","items":{"type":"string"}},"has_secret":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"url":{"type":"string"}}},"WebhookTriggerRequest":{"allOf":[{"description":"Arbitrary JSON payload from the caller. Passed to the agent as user_context."}]},"WebhookTriggerResponse":{"type":"object","required":["run_id","status"],"properties":{"run_id":{"type":"integer","format":"int32"},"status":{"type":"string"}}},"WorkflowDryRunRequest":{"type":"object","required":["yaml"],"properties":{"cpu_limit":{"type":["number","null"],"format":"double","description":"Optional CPU override applied after parsing YAML (clamped server-side).\nWhen `Some`, this takes precedence over `cpu_limit` inside the YAML —\nlets the CLI pass `--cpu` without rewriting the YAML text."},"error_group_id":{"type":["integer","null"],"format":"int32","description":"Optional error group to link this dry-run to. When set, the executor's\n`load_error_context` path injects `{{error_type}}` / `{{error_message}}`\n/ `{{stack_trace}}` into the prompt — same behaviour as a committed\nworkflow triggered with `trigger_source_type = \"error_group\"`. Must\nbelong to `project_id` (handler enforces)."},"memory_limit_mb":{"type":["integer","null"],"format":"int64","description":"Optional memory override in MB (clamped server-side). Same precedence\nrule as `cpu_limit`.","minimum":0},"user_context":{"type":["string","null"],"description":"Optional context appended to the prompt (e.g. \"test against staging\nonly\"). Mirrors `TriggerAgentRequest.user_context`."},"yaml":{"type":"string","description":"Full WorkflowYamlConfig as YAML text. Server validates and re-serializes\nbefore storing on the run row."}}},"WorkloadDescriptor":{"type":"object","description":"Brief descriptor for discovered workloads (used in listing)","required":["id","workload_type","status","labels"],"properties":{"created_at":{"type":["string","null"],"format":"date-time","description":"Creation timestamp"},"id":{"$ref":"#/components/schemas/WorkloadId","description":"Unique ID in source system"},"image":{"type":["string","null"],"description":"Image/build reference (for containers)"},"labels":{"type":"object","description":"Labels/tags from source system","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":["string","null"],"description":"Workload name (if any)"},"status":{"$ref":"#/components/schemas/WorkloadStatus","description":"Current status"},"workload_type":{"$ref":"#/components/schemas/WorkloadType","description":"Workload type (container, function, static-site, etc.)"}}},"WorkloadId":{"type":"string","description":"Unique identifier for a workload in the source system"},"WorkloadStatus":{"type":"string","description":"Workload status in source system","enum":["running","paused","stopped","exited","failed","deployed","building","unknown"]},"WorkloadType":{"type":"string","description":"Workload type","enum":["container","function","static-site","server-side-app","worker","database","message-queue","cache","cron-job","other"]},"WriteFileBody":{"type":"object","required":["path","contents_b64"],"properties":{"contents_b64":{"type":"string","description":"File contents, base64-encoded. Required — lets callers ship binary\ndata over JSON without charset games."},"mode":{"type":["integer","null"],"format":"int32","description":"Unix permission mask (e.g. 0o644). Defaults to 0o644 when absent.","minimum":0},"path":{"type":"string","description":"Absolute path inside the sandbox. Must start with `/`."}},"additionalProperties":false},"WriteFilesBody":{"type":"object","required":["files"],"properties":{"files":{"type":"array","items":{"$ref":"#/components/schemas/WriteFileBody"},"description":"List of files to write. Each entry must include an absolute\n`path` and base64-encoded `contents_b64`. Empty list is a no-op."}},"additionalProperties":false},"WriteFilesResponse":{"type":"object","required":["written"],"properties":{"written":{"type":"integer","description":"Number of files successfully written before the first failure\n(if any). On full success this equals `files.len()`.","minimum":0}}},"ZoneListResponse":{"type":"object","description":"Zone list response","required":["zones"],"properties":{"zones":{"type":"array","items":{"$ref":"#/components/schemas/DnsZone"}}}}},"securitySchemes":{"bearer_auth":{"type":"http","scheme":"bearer","description":"Bearer token authentication. Use format: `Bearer `. Supports API keys (starting with `tk_`), CLI tokens, and session tokens."}}},"tags":[{"name":"Events","description":"Analytics events tracking endpoints"},{"name":"Metrics","description":"Analytics metrics collection endpoints including performance web vitals"},{"name":"Funnels","description":"Funnel management endpoints"},{"name":"Analytics","description":"Analytics and session replay management"},{"name":"Performance","description":"Performance metrics management"},{"name":"geo","description":"Geolocation API endpoints"},{"name":"Platform","description":"Platform information and compatibility"},{"name":"Teams","description":"Teams and project-scoped access"},{"name":"Git Providers","description":"Git provider management endpoints"},{"name":"Repositories","description":"Repository management endpoints"},{"name":"Public Repositories","description":"Endpoints for accessing public repositories without authentication. Supports GitHub and GitLab."},{"name":"Notification Providers","description":"Notification provider management endpoints"},{"name":"Notification Preferences","description":"User notification preferences and settings"},{"name":"DNS Providers","description":"DNS provider management endpoints"},{"name":"Internal DNS","description":"Per-node DNS resolver sync (ADR-011)"},{"name":"Domains","description":"Domain management endpoints"},{"name":"Email Providers","description":"Email provider management endpoints"},{"name":"Email Domains","description":"Email domain management and verification"},{"name":"Emails","description":"Email sending and retrieval"},{"name":"Email Tracking","description":"Email open and click tracking"},{"name":"Email Validation","description":"Email address validation and verification"},{"name":"Webhooks","description":"Webhook management endpoints"},{"name":"Webhook Deliveries","description":"Webhook delivery history and retry endpoints"},{"name":"External Services","description":"External service integration endpoints"},{"name":"External Services - Query","description":"Data querying and exploration endpoints"},{"name":"Metrics","description":"Time-series metrics and alert rule endpoints"},{"name":"KV Store","description":"Key-Value storage operations"},{"name":"KV Management","description":"KV service management operations"},{"name":"Blob","description":"Blob storage operations"},{"name":"Blob Management","description":"Blob service management operations"},{"name":"Feature Flags","description":"Runtime configuration that changes without a redeploy"},{"name":"Environments","description":"Environment management operations"},{"name":"Secrets","description":"File-mounted secrets (/run/secrets/)"},{"name":"Projects","description":"Project management endpoints"},{"name":"Presets","description":"Available deployment presets"},{"name":"Templates","description":"Project template endpoints"},{"name":"Custom Domains","description":"Custom domain management for projects"},{"name":"error-tracking","description":"Error tracking data fetching endpoints"},{"name":"Vulnerability Scans","description":"Vulnerability scan management endpoints"},{"name":"Agents","description":"Autonomous AI agents, autofixer (interactive AI debugging), skills/MCP definitions, and preview gateway management."},{"name":"Crons","description":"Cron jobs management API"},{"name":"Sandboxes","description":"Standalone sandbox API (`/v1/sandboxes/*`) for running isolated containers."},{"name":"Logs","description":"Log search, context, live tail, and retention management"},{"name":"Imports","description":"Import workloads from external sources"},{"name":"Status Page","description":"Status page and monitoring endpoints"},{"name":"OTel Ingest","description":"OTLP/HTTP ingest endpoints (protobuf)"},{"name":"OTel","description":"Query endpoints for the monitoring UI"},{"name":"GenAI","description":"GenAI agent activity tracing endpoints"},{"name":"Alarms","description":"Unified alarm history — list, summarise, acknowledge, resolve"},{"name":"Authentication","description":"Authentication and authorization endpoints"},{"name":"Users","description":"User management endpoints"},{"name":"Backups","description":"Backup management endpoints"},{"name":"Restore","description":"External service restore operations"},{"name":"Revenue","description":"Per-project revenue tracking integrations and analytics"},{"name":"Observability","description":"Unified observability event stream — runtime logs, requests, spans, errors, revenue"},{"name":"AI Gateway","description":"OpenAI-compatible chat, embeddings, and model endpoints"},{"name":"AI Gateway Admin","description":"Provider key management endpoints"},{"name":"AI Gateway Usage","description":"Usage analytics and reporting endpoints"},{"name":"AI Gateway Pricing","description":"Model pricing endpoints"},{"name":"API Keys","description":"API key management endpoints"},{"name":"Load Balancer","description":"Load balancer management endpoints"},{"name":"IP Access Control","description":"IP access control management endpoints"},{"name":"Files","description":"Static file serving endpoints"},{"name":"External Plugins","description":"External plugin management and discovery"}]} +{"openapi":"3.1.0","info":{"title":"Temps","description":"An API for managing projects, deployments, and infrastructure resources","contact":{"name":"Temps Support","url":"https://temps.sh"},"version":"1.0.0"},"servers":[{"url":"/api","description":"Base path for all API endpoints"}],"paths":{"/.well-known/temps.json":{"get":{"tags":["Platform"],"summary":"Get platform information","operationId":"get_platform_info","responses":{"200":{"description":"Successfully retrieved platform information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlatformInfo"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/0/organizations/{org_slug}/chunk-upload/":{"get":{"tags":["sentry-compat"],"summary":"Chunk upload options (stub for sentry-cli compatibility).","description":"sentry-cli checks this endpoint to determine if chunk-based upload is supported.\nWe return a response indicating that chunk upload is NOT supported, which forces\nsentry-cli to fall back to the standard file-by-file upload.","operationId":"chunk_upload_options","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Chunk upload options","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryChunkUploadResponse"}}}}}}},"/0/organizations/{org_slug}/releases/":{"post":{"tags":["sentry-compat"],"summary":"Create a release (stub for sentry-cli compatibility).","description":"sentry-cli calls this before uploading files. Since Temps implicitly creates\nreleases when source maps are uploaded, this is a no-op that returns the\nexpected response format.","operationId":"create_release","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored in single-tenant mode)","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryCreateReleaseRequest"}}},"required":true},"responses":{"201":{"description":"Release created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryReleaseResponse"}}}},"401":{"description":"Unauthorized"}}}},"/0/projects/{org_slug}/{project_slug}/releases/":{"post":{"tags":["sentry-compat"],"summary":"Create a release for a specific project (stub for sentry-cli compatibility).","description":"sentry-cli calls this endpoint (instead of /organizations/.../releases/) when\nboth SENTRY_ORG and SENTRY_PROJECT env vars are set. Behaves identically to\nthe organizations endpoint but validates the project slug.","operationId":"create_project_release","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored in single-tenant mode)","required":true,"schema":{"type":"string"}},{"name":"project_slug","in":"path","description":"Project slug or numeric ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryCreateReleaseRequest"}}},"required":true},"responses":{"201":{"description":"Release created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryReleaseResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"}}}},"/0/projects/{org_slug}/{project_slug}/releases/{version}/":{"put":{"tags":["sentry-compat"],"summary":"Finalize a release (stub for sentry-cli compatibility).","description":"sentry-cli calls `releases finalize` after uploading source maps. This sets\nthe dateReleased on the release. Since Temps stores source maps independently\nof releases, this is a no-op that returns the expected response.","operationId":"finalize_project_release","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored)","required":true,"schema":{"type":"string"}},{"name":"project_slug","in":"path","description":"Project slug or numeric ID","required":true,"schema":{"type":"string"}},{"name":"version","in":"path","description":"Release version to finalize","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Release finalized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryReleaseResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"}}}},"/0/projects/{org_slug}/{project_slug}/releases/{version}/files/":{"get":{"tags":["sentry-compat"],"summary":"List files for a release.","description":"Returns all source maps stored for a specific release in sentry-cli compatible format.","operationId":"list_release_files","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored)","required":true,"schema":{"type":"string"}},{"name":"project_slug","in":"path","description":"Project slug or numeric ID","required":true,"schema":{"type":"string"}},{"name":"version","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of release files","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SentryReleaseFileResponse"}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"}}},"post":{"tags":["sentry-compat"],"summary":"Upload a source map file for a release.","description":"Accepts the same multipart format as the Sentry release files API.\nThe `name` field should be the URL path of the file (e.g., `~/dist/bundle.js.map`).\n\nThe route has a 50 MiB body limit applied at the router level (Fix #4).\nA per-field size check provides an additional defense-in-depth layer.","operationId":"upload_release_file","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored)","required":true,"schema":{"type":"string"}},{"name":"project_slug","in":"path","description":"Project slug or numeric ID","required":true,"schema":{"type":"string"}},{"name":"version","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"File uploaded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryReleaseFileResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"},"413":{"description":"Source map file exceeds the 50 MiB per-field limit"}}}},"/_temps/event":{"post":{"tags":["Metrics"],"summary":"Record analytics event","operationId":"record_event_metrics","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventMetricsPayload"}}},"required":true},"responses":{"204":{"description":"Event recorded successfully"},"400":{"description":"Bad request"},"500":{"description":"Internal server error"}}}},"/_temps/session-replay/events":{"post":{"tags":["Analytics"],"summary":"Add events to existing session replay","operationId":"add_session_replay_events","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionReplayEventsRequest"}}},"required":true},"responses":{"200":{"description":"Events added successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddEventsResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/_temps/session-replay/init":{"post":{"tags":["Analytics"],"summary":"Initialize session replay with metadata","operationId":"init_session_replay","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionReplayInitRequest"}}},"required":true},"responses":{"201":{"description":"Session initialized successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionReplayInitResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/_temps/speed":{"post":{"tags":["Performance"],"summary":"Record performance metrics from client","operationId":"record_speed_metrics","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpeedMetricsPayload"}}},"required":true},"responses":{"204":{"description":"Metrics recorded successfully"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Host not found in route table","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/_temps/speed/update":{"post":{"tags":["Performance"],"summary":"Update late performance metrics","operationId":"update_speed_metrics","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSpeedMetricsPayload"}}},"required":true},"responses":{"204":{"description":"Metrics updated successfully"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Host not found or metrics not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/admin/gate-settings":{"get":{"tags":["AdminGate"],"operationId":"get_admin_gate","responses":{"200":{"description":"Current admin gate config","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminGateResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["AdminGate"],"operationId":"patch_admin_gate","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAdminGateRequest"}}},"required":true},"responses":{"200":{"description":"Updated admin gate config","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminGateResponse"}}}},"400":{"description":"Invalid IP/CIDR/host"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"409":{"description":"Env-overridden or would lock out caller"}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers":{"get":{"tags":["Authentication"],"operationId":"list_oidc_providers","responses":{"200":{"description":"OIDC providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OidcProviderResponse"}}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Authentication"],"operationId":"create_oidc_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOidcProviderRequest"}}},"required":true},"responses":{"201":{"description":"OIDC provider created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcProviderResponse"}}}},"409":{"description":"Another OIDC provider already uses that name"}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers/{provider_id}":{"delete":{"tags":["Authentication"],"operationId":"delete_oidc_provider","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"OIDC provider deleted"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Authentication"],"operationId":"update_oidc_provider","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOidcProviderRequest"}}},"required":true},"responses":{"200":{"description":"OIDC provider updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcProviderResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers/{provider_id}/role-mappings":{"get":{"tags":["Authentication"],"operationId":"list_oidc_role_mappings","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"OIDC role mappings","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OidcRoleMappingResponse"}}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Authentication"],"operationId":"create_oidc_role_mapping","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOidcRoleMappingRequest"}}},"required":true},"responses":{"201":{"description":"Role mapping created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcRoleMappingResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers/{provider_id}/test":{"post":{"tags":["Authentication"],"operationId":"test_oidc_provider","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcTestConnectionResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers/{provider_id}/users":{"get":{"tags":["Authentication"],"operationId":"list_oidc_provider_users","parameters":[{"name":"provider_id","in":"path","description":"OIDC provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Users authenticated via this OIDC provider","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OidcProviderUserResponse"}}}}},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/role-mappings/{mapping_id}":{"delete":{"tags":["Authentication"],"operationId":"delete_oidc_role_mapping","parameters":[{"name":"mapping_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Role mapping deleted"}},"security":[{"bearer_auth":[]}]}},"/agents/webhook/{webhook_id}":{"post":{"tags":["Agents"],"summary":"Public webhook endpoint. Authenticated via `X-Webhook-Token` header.","description":"`POST /api/agents/webhook/{webhook_id}`\nHeader: `X-Webhook-Token: `\n\nThe `webhook_id` in the URL is a short non-secret identifier (safe to log).\nThe actual credential is the secret token in the header.\n\nAccepts any JSON body, which is passed as `user_context` to the agent run.","operationId":"webhook_trigger","parameters":[{"name":"webhook_id","in":"path","description":"Webhook ID (non-secret)","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookTriggerRequest"}}},"required":true},"responses":{"202":{"description":"Agent run created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookTriggerResponse"}}}},"401":{"description":"Missing or invalid X-Webhook-Token header"},"404":{"description":"Invalid webhook ID"},"422":{"description":"Agent disabled"}}}},"/ai/conversations":{"get":{"tags":["AI Chat"],"summary":"List every active conversation across all projects, most-recently-active\nfirst, annotated with project name/slug. Powers the unified \"all chats\"\nswitcher in the AI assistant dock.","operationId":"list_all_conversations","responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GlobalConversationResponse"}}}}},"401":{"description":""},"403":{"description":""}},"security":[{"bearer_auth":[]}]}},"/ai/pricing":{"get":{"tags":["AI Gateway Pricing"],"operationId":"get_pricing","responses":{"200":{"description":"Model pricing information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PricingResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/providers":{"get":{"tags":["AI Gateway Admin"],"operationId":"list_provider_keys","responses":{"200":{"description":"List of provider keys","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderKeyResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["AI Gateway Admin"],"operationId":"create_provider_key","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProviderKeyRequest"}}},"required":true},"responses":{"201":{"description":"Provider key created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderKeyResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/providers/test":{"post":{"tags":["AI Gateway Admin"],"operationId":"test_provider_key_inline","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestProviderKeyRequest"}}},"required":true},"responses":{"200":{"description":"Test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestProviderKeyResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/providers/{id}":{"delete":{"tags":["AI Gateway Admin"],"operationId":"delete_provider_key","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Provider key deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["AI Gateway Admin"],"operationId":"update_provider_key","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProviderKeyRequest"}}},"required":true},"responses":{"200":{"description":"Provider key updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderKeyResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/providers/{id}/test":{"post":{"tags":["AI Gateway Admin"],"operationId":"test_provider_key_by_id","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestProviderKeyResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Provider key not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/by-provider":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_by_provider","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Usage broken down by provider","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderUsage"}}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/conversations":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_conversations","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max results (defaults to 50, max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"user_id","in":"query","description":"Filter by user ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"tags","in":"query","description":"Filter by tags (comma-separated)","required":false,"schema":{"type":"string"}},{"name":"model","in":"query","description":"Filter by model name","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Conversation summaries","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ConversationSummary"}}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/conversations/{conversation_id}":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_conversation_detail","parameters":[{"name":"conversation_id","in":"path","description":"Conversation ID","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max results (defaults to 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Invocations within a conversation","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UsageLogEntry"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/recent":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_recent","parameters":[{"name":"limit","in":"query","description":"Page size (defaults to 20, max 50)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Number of results to skip for pagination (defaults to 0)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"provider","in":"query","description":"Filter by provider name","required":false,"schema":{"type":"string"}},{"name":"model","in":"query","description":"Filter by model name","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Filter by HTTP status code (exact match)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"cost_gte","in":"query","description":"Cost greater-than-or-equal, in microcents","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"cost_gt","in":"query","description":"Cost strictly greater-than, in microcents","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"cost_lte","in":"query","description":"Cost less-than-or-equal, in microcents","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"cost_lt","in":"query","description":"Cost strictly less-than, in microcents","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tokens_gte","in":"query","description":"Total tokens greater-than-or-equal","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tokens_gt","in":"query","description":"Total tokens strictly greater-than","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tokens_lte","in":"query","description":"Total tokens less-than-or-equal","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tokens_lt","in":"query","description":"Total tokens strictly less-than","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Page of recent usage log entries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageLogPage"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/summary":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_summary","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Usage summary for the time range","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageSummary"}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/timeseries":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_timeseries","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}},{"name":"bucket","in":"query","description":"Bucket size: hour, day, week (defaults to day)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Time-series usage data","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TimeseriesBucket"}}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/top-models":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_top_models","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max results (defaults to 10)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Top models by request count","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ModelUsage"}}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/v1/chat/completions":{"post":{"tags":["AI Gateway"],"operationId":"chat_completions","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatCompletionRequest"}}},"required":true},"responses":{"200":{"description":"Chat completion response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatCompletionResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"404":{"description":"Model not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/v1/embeddings":{"post":{"tags":["AI Gateway"],"operationId":"embeddings","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmbeddingRequest"}}},"required":true},"responses":{"200":{"description":"Embedding response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmbeddingResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"404":{"description":"Model not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/v1/models":{"get":{"tags":["AI Gateway"],"operationId":"list_models","responses":{"200":{"description":"List of available models","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/analytics/active-visitors":{"get":{"tags":["Analytics"],"summary":"Get detailed active visitors","operationId":"get_analytics_active_visitors","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Deployment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"window_minutes","in":"query","description":"Time window in minutes for active visitors (default: 5)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved active visitors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActiveVisitorsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/event-detail":{"get":{"tags":["Analytics"],"summary":"Get detailed analytics for a specific event","operationId":"get_event_detail","parameters":[{"name":"event_name","in":"query","description":"Event name to get details for","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"bucket_interval","in":"query","description":"Bucket interval: hour, day, week, month (default: auto)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved event details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventDetailResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/event-entries":{"get":{"tags":["Analytics"],"summary":"Get paginated list of raw occurrences of a specific event, including custom JSON properties","operationId":"get_event_entries","parameters":[{"name":"event_name","in":"query","description":"Event name to list occurrences for","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (1-based, default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Successfully retrieved event entries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventEntriesResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/event-visitors":{"get":{"tags":["Analytics"],"summary":"Get paginated list of visitors who triggered a specific event","operationId":"get_event_visitors","parameters":[{"name":"event_name","in":"query","description":"Event name to list visitors for","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (1-based, default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Successfully retrieved event visitors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventVisitorsResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/events":{"get":{"tags":["Analytics"],"operationId":"get_analytics_events_count","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Maximum number of results to return","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"custom_events_only","in":"query","description":"Only return custom events, excluding system events like page_view, page_leave, heartbeat (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"breakdown","in":"query","description":"Breakdown by geography: 'country', 'region', or 'city' (optional)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved event counts","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventCount"}}}}},"400":{"description":"Invalid date format, missing required parameters, or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/general-stats":{"get":{"tags":["Analytics"],"summary":"Get general statistics across all projects for a time frame","operationId":"get_general_stats","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_ids","in":"query","description":"Optional: Filter by specific project IDs (comma-separated)","required":false,"schema":{"type":"array","items":{"type":"integer","format":"int32"}}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"include_project_breakdown","in":"query","description":"Whether to include per-project breakdown (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Successfully retrieved general statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeneralStatsResponse"}}}},"400":{"description":"Invalid date format or parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/has-events":{"get":{"tags":["Analytics"],"operationId":"check_analytics_has_events","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Analytics events existence check","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HasAnalyticsEventsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/live-visitors":{"get":{"tags":["Analytics"],"summary":"Get list of currently live visitors from visitor table","operationId":"get_live_visitors_list","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"window_minutes","in":"query","description":"Time window in minutes for live visitors (default: 5)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved live visitors list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LiveVisitorsListResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-flow":{"get":{"tags":["Analytics"],"summary":"Get page flow analytics: entry pages, exit pages, drop-off points, and page transitions","operationId":"get_page_flow","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max entry/exit pages to return (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"transitions_limit","in":"query","description":"Max page transitions to return (default: 50, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"min_views_for_dropoff","in":"query","description":"Minimum views for drop-off analysis (default: 5)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved page flow analytics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PageFlowResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-hourly-sessions":{"get":{"tags":["Analytics"],"operationId":"get_page_hourly_sessions","parameters":[{"name":"page_path","in":"query","description":"The page path to get sessions for","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","description":"Start time in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"bucket_interval","in":"query","description":"Bucket interval: 'hour', 'day', 'week', or 'month' (default: auto-determined based on range)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved page sessions with time buckets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PageHourlySessionsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-path-detail":{"get":{"tags":["Analytics"],"summary":"Get detailed analytics for a specific page path\nReturns visitors, page views, activity over time, geographic distribution, and referrers","operationId":"get_page_path_detail","parameters":[{"name":"page_path","in":"query","description":"The page path to get details for (URL-encoded)","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"bucket_interval","in":"query","description":"Bucket interval for time series: 'hour', 'day', 'week', 'month' (default: auto based on date range)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved page path detail analytics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PagePathDetailResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-path-visitors":{"get":{"tags":["Analytics"],"summary":"Get individual visitor sessions for a specific page path","operationId":"get_page_path_visitors","parameters":[{"name":"page_path","in":"query","description":"The page path to get visitors for (URL-encoded)","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (1-based, default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Successfully retrieved page path visitors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PagePathVisitorsResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-paths":{"get":{"tags":["Analytics"],"operationId":"get_page_paths","parameters":[{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS (optional)","required":false,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS (optional)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Maximum number of page paths to return (default: 100, max: 1000)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved page paths","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PagePathsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-paths-sparklines":{"get":{"tags":["Analytics"],"operationId":"get_page_paths_sparklines","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","description":"Start time in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"page_paths","in":"query","description":"Comma-separated list of page paths","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sparkline data for all requested page paths","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PagePathsSparklineResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/recent-activity":{"get":{"tags":["Analytics"],"summary":"Get recent activity events for real-time activity feed","operationId":"get_recent_activity","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"since_id","in":"query","description":"Return events with ID greater than this (cursor-based polling)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"limit","in":"query","description":"Max events to return (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved recent activity events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecentActivityResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/sessions/{session_id}":{"get":{"tags":["Analytics"],"summary":"Get detailed information about a specific session including events and request logs","operationId":"get_session_details","parameters":[{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved session details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionDetails"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Session not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/sessions/{session_id}/events":{"get":{"tags":["Analytics"],"operationId":"get_analytics_session_events","parameters":[{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":false,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Number of results to return (default: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Number of results to skip (default: 0)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved session events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionEventsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Session not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/sessions/{session_id}/logs":{"get":{"tags":["Analytics"],"operationId":"get_session_logs","parameters":[{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":false,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Number of results to return (default: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Number of results to skip (default: 0)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved session logs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionLogsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Session not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitor-facets":{"get":{"tags":["Analytics"],"summary":"Get filter dropdown contents for the visitors page. Returns the top\nvalues per dimension with distinct visitor counts so the UI can render\n\"Country — 1,234 visitors\" rows. Each dimension is computed against the\nsegment minus its own filter, so a selected value never collapses its\nown dropdown.","operationId":"get_visitor_facets","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"include_crawlers","in":"query","description":"Include crawlers (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"has_activity_only","in":"query","description":"Hide ghost visitors (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"per_facet_limit","in":"query","description":"Top N values per dimension (default: 50, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"filter_country","in":"query","description":"Geolocation country","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Geolocation region","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Geolocation city","required":false,"schema":{"type":"string"}},{"name":"filter_channel","in":"query","description":"First-touch channel","required":false,"schema":{"type":"string"}},{"name":"filter_referrer","in":"query","description":"First-touch referrer hostname (use 'Direct' for null)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Top values per dimension","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorFacets"}}}},"400":{"description":"Invalid date format or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors":{"get":{"tags":["Analytics"],"summary":"Get list of visitors with summary information","operationId":"get_visitors","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"include_crawlers","in":"query","description":"Include crawlers (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Maximum number of visitors to return (default: 50)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Number of visitors to skip (default: 0)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"has_activity_only","in":"query","description":"Filter to only include visitors with recorded activity (events/sessions). When true, excludes ghost visitors (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"filter_country","in":"query","description":"Geolocation country","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Geolocation region","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Geolocation city","required":false,"schema":{"type":"string"}},{"name":"filter_channel","in":"query","description":"First-touch channel","required":false,"schema":{"type":"string"}},{"name":"filter_referrer","in":"query","description":"First-touch referrer hostname (use 'Direct' for null)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved visitors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorsResponse"}}}},"400":{"description":"Invalid date format, missing required parameters, or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/guid/{visitor_id}":{"get":{"tags":["Analytics"],"summary":"Get visitor by GUID with geolocation data","operationId":"get_visitor_by_guid","parameters":[{"name":"visitor_id","in":"path","description":"Visitor GUID (supports enc_ prefix for encrypted IDs)","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor with geolocation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorWithGeolocation"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/id/{id}":{"get":{"tags":["Analytics"],"summary":"Get visitor by numeric ID with geolocation data","operationId":"get_visitor_by_id","parameters":[{"name":"id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor with geolocation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorWithGeolocation"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}":{"get":{"tags":["Analytics"],"summary":"Get detailed information about a specific visitor by numeric ID","operationId":"get_visitor_details","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorDetails"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/enrich":{"put":{"tags":["Analytics"],"operationId":"enrich_visitor","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID - can be numeric ID, GUID, or encrypted GUID (enc_xxx)","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnrichVisitorRequest"}}},"required":true},"responses":{"200":{"description":"Successfully enriched visitor data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnrichVisitorResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/info":{"get":{"tags":["Analytics"],"summary":"Get visitor record from database","operationId":"get_visitor_info","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor info","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorRecord"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/journey":{"get":{"tags":["Analytics"],"summary":"Get the complete visitor journey: all events across all sessions, grouped by session","operationId":"get_visitor_journey","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"limit_sessions","in":"query","description":"Maximum number of sessions to return (default: 50)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor journey","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorJourneyResponse"}}}},"400":{"description":"Invalid parameters"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/sessions":{"get":{"tags":["Analytics"],"summary":"Get all sessions for a specific visitor by numeric ID","operationId":"get_analytics_visitor_sessions","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Maximum number of sessions to return (default: 100)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor sessions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorSessionsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/stats":{"get":{"tags":["Analytics"],"summary":"Get visitor statistics","operationId":"get_visitor_stats","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorStats"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys":{"get":{"tags":["API Keys"],"operationId":"list_api_keys","parameters":[{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default: 20)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"API keys retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["API Keys"],"operationId":"create_api_key","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyRequest"}}},"required":true},"responses":{"201":{"description":"API key created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"409":{"description":"Conflict - API key name already exists"},"428":{"description":"Recent MFA verification required"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/permissions":{"get":{"tags":["API Keys"],"operationId":"get_api_key_permissions","responses":{"200":{"description":"Available permissions and roles retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AvailablePermissions"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/{id}":{"get":{"tags":["API Keys"],"operationId":"get_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"API key retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["API Keys"],"operationId":"update_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateApiKeyRequest"}}},"required":true},"responses":{"200":{"description":"API key updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"409":{"description":"Conflict - API key name already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["API Keys"],"operationId":"delete_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"API key deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/{id}/activate":{"post":{"tags":["API Keys"],"operationId":"activate_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"API key activated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/{id}/deactivate":{"post":{"tags":["API Keys"],"operationId":"deactivate_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"API key deactivated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/{id}/rotate":{"post":{"tags":["API Keys"],"operationId":"rotate_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"API key rotated successfully; the response contains the new plaintext secret, shown only once","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"428":{"description":"Recent MFA verification required"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/auth/cli/device/approve":{"post":{"tags":["Authentication"],"operationId":"cli_device_approve","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceApproveRequest"}}},"required":true},"responses":{"200":{"description":"Session approved; CLI can now claim the API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceApproveResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Browser session required"},"404":{"description":"Unknown user_code"},"409":{"description":"Already resolved"},"410":{"description":"Session expired"},"428":{"description":"Recent MFA verification required"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/auth/cli/device/deny":{"post":{"tags":["Authentication"],"operationId":"cli_device_deny","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceApproveRequest"}}},"required":true},"responses":{"200":{"description":"Session denied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceApproveResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Unknown user_code"},"409":{"description":"Already resolved"},"410":{"description":"Session expired"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/auth/cli/device/lookup":{"get":{"tags":["Authentication"],"operationId":"cli_device_lookup","parameters":[{"name":"user_code","in":"query","description":"`user_code` as displayed in the CLI / pasted into the URL.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Device session metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceLookupResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Unknown user_code"},"410":{"description":"Device session expired"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/auth/cli/device/poll":{"post":{"tags":["Authentication"],"operationId":"cli_device_poll","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDevicePollRequest"}}},"required":true},"responses":{"200":{"description":"Poll result; check `status` field","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDevicePollResponse"}}}},"404":{"description":"Unknown device_code"},"500":{"description":"Internal server error"}}}},"/auth/cli/device/start":{"post":{"tags":["Authentication"],"operationId":"cli_device_start","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceStartRequest"}}},"required":true},"responses":{"200":{"description":"Device session created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceStartResponse"}}}},"500":{"description":"Internal server error"}}}},"/auth/cli/logout":{"post":{"tags":["Authentication"],"operationId":"cli_logout","responses":{"204":{"description":"API key revoked"},"401":{"description":"Not authenticated"},"403":{"description":"Endpoint requires API key authentication"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/auth/email-status":{"get":{"tags":["Authentication"],"operationId":"email_status","responses":{"200":{"description":"Email configuration status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailStatusResponse"}}}},"500":{"description":"Internal server error"}}}},"/auth/login":{"post":{"tags":["Authentication"],"operationId":"login","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginRequest"}}},"required":true},"responses":{"200":{"description":"Login successful, session cookie set","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"401":{"description":"Invalid credentials, or the account's role requires MFA enrollment that has not been completed"},"500":{"description":"Internal server error"}}}},"/auth/oidc/callback":{"get":{"tags":["Authentication"],"operationId":"oidc_callback","parameters":[{"name":"code","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"state","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"error","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"error_description","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"302":{"description":"Redirect to app with session cookie or login error"}}}},"/auth/oidc/login/{slug}":{"get":{"tags":["Authentication"],"operationId":"start_oidc_login_by_slug","parameters":[{"name":"slug","in":"path","description":"OIDC provider slug (from /email-status or /auth/oidc/providers)","required":true,"schema":{"type":"string"}},{"name":"return_to","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"302":{"description":"Redirect to IdP authorize URL"},"404":{"description":"Provider not found"},"503":{"description":"OIDC provider unreachable"}}}},"/auth/oidc/providers":{"get":{"tags":["Authentication"],"operationId":"list_public_providers","responses":{"200":{"description":"Enabled OIDC providers for login page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcProvidersListResponse"}}}}}}},"/auth/password-reset/request":{"post":{"tags":["Authentication"],"operationId":"request_password_reset","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailRequest"}}},"required":true},"responses":{"200":{"description":"Reset email sent if account exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"503":{"description":"Email service not configured"}}}},"/auth/password-reset/verify":{"post":{"tags":["Authentication"],"operationId":"reset_password","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPasswordRequest"}}},"required":true},"responses":{"200":{"description":"Password reset successful","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"400":{"description":"Invalid or expired token"},"500":{"description":"Internal server error"}}}},"/auth/step-up":{"post":{"tags":["Authentication"],"operationId":"verify_step_up","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyStepUpRequest"}}},"required":true},"responses":{"200":{"description":"Session elevated for sensitive actions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StepUpResponse"}}}},"400":{"description":"Verification code is empty"},"401":{"description":"Invalid code or expired session"},"403":{"description":"Browser session required"},"428":{"description":"MFA setup required"},"429":{"description":"Too many verification attempts"},"500":{"description":"Verification infrastructure failed"}},"security":[{"session_token":[]}]}},"/auth/verify-email":{"get":{"tags":["Authentication"],"operationId":"verify_email","parameters":[{"name":"token","in":"query","description":"Email verification token","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Email verified successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"400":{"description":"Invalid or expired token"},"500":{"description":"Internal server error"}}}},"/auth/verify-mfa":{"post":{"tags":["Authentication"],"operationId":"verify_mfa_challenge","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaVerificationRequest"}}},"required":true},"responses":{"204":{"description":"MFA verification successful"},"400":{"description":"Invalid request"},"401":{"description":"Invalid MFA code"},"500":{"description":"Internal server error"}}}},"/backups/alerts":{"get":{"tags":["Backups"],"summary":"List open backup alerts.","description":"Returns all alerts that have not yet been resolved, ordered by `opened_at`\ndescending (newest first). The UI renders these as a banner above the\nBackups page content. Alerts are auto-opened by the watcher and\nauto-resolved when the triggering condition clears.\n\n**Schedule overdue** — the backup scheduler did not enqueue a job within\nthe expected window (1 hour past `next_run`). Usually means the scheduler\ntask is dead or wedged.\n\n**Job stalled** — a `backup_jobs` row has been in `state='pending'` for\nmore than 1 hour. The runner never claimed the job. Usually means the\nrunner task is dead or the runner concurrency cap is too low.","operationId":"list_backup_alerts","responses":{"200":{"description":"List of open backup alerts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupAlertListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/cleanup":{"post":{"tags":["Backups"],"summary":"Preview or run retention using each selected schedule's configured retention days.","operationId":"cleanup_expired_backups","parameters":[{"name":"dry_run","in":"query","description":"Return the backups selected by retention without deleting anything.","required":false,"schema":{"type":"boolean"}},{"name":"schedule_id","in":"query","description":"Limit cleanup to one backup schedule.","required":false,"schema":{"type":["integer","null"],"format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CleanupExpiredBackupsRequest"}}},"required":true},"responses":{"200":{"description":"Retention cleanup completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RetentionCleanupReport"}}}},"400":{"description":"Missing or invalid preview candidate list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule or backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"409":{"description":"Cleanup preview is stale","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Cleanup could not be started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/external-services/{id}/run":{"post":{"tags":["Backups"],"summary":"Run a backup for an external service manually.","description":"Enqueues the backup for asynchronous execution via the `BackupRunner`\n(ADR-014). Returns `202 Accepted` immediately: pending parent and child\nrows are inserted, and a `backup_jobs` row is enqueued for the resolved\nengine. Poll `GET /backups/{id}` to observe `pending → running → completed`.","operationId":"run_external_service_backup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunExternalServiceBackupRequest"}}},"required":true},"responses":{"202":{"description":"Backup enqueued for async execution","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceBackupResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"External service or S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/external-services/{service_id}/backups":{"get":{"tags":["Backups"],"summary":"List all backups for a specific external service (DB-only, no S3 scan).","description":"Returns a paginated list of backups that belong to this service.\nCompletes in <100 ms regardless of S3 endpoint latency because it\nnever touches S3.","operationId":"list_external_service_backups","parameters":[{"name":"service_id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based). Defaults to 1.","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"page_size","in":"query","description":"Items per page. Defaults to 20, max 100.","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Paginated list of backups for this service","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceBackupListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/external-services/{service_id}/schedules":{"get":{"tags":["Backups"],"summary":"List the schedules that target a specific external service. Useful for\nthe service detail page (\"which schedules back this DB up?\").","operationId":"list_service_schedules","parameters":[{"name":"service_id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Schedules backing up this service","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Service not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources":{"get":{"tags":["Backups"],"summary":"List all S3 sources","operationId":"list_s3_sources","responses":{"200":{"description":"List of S3 sources","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/S3SourceResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Backups"],"summary":"Create a new S3 source","operationId":"create_s3_source","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateS3SourceRequest"}}},"required":true},"responses":{"201":{"description":"S3 source created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3SourceResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/test":{"post":{"tags":["Backups"],"summary":"Test S3 connectivity against a prospective source configuration (before creating it).\nThe credentials are NOT persisted. Useful for validating the form in the UI.","operationId":"test_s3_connection_preview","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateS3SourceRequest"}}},"required":true},"responses":{"200":{"description":"Connection test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3ConnectionTestResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}":{"get":{"tags":["Backups"],"summary":"Get an S3 source by ID","operationId":"get_s3_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"S3 source details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3SourceResponse"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Backups"],"summary":"Delete an S3 source","operationId":"delete_s3_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"S3 source deleted"},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Backups"],"summary":"Update an S3 source","operationId":"update_s3_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateS3SourceRequest"}}},"required":true},"responses":{"200":{"description":"S3 source updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3SourceResponse"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}/backups":{"get":{"tags":["Backups"],"summary":"List all backups in an S3 source","operationId":"list_source_backups","parameters":[{"name":"include_s3_scan","in":"query","description":"When `true`, scan the S3 bucket for backups not tracked in the\nlocal database (useful after disaster-recovery from another Temps\ninstance). Defaults to `false` — the fast DB-only path.","required":false,"schema":{"type":"boolean"}},{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of all backups in the source","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceBackupIndexResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"S3 source not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}/run":{"post":{"tags":["Backups"],"summary":"Run a backup immediately for an S3 source.","description":"Enqueues the backup for asynchronous execution via the `BackupRunner`\n(ADR-014). Returns `202 Accepted` immediately: a `backups` row is inserted\nwith `state='pending'` and a `backup_jobs` row is enqueued for the\n`ControlPlaneEngine`. Poll `GET /backups/{id}` to observe\n`pending → running → completed`.","operationId":"run_backup_for_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunBackupRequest"}}},"required":true},"responses":{"202":{"description":"Backup enqueued for async execution","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}/set-default":{"post":{"tags":["Backups"],"summary":"Mark an S3 source as the default. All new backups/schedules/services that do not\nexplicitly reference a source will use the default. Returns the updated source.","operationId":"set_default_s3_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"S3 source marked as default","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3SourceResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}/test":{"post":{"tags":["Backups"],"summary":"Test connectivity to an existing S3 source using its stored credentials.","operationId":"test_s3_source_connection","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3ConnectionTestResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedule-runs/{id}/cancel":{"post":{"tags":["Backups"],"summary":"Cancel every non-terminal child backup belonging to a schedule run.","description":"Loops over `state IN ('pending','running')` children and flips each via\nthe same path as the per-backup cancel endpoint. The parent\n`schedule_runs.finished_at` is stamped automatically once no live\nchildren remain. Idempotent: cancelling a run with no live children is\na 200 with `cancelled = 0`.","operationId":"cancel_schedule_run","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Cancel processed (idempotent)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelBackupResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule run not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedule-runs/{id}/jobs":{"get":{"tags":["Backups"],"summary":"List the individual backup jobs for a single scheduler run.","description":"Returns each child `backups` row joined with its external service name and\nthe most-recent `backup_jobs` engine key. Used by the schedule detail\naccordion to show per-job detail on row expand.\n\n`page_size` defaults to 50 and is capped at 200.","operationId":"list_schedule_run_jobs","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Jobs for this scheduler run","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ScheduleRunJobEntry"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules":{"get":{"tags":["Backups"],"summary":"List all backup schedules","operationId":"list_backup_schedules","responses":{"200":{"description":"List of backup schedules","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Backups"],"summary":"Create a new backup schedule","operationId":"create_backup_schedule","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBackupScheduleRequest"}}},"required":true},"responses":{"201":{"description":"Backup schedule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}":{"get":{"tags":["Backups"],"summary":"Get a backup schedule by ID","operationId":"get_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Backup schedule details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"404":{"description":"Backup schedule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Backups"],"summary":"Delete a backup schedule","operationId":"delete_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Backup schedule deleted"},"404":{"description":"Backup schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Backups"],"summary":"Update a backup schedule (partial update).","description":"All request fields are optional; only fields that are present in the\nJSON body are updated. Absent fields leave the corresponding column\nunchanged. If `schedule_expression` is changed, `next_run` is\nrecomputed automatically.","operationId":"update_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBackupScheduleRequest"}}},"required":true},"responses":{"200":{"description":"Schedule updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/backups":{"get":{"tags":["Backups"],"summary":"List backups for a schedule","operationId":"list_backups_for_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of backups for the schedule","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BackupResponse"}}}}},"404":{"description":"Backup schedule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/disable":{"patch":{"tags":["Backups"],"summary":"Disable a backup schedule","operationId":"disable_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Backup schedule disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"404":{"description":"Backup schedule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/enable":{"patch":{"tags":["Backups"],"summary":"Enable a backup schedule","operationId":"enable_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Backup schedule enabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"404":{"description":"Backup schedule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/run":{"post":{"tags":["Backups"],"summary":"Immediately fan-out a run for the given schedule (Run Now).","description":"Creates one `schedule_runs` row, one control-plane backup job, and one\nbackup job per supported external service — all in a single transaction.\nReturns `202 Accepted` with a [`ScheduleRunResponse`] containing the new\n`schedule_run_id` and the list of enqueued jobs. Returns `409 Conflict` if\na run for this schedule is already in flight or if the schedule is disabled.","operationId":"run_schedule_now","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Fan-out run enqueued for async execution","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduleRunResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"409":{"description":"Run already in flight or schedule disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/runs":{"get":{"tags":["Backups"],"summary":"Paginated run history for a backup schedule (one row per scheduler tick).","description":"Returns one [`ScheduleRunSummary`] per scheduler tick, with child backup\ncounts aggregated in a single SQL round-trip. Legacy `backups` rows (pre-\nfan-out) are surfaced as synthetic single-job runs so history does not\ndisappear. Ordered by `started_at DESC` (newest first).\n\nUse `GET /backups/schedule-runs/{run_id}/jobs` to drill into a single run.","operationId":"list_schedule_runs","parameters":[{"name":"page","in":"query","description":"Page number (1-based, defaults to 1, clamped to 1 if < 1).","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"page_size","in":"query","description":"Items per page (defaults to 20, clamped to 100 if > 100).","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Paginated run history for the schedule","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduleRunSummaryList"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/services":{"get":{"tags":["Backups"],"summary":"List the external services attached to a backup schedule.","operationId":"list_schedule_services","parameters":[{"name":"id","in":"path","description":"Schedule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Services attached to this schedule","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ExternalServiceSummary"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Backups"],"summary":"Attach one or more external services to a backup schedule. Idempotent —\nservices that are already attached are silently skipped (`ON CONFLICT\nDO NOTHING`). Returns the count of newly inserted rows + the total\nmembership after the operation.","operationId":"attach_schedule_services","parameters":[{"name":"id","in":"path","description":"Schedule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachScheduleServicesRequest"}}},"required":true},"responses":{"200":{"description":"Services attached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachScheduleServicesResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/services/{service_id}":{"delete":{"tags":["Backups"],"summary":"Detach a single external service from a backup schedule. Idempotent —\nreturns `204` whether or not a row was actually removed.","operationId":"detach_schedule_service","parameters":[{"name":"id","in":"path","description":"Schedule ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"service_id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Service detached (or was not attached)"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/{id}":{"get":{"tags":["Backups"],"summary":"Get a backup by ID","operationId":"get_backup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Backup details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Backups"],"summary":"Permanently delete one terminal backup from object storage and the database.","operationId":"delete_backup","parameters":[{"name":"id","in":"path","description":"Backup UUID","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Backup deleted"},"400":{"description":"Backup artifact cannot be safely attributed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"409":{"description":"Backup is running, referenced, or lacks safe artifact identity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Object storage or database error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/{id}/cancel":{"post":{"tags":["Backups"],"summary":"Cancel a single in-flight backup.","description":"Flips the parent `backups` row + its latest `backup_jobs` row to\n`failed` with reason `\"cancelled by user \"`. The in-process\n`CancellationToken` is observed on the next heartbeat tick (≤5s), so the\nengine exits cleanly and rollback reaps the sidecar. Idempotent: cancelling\nan already-terminal backup is a 200 with `cancelled = 0`.","operationId":"cancel_backup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Cancel processed (idempotent)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelBackupResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/{id}/children":{"get":{"tags":["Backups"],"summary":"List the external-service child backups that belong to a parent backup.","description":"Each entry in `children` corresponds to one `external_service_backups` row,\njoined with `external_services` so the caller receives the service name and\ntype without a second request.\n\nReturns an empty `{ \"children\": [] }` — **not 404** — when the parent\nbackup exists but has no children (e.g. control-plane backups).\nReturns 404 when the parent backup itself does not exist.","operationId":"list_backup_children","parameters":[{"name":"id","in":"path","description":"Integer row id of the parent backup","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Child backup list (may be empty)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChildBackupListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Parent backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/blob":{"get":{"tags":["Blob"],"summary":"List blobs","operationId":"blob_list","parameters":[{"name":"limit","in":"query","description":"Maximum number of items to return","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"prefix","in":"query","description":"Prefix to filter by","required":false,"schema":{"type":"string"}},{"name":"cursor","in":"query","description":"Continuation token for pagination","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of blobs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListBlobsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Blob"],"summary":"Upload a blob","operationId":"blob_put","requestBody":{"description":"Binary blob data","content":{"application/octet-stream":{"schema":{"type":"string"}}},"required":true},"responses":{"201":{"description":"Blob uploaded successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlobResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Blob"],"summary":"Delete blobs","operationId":"blob_delete","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteBlobRequest"}}},"required":true},"responses":{"200":{"description":"Blobs deleted successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteBlobResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/blob/copy":{"post":{"tags":["Blob"],"summary":"Copy a blob to a new location","operationId":"blob_copy","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CopyBlobRequest"}}},"required":true},"responses":{"200":{"description":"Blob copied successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlobResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Source blob not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/blob/disable":{"delete":{"tags":["Blob Management"],"summary":"Disable Blob service","operationId":"blob_disable","responses":{"200":{"description":"Blob service disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DisableBlobResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Blob service not enabled"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/blob/enable":{"post":{"tags":["Blob Management"],"summary":"Enable Blob service","operationId":"blob_enable","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnableBlobRequest"}}},"required":true},"responses":{"200":{"description":"Blob service enabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnableBlobResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/blob/status":{"get":{"tags":["Blob Management"],"summary":"Get Blob service status","operationId":"blob_status","responses":{"200":{"description":"Blob service status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlobStatusResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/blob/update":{"patch":{"tags":["Blob Management"],"summary":"Update Blob service configuration","operationId":"blob_update","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBlobRequest"}}},"required":true},"responses":{"200":{"description":"Blob service updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBlobResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Blob service not enabled"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/blob/{project_id}/{path}":{"get":{"tags":["Blob"],"summary":"Download a blob","operationId":"blob_download","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","description":"Blob path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Blob content"},"404":{"description":"Blob not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"head":{"tags":["Blob"],"summary":"Get blob metadata","operationId":"blob_head","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","description":"Blob path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Blob metadata in headers"},"404":{"description":"Blob not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/cloud":{"delete":{"tags":["Cloud"],"operationId":"disconnect_cloud","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CloudStatus"}}}}},"security":[{"bearer_auth":[]}]}},"/cloud/capability":{"get":{"tags":["Cloud"],"operationId":"get_cloud_capability","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CloudCapability"}}}}},"security":[{"bearer_auth":[]}]}},"/cloud/enroll":{"post":{"tags":["Cloud"],"operationId":"enroll_cloud","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnrollCloudRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CloudStatus"}}}}},"security":[{"bearer_auth":[]}]}},"/cloud/status":{"get":{"tags":["Cloud"],"operationId":"get_cloud_status","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CloudStatus"}}}}},"security":[{"bearer_auth":[]}]}},"/dashboard/projects-analytics":{"get":{"tags":["Events"],"summary":"Get dashboard analytics for multiple projects in a single batch request","description":"Returns unique visitor counts and hourly sparkline data for all requested projects\nusing only 2 SQL queries instead of 2×N per-project queries.","operationId":"get_dashboard_projects_analytics","parameters":[{"name":"project_ids","in":"query","description":"Comma-separated list of project IDs","required":true,"schema":{"type":"string"}},{"name":"start_date","in":"query","description":"Start date for filtering","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved batch analytics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DashboardProjectsAnalyticsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/deployments/activity-graph":{"get":{"tags":["Deployments"],"summary":"Get deployment activity graph showing daily deployment counts\nSimilar to GitHub's contribution graph","operationId":"get_activity_graph","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"days","in":"query","description":"Number of days to include (default: 365)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved activity graph","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivityGraphResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/deployments/{deployment_id}/vulnerability-scan":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_scan_by_deployment","parameters":[{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Scan for the specified deployment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"No scan found for deployment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/deployments/{id}/metrics":{"get":{"tags":["Metrics"],"summary":"Fetch a time-series range for a single metric on a deployment.","operationId":"DeploymentMetricsGetRange","parameters":[{"name":"id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric","in":"query","description":"Metric name, e.g. `\"pg.connections_active\"`.","required":true,"schema":{"type":"string"}},{"name":"range","in":"query","description":"Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`.","required":false,"schema":{"type":"string"}},{"name":"percentile","in":"query","description":"Optional histogram percentile (0–100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile.","required":false,"schema":{"type":["number","null"],"format":"double"}}],"responses":{"200":{"description":"Metric time series data points","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MetricDataPoint"}}}}},"400":{"description":"Invalid query parameters"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/deployments/{id}/metrics/enable":{"patch":{"tags":["Metrics"],"summary":"Enable or disable OTLP metric ingestion for a deployment.","description":"When `enabled=true`, seeds the default container alert rules for the\ndeployment via [`temps_monitoring::seed_default_container_rules`] (idempotent).","operationId":"DeploymentMetricsToggle","parameters":[{"name":"id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToggleDeploymentMetricsRequest"}}},"required":true},"responses":{"200":{"description":"Metrics toggle applied"},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/deployments/{id}/metrics/latest":{"get":{"tags":["Metrics"],"summary":"Fetch the most-recent metric values for a deployment.","operationId":"DeploymentMetricsGetLatest","parameters":[{"name":"id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Map of metric name to latest value","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"number","format":"double"},"propertyNames":{"type":"string"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/dns-providers":{"get":{"tags":["DNS Providers"],"summary":"List all DNS providers","operationId":"list_dns_providers","responses":{"200":{"description":"List of DNS providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DnsProviderResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["DNS Providers"],"summary":"Create a new DNS provider","description":"The provider's credentials will be tested before creation.\nIf the connection test fails, the provider will not be created.","operationId":"create_dns_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDnsProviderRequest"}}},"required":true},"responses":{"201":{"description":"DNS provider created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsProviderResponse"}}}},"400":{"description":"Invalid request or connection test failed"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{id}":{"get":{"tags":["DNS Providers"],"summary":"Get a DNS provider by ID","operationId":"get_dns_provider","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"DNS provider details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsProviderResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["DNS Providers"],"summary":"Update a DNS provider","description":"If new credentials are supplied, they are tested before the update is\npersisted (same as creation) -- otherwise a provider's credentials (and,\nfor Pebble, its target URL) could be swapped for something invalid or\nunsafe without ever going through validation.","operationId":"update_provider","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDnsProviderRequest"}}},"required":true},"responses":{"200":{"description":"DNS provider updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsProviderResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["DNS Providers"],"summary":"Delete a DNS provider","operationId":"delete_dns_provider","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"DNS provider deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{id}/domains":{"get":{"tags":["DNS Providers"],"summary":"List managed domains for a provider","operationId":"list_managed_domains","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of managed domains","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ManagedDomainResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["DNS Providers"],"summary":"Add a managed domain to a provider","operationId":"add_managed_domain","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddManagedDomainApiRequest"}}},"required":true},"responses":{"201":{"description":"Managed domain added","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedDomainResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{id}/test":{"post":{"tags":["DNS Providers"],"summary":"Test provider connection","operationId":"test_provider_connection","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionTestResult"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{id}/zones":{"get":{"tags":["DNS Providers"],"summary":"List zones available in a provider","operationId":"list_provider_zones","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of zones","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ZoneListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{provider_id}/domains/{domain}":{"delete":{"tags":["DNS Providers"],"summary":"Remove a managed domain","operationId":"remove_managed_domain","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Managed domain removed"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["DNS Providers"],"summary":"Update a managed domain's settings (hostname mode, sync opt-in, auto-manage).","operationId":"update_managed_domain","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateManagedDomainApiRequest"}}},"required":true},"responses":{"200":{"description":"Managed domain updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedDomainResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{provider_id}/domains/{domain}/apply-hostname-mode":{"post":{"tags":["DNS Providers"],"summary":"Apply a hostname mode to a managed domain (persist + optional DNS sync +\nroute reload).","operationId":"apply_hostname_mode","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplyHostnameModeRequest"}}},"required":true},"responses":{"200":{"description":"Hostname mode applied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HostnamePreviewResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions or token lacks zone access"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{provider_id}/domains/{domain}/hostname-preview":{"get":{"tags":["DNS Providers"],"summary":"Preview the impact of switching a managed domain's hostname mode.","operationId":"preview_hostname_mode","parameters":[{"name":"mode","in":"query","description":"Target mode: standard|flat","required":true,"schema":{"type":"string"}},{"name":"sync","in":"query","description":"Include DNS record changes","required":false,"schema":{"type":"boolean"}},{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Hostname mode preview","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HostnamePreviewResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{provider_id}/domains/{domain}/verify":{"post":{"tags":["DNS Providers"],"summary":"Verify a managed domain","operationId":"verify_managed_domain","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Domain verification result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedDomainResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]}},"/dns/lookup":{"get":{"tags":["DNS"],"summary":"Lookup DNS A records for a domain","operationId":"lookup_dns_a_records","parameters":[{"name":"domain","in":"query","description":"Domain name to lookup","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved DNS A records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsLookupResponse"}}}},"400":{"description":"Invalid domain name or lookup failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsLookupError"}}}}}}},"/domains":{"get":{"tags":["Domains"],"summary":"List all domains","operationId":"list_domains","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"search","in":"query","description":"Search domains by name (substring match)","required":false,"schema":{"type":["string","null"]},"example":"example.com"}],"responses":{"200":{"description":"Domains retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListDomainsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Domains"],"summary":"Create a new domain","description":"Creates a new domain and automatically requests a Let's Encrypt challenge.\nYou can specify the challenge type (HTTP-01 or DNS-01) in the request.\n\n- **HTTP-01**: Validates domain ownership by placing a file on your web server at `/.well-known/acme-challenge/`\n- **DNS-01**: Validates domain ownership by adding a TXT record to your DNS (required for wildcard domains)","operationId":"create_domain","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDomainRequest"}}},"required":true},"responses":{"201":{"description":"Domain created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/by-host/{hostname}":{"get":{"tags":["Domains"],"summary":"Get domain details by hostname","operationId":"get_domain_by_host","parameters":[{"name":"hostname","in":"path","description":"Domain hostname","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Domain details retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/by-host/{hostname}/cert-status":{"get":{"tags":["Domains"],"summary":"Get on-demand TLS certificate status for a hostname","description":"Returns the current cert lifecycle state for a single hostname (from the\n`domains` row) plus the most recent on-demand issuance attempt (from the\n`on_demand_cert_attempts` audit log). This is the operator's first-line\ndiagnostic, surfaced by `temps domain cert-status` (ADR-018 §5). Returns the\nhostname with `None` fields when no on-demand activity exists for it (never a\n404, so the CLI can render \"no attempts recorded\").","operationId":"get_on_demand_cert_status","parameters":[{"name":"hostname","in":"path","description":"Domain hostname","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"On-demand cert status retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CertStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/on-demand-certs":{"get":{"tags":["Domains"],"summary":"List on-demand TLS certificate attempts","description":"Returns rows from the append-only `on_demand_cert_attempts` audit log\n(ADR-018 §5), newest first, each joined with the current authoritative cert\nstate (`status`, `expiration_time`, `backoff_until`) from the `domains` row.\nThis backs the console \"Certificates\" surface. No certificate or private-key\nmaterial is returned — only audit metadata.","operationId":"list_on_demand_certs","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20}],"responses":{"200":{"description":"On-demand cert attempts retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListOnDemandCertsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain_id}/order":{"get":{"tags":["Domains"],"summary":"Get ACME order for a domain","operationId":"get_domain_order","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Order retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AcmeOrderResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Order not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Domains"],"summary":"Create or recreate ACME order for a domain","description":"Creates a new ACME order with Let's Encrypt for the specified domain.\nIf an order already exists, you should cancel it first using the cancel-order endpoint.\nReturns the challenge details that need to be fulfilled (DNS record or HTTP token).","operationId":"create_or_recreate_order","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Order created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainChallengeResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Domains"],"summary":"Cancel ACME order for a domain","description":"Cancels the current ACME order for a domain and clears all challenge data.\nThis allows you to start over with a new order if the previous one failed or got stuck.","operationId":"cancel_domain_order","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Order cancelled successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain_id}/order/finalize":{"post":{"tags":["Domains"],"summary":"Finalize ACME order for a domain","description":"Finalizes the ACME order by completing the challenge validation and requesting the certificate.\nThis should be called after the challenge has been set up (DNS record added or HTTP token served).","operationId":"finalize_order","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Order finalized successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain or order not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain_id}/setup-dns":{"post":{"tags":["Domains"],"summary":"Setup DNS challenge records automatically using a DNS provider","description":"This endpoint automatically creates the required DNS TXT records for ACME DNS-01 challenge\nvalidation using a configured DNS provider. The domain must have an active DNS challenge\npending (created via POST /domains/{id}/order with dns-01 challenge type).\n\nThis is similar to how email domain DNS records are auto-provisioned.","operationId":"setup_dns_challenge","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupDnsChallengeRequest"}}},"required":true},"responses":{"200":{"description":"DNS records created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupDnsChallengeResponse"}}}},"400":{"description":"Bad request - DNS provider not configured or no challenge pending"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain or DNS provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}":{"get":{"tags":["Domains"],"summary":"Get domain by ID","operationId":"get_domain_by_id","parameters":[{"name":"domain","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Domain retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Domains"],"summary":"Delete a domain","operationId":"delete_domain","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Domain deleted successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/challenge-token":{"get":{"tags":["Domains"],"summary":"Get challenge token for a domain (returns plain text token)","operationId":"get_challenge_token","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Challenge token retrieved successfully","content":{"text/plain":{"schema":{"type":"string"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Challenge not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/http-challenge-debug":{"get":{"tags":["Domains"],"summary":"Get HTTP challenge debug information","description":"Returns detailed debug information for HTTP-01 challenge including:\n- Whether a challenge exists for the domain\n- The challenge token and URL that Let's Encrypt will access\n- DNS resolution information showing where the domain currently points\n\nThis is useful for debugging why HTTP-01 challenges fail.","operationId":"get_http_challenge_debug","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Debug information retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpChallengeDebugResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/provision":{"post":{"tags":["Domains"],"summary":"Provision a domain certificate","operationId":"provision_domain","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Certificate provisioning initiated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProvisionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/renew":{"post":{"tags":["Domains"],"summary":"Renew domain certificate","description":"For HTTP-01 domains: Automatically renews the certificate\nFor DNS-01 domains (wildcards): Creates a new ACME order and returns challenge data","operationId":"renew_domain","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Certificate renewal initiated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProvisionResponse"}}}},"202":{"description":"DNS challenge created - manual action required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainChallengeResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/status":{"get":{"tags":["Domains"],"summary":"Check domain status","operationId":"check_domain_status","parameters":[{"name":"domain","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Domain status retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/drop/inspect":{"post":{"tags":["Projects"],"summary":"Inspect a source ZIP without creating a project or retaining the upload.","operationId":"inspect_drop_archive","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/DropArchiveUpload"}}},"required":true},"responses":{"200":{"description":"Detected deployable project roots","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DropInspectionResponse"}}}},"400":{"description":"Invalid or unsupported archive"}},"security":[{"bearer_auth":[]}]}},"/email-domains":{"get":{"tags":["Email Domains"],"summary":"List all email domains","operationId":"list_email_domains","parameters":[{"name":"provider_id","in":"query","description":"Only return domains belonging to this provider","required":false,"schema":{"type":["integer","null"],"format":"int32"}}],"responses":{"200":{"description":"List of email domains","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EmailDomainResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Email Domains"],"summary":"Create a new email domain","operationId":"create_email_domain","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEmailDomainRequest"}}},"required":true},"responses":{"201":{"description":"Domain created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailDomainWithDnsResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/by-domain/{domain}":{"get":{"tags":["Email Domains"],"summary":"Get an email domain by domain name with DNS records","operationId":"get_domain_by_name","parameters":[{"name":"domain","in":"path","description":"Domain name (e.g., 'mail.example.com')","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Email domain details with DNS records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailDomainWithDnsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/{id}":{"get":{"tags":["Email Domains"],"summary":"Get an email domain by ID with DNS records","operationId":"get_domain","parameters":[{"name":"id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Email domain details with DNS records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailDomainWithDnsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Email Domains"],"summary":"Delete an email domain","operationId":"delete_email_domain","parameters":[{"name":"id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Domain deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/{id}/dns-records":{"get":{"tags":["Email Domains"],"summary":"Get DNS records for an email domain","operationId":"get_domain_dns_records","parameters":[{"name":"id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"DNS records for the domain","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecordResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/{id}/setup-dns":{"post":{"tags":["Email Domains"],"summary":"Setup DNS records for an email domain using a configured DNS provider","operationId":"setup_dns","parameters":[{"name":"id","in":"path","description":"Email Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupDnsRequest"}}},"required":true},"responses":{"200":{"description":"DNS records setup result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupDnsResponse"}}}},"400":{"description":"Invalid request or DNS provider not configured"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/{id}/verify":{"post":{"tags":["Email Domains"],"summary":"Verify an email domain's DNS configuration","operationId":"verify_domain","parameters":[{"name":"id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Domain verification result with DNS records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailDomainWithDnsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-providers":{"get":{"tags":["Email Providers"],"summary":"List all email providers","operationId":"list_email_providers","responses":{"200":{"description":"List of email providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EmailProviderResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Email Providers"],"summary":"Create a new email provider","operationId":"create_email_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEmailProviderRequest"}}},"required":true},"responses":{"201":{"description":"Provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailProviderResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-providers/{id}":{"get":{"tags":["Email Providers"],"summary":"Get an email provider by ID","operationId":"get_email_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Email provider details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailProviderResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Email Providers"],"summary":"Delete an email provider","operationId":"delete_email_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Provider deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Email Providers"],"summary":"Update an email provider","description":"Partial update — any field left out keeps its current value. Most importantly,\nomitting the credential block (`ses_credentials`/`scaleway_credentials`/`smtp_credentials`)\npreserves the stored secret, so operators can rename a provider without re-typing\npasswords. `provider_type` is immutable; to switch providers, delete and recreate.","operationId":"update_email_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEmailProviderRequest"}}},"required":true},"responses":{"200":{"description":"Provider updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailProviderResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"409":{"description":"Provider type mismatch"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-providers/{id}/test":{"post":{"tags":["Email Providers"],"summary":"Test an email provider by sending a test email to the logged-in user","operationId":"test_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestEmailRequest"}}},"required":true},"responses":{"200":{"description":"Test email result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestEmailResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-providers/{id}/tracking/setup":{"post":{"tags":["Email Providers"],"summary":"One-click AWS-side setup of SES event tracking (SNS topic + webhook\nsubscription + SESv2 event destination), using the provider's stored\ncredentials.","operationId":"setup_email_tracking","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Setup completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailTrackingSetupResponse"}}}},"400":{"description":"Provider does not support event tracking"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"502":{"description":"An AWS call failed — the response detail names the failed step"}},"security":[{"bearer_auth":[]}]}},"/email-providers/{id}/tracking/status":{"get":{"tags":["Email Providers"],"summary":"Live status of SES event tracking for a provider","operationId":"get_email_tracking_status","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Event tracking status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailTrackingStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/emails":{"get":{"tags":["Emails"],"summary":"List emails with optional filtering","operationId":"list_emails","parameters":[{"name":"domain_id","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"project_id","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"status","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"from_address","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"page","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"page_size","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"List of emails","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedEmailsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Emails"],"summary":"Send an email","operationId":"send_email","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendEmailRequestBody"}}},"required":true},"responses":{"201":{"description":"Email sent successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendEmailResponseBody"}}}},"400":{"description":"Invalid request or domain not verified"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/emails/events":{"get":{"tags":["Email Tracking"],"summary":"GET /emails/events","operationId":"get_global_events","parameters":[{"name":"event_type","in":"query","description":"Filter by event type (open, click)","required":false,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Paginated tracking events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedEventsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/emails/events/stats":{"get":{"tags":["Email Tracking"],"summary":"GET /emails/events/stats","operationId":"get_global_event_stats","responses":{"200":{"description":"Global tracking statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlobalEventStatsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/emails/stats":{"get":{"tags":["Emails"],"summary":"Get email statistics","operationId":"get_email_stats","parameters":[{"name":"domain_id","in":"query","description":"Optional domain ID to filter stats","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Email statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailStatsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/emails/validate":{"post":{"tags":["Email Validation"],"summary":"Validate an email address","operationId":"validate_email","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateEmailRequest"}}},"required":true},"responses":{"200":{"description":"Email validation result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateEmailResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/emails/{email_id}/track/click/{link_index}":{"get":{"tags":["Email Tracking"],"summary":"Track email link click - redirects to original URL","description":"This endpoint replaces original links in tracked emails.\nNo authentication required - it's called when the recipient clicks a link.","operationId":"track_click","parameters":[{"name":"email_id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}},{"name":"link_index","in":"path","description":"Link index","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"302":{"description":"Redirect to original URL"},"404":{"description":"Link not found"}}}},"/emails/{email_id}/track/open":{"get":{"tags":["Email Tracking"],"summary":"Track email open - returns a 1x1 transparent GIF","description":"This endpoint is embedded as an tag in emails.\nNo authentication required - it's called by the email client.","operationId":"track_open","parameters":[{"name":"email_id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"1x1 transparent tracking pixel"},"404":{"description":"Email not found"}}}},"/emails/{id}":{"get":{"tags":["Emails"],"summary":"Get an email by ID","operationId":"get_email","parameters":[{"name":"id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Email details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Email not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/emails/{id}/tracking":{"get":{"tags":["Email Tracking"],"summary":"Get email tracking summary","operationId":"get_email_tracking","parameters":[{"name":"id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Tracking summary","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailTrackingResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Email not found"}},"security":[{"bearer_auth":[]}]}},"/emails/{id}/tracking/events":{"get":{"tags":["Email Tracking"],"summary":"Get email tracking events","operationId":"get_email_events","parameters":[{"name":"id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}},{"name":"event_type","in":"query","description":"Filter by event type (open, click)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Tracking events","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TrackingEventResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Email not found"}},"security":[{"bearer_auth":[]}]}},"/emails/{id}/tracking/links":{"get":{"tags":["Email Tracking"],"summary":"Get tracked links for an email","operationId":"get_email_links","parameters":[{"name":"id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Tracked links","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TrackedLinkResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Email not found"}},"security":[{"bearer_auth":[]}]}},"/external-services":{"get":{"tags":["External Services"],"summary":"Get all external services","operationId":"list_services","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of external services","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}}},"500":{"description":"Internal server error"}}},"post":{"tags":["External Services"],"summary":"Create new external service","operationId":"create_service","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateExternalServiceRequest"}}},"required":true},"responses":{"201":{"description":"Service created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}}}},"/external-services/available-containers":{"get":{"tags":["External Services"],"summary":"List available Docker containers that can be imported as services","operationId":"list_available_containers","responses":{"200":{"description":"List of available containers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AvailableContainerInfo"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/by-slug/{slug}":{"get":{"tags":["External Services"],"summary":"Get external service details by slug","operationId":"get_service_by_slug","parameters":[{"name":"slug","in":"path","description":"External service slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"External service details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceDetails"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/health-status-batch":{"get":{"tags":["External Services"],"summary":"Current health status for many services at once","description":"Powers the status dot on the Storage list page. Pass a comma-separated\nlist of service IDs via `?ids=1,2,3`. Omit to get every service.","operationId":"list_service_health_statuses","parameters":[{"name":"ids","in":"query","description":"Comma-separated service IDs. Omit for all services.","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Batch of current health statuses","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceHealthStatusBatchResponse"}}}},"500":{"description":"Internal server error"}}}},"/external-services/import":{"post":{"tags":["External Services"],"summary":"Import an existing Docker container as a managed external service","operationId":"import_external_service","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportExternalServiceRequest"}}},"required":true},"responses":{"201":{"description":"Service imported successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/projects/{project_id}":{"get":{"tags":["External Services"],"summary":"List services linked to a project","operationId":"list_project_services","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of services linked to project","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectServiceInfo"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/external-services/projects/{project_id}/environment":{"get":{"tags":["External Services"],"summary":"Get all environment variables for all services linked to a project","operationId":"get_project_service_environment_variables","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Map of service IDs to their environment variables","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"propertyNames":{"type":"integer","format":"int32"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/external-services/providers/metadata":{"get":{"tags":["External Services"],"summary":"Get provider metadata (display names, icons, descriptions)","operationId":"get_providers_metadata","responses":{"200":{"description":"List of provider metadata","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderMetadata"}}}}},"500":{"description":"Internal server error"}}}},"/external-services/providers/metadata/{service_type}":{"get":{"tags":["External Services"],"summary":"Get metadata for a specific provider","operationId":"get_provider_metadata","parameters":[{"name":"service_type","in":"path","description":"Service type (mongodb, postgres, redis, s3)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Provider metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderMetadata"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}}}},"/external-services/types":{"get":{"tags":["External Services"],"summary":"Get available service types","operationId":"get_service_types","responses":{"200":{"description":"List of available service types","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ServiceTypeRoute"}}}}},"500":{"description":"Internal server error"}}}},"/external-services/types/{service_type}/parameters":{"get":{"tags":["External Services"],"summary":"Get parameter schema for a specific service type","operationId":"get_service_type_parameters","parameters":[{"name":"service_type","in":"path","description":"Service type","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Service type parameter schema"},"404":{"description":"Service type not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}":{"get":{"tags":["External Services"],"summary":"Get external service details","operationId":"get_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"External service details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceDetails"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}},"put":{"tags":["External Services"],"summary":"Update external service","operationId":"update_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateExternalServiceRequest"}}},"required":true},"responses":{"200":{"description":"Service updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Invalid request"},"404":{"description":"Service not found"},"409":{"description":"A major upgrade is in progress for this service"},"500":{"description":"Internal server error"}}},"delete":{"tags":["External Services"],"summary":"Delete external service","operationId":"delete_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Service deleted successfully"},"400":{"description":"Cannot delete: service is still linked to projects"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/cluster-health":{"get":{"tags":["External Services"],"summary":"Per-member health for a Postgres HA cluster.","description":"Reads pg_auto_failover's `pgautofailover.node` table from the cluster's\nmonitor (TLS, autoctl_node) and joins each member with its\n`pg_stat_replication` row from the current primary. Returns one row per\ndata member with role/state, sync state, and replay lag.\n\nReturns `200` with `monitor_error` set when the monitor is briefly\nunreachable (UI surfaces it as a banner above the table); the table\nitself is empty in that case. Returns `400` for non-cluster services.","operationId":"get_cluster_health","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Per-member cluster health report","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClusterHealthReportResponse"}}}},"400":{"description":"Service is not a cluster"},"401":{"description":"Unauthorized"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/health-check":{"post":{"tags":["External Services"],"summary":"Run a health check for one service right now","description":"Triggers the same engine-specific probe as the background monitor, writes\na history row, updates the denormalized fields on `external_services`, and\nfires alerts on the Nth consecutive failure (so consecutive-failure state\nstays honest). Returns the fresh snapshot the UI can display immediately.","operationId":"trigger_service_health_check","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Fresh health snapshot after probing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceHealthResponse"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"},"503":{"description":"Health monitor not running on this node"}}}},"/external-services/{id}/health-status":{"get":{"tags":["External Services"],"summary":"Persisted health status for an external service","description":"Returns the latest health probe result recorded by\n`ExternalServiceHealthMonitor`, plus recent check history for sparklines\nand a 24-hour uptime percentage. Safe to poll from the UI every 30s.","operationId":"get_service_health_status","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Max number of recent checks (default 50, max 200)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Current health + recent history","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceHealthResponse"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/members":{"post":{"tags":["External Services"],"summary":"Begin adding a single new member to a running cluster.","description":"Currently only `replica` members can be added at runtime. The\nresponse is **202 Accepted** as soon as the validation passes and\nthe placeholder `service_members` row is inserted. The actual\ncontainer provisioning + DNS registration runs in the background;\npoll `GET /external-services/{id}/members/{member_id}` to watch\n`provisioning_step` advance through the phases.","operationId":"add_cluster_member","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddClusterMemberRequest"}}},"required":true},"responses":{"202":{"description":"Cluster member provisioning started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceMemberInfo"}}}},"400":{"description":"Validation failed (wrong topology, status, or role)"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/members/{member_id}":{"get":{"tags":["External Services"],"summary":"Get a single cluster member's current state.","description":"Used by the add-member page to poll the row every second while the\nbackground provisioning task walks through its phases. The\n`provisioning_step` field advances through `inserting_row` →\n`provisioning_container` → `registering_dns` → `done` (or `failed`\nwith `provisioning_error` set).","operationId":"get_cluster_member","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"member_id","in":"path","description":"Cluster member ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Cluster member details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceMemberInfo"}}}},"404":{"description":"Service or member not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["External Services"],"summary":"Remove a single member from a running cluster.","description":"Refuses to remove the monitor (singleton), the current primary\n(failover first), or any member if the cluster would drop below the\n2-data-member quorum required for HA. Stops + removes the container,\ndeletes the row, and drops the Tier-2 DNS record.","operationId":"remove_cluster_member","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"member_id","in":"path","description":"Cluster member ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Cluster member removed"},"400":{"description":"Validation failed (monitor, primary, or quorum violation)"},"404":{"description":"Service or member not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/members/{member_id}/promote":{"post":{"tags":["External Services"],"summary":"Promote a replica to primary by triggering a pg_auto_failover\nfailover. The monitor demotes the current primary and the chosen\nreplica transitions to primary; the role reconciler then refreshes\nthe role-aliased VIPs (≤30s).","operationId":"promote_cluster_member","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"member_id","in":"path","description":"Cluster member ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Promotion initiated"},"400":{"description":"Validation failed (monitor, already primary, not running, etc.)"},"404":{"description":"Service or member not found"},"500":{"description":"pg_autoctl perform promotion failed"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics":{"get":{"tags":["Metrics"],"summary":"Fetch a time-series range for a single metric on an external service.","description":"Pass `percentile` to compute a histogram quantile instead of a plain\ngauge/counter average.","operationId":"ExternalServiceMetricsGetRange","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric","in":"query","description":"Metric name, e.g. `\"pg.connections_active\"`.","required":true,"schema":{"type":"string"}},{"name":"range","in":"query","description":"Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`.","required":false,"schema":{"type":"string"}},{"name":"percentile","in":"query","description":"Optional histogram percentile (0–100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile.","required":false,"schema":{"type":["number","null"],"format":"double"}}],"responses":{"200":{"description":"Metric time series data points","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MetricDataPoint"}}}}},"400":{"description":"Invalid query parameters"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/alert-rules":{"get":{"tags":["Metrics"],"summary":"List all monitoring alert rules for an external service.","operationId":"ExternalServiceMetricsGetAlertRules","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of alert rules","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ServiceAlertRuleResponse"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Metrics"],"summary":"Create a monitoring alert rule for an external service.","description":"If metric collection is enabled and the service engine has default rules,\nseeding is idempotent (ON CONFLICT DO NOTHING).","operationId":"ExternalServiceMetricsCreateAlertRule","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceCreateAlertRuleRequest"}}},"required":true},"responses":{"201":{"description":"Alert rule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceAlertRuleResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/alert-rules/{rule_id}":{"put":{"tags":["Metrics"],"summary":"Update an existing monitoring alert rule for an external service.","operationId":"ExternalServiceMetricsUpdateAlertRule","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceUpdateAlertRuleRequest"}}},"required":true},"responses":{"200":{"description":"Updated alert rule","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceAlertRuleResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Metrics"],"summary":"Delete a monitoring alert rule for an external service.","operationId":"ExternalServiceMetricsDeleteAlertRule","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Alert rule deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/by-database":{"get":{"tags":["Metrics"],"summary":"Return the latest per-database metric values for a Postgres service.","description":"Groups `pg_stat_database` / size metrics by `datname` so the UI can show a\nbreakdown table (each database with its own size, cache-hit ratio, etc.)\nrather than collapsing every database into one value.","operationId":"ExternalServiceMetricsByDatabase","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Per-database metric breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatabaseMetricsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics not available"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/enable":{"patch":{"tags":["Metrics"],"summary":"Enable or disable metric collection for an external service.","description":"When `enabled=true`, seeds the default alert rules for the service's engine\nvia [`temps_monitoring::seed_default_rules`] (idempotent).","operationId":"ExternalServiceMetricsToggle","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToggleServiceMetricsRequest"}}},"required":true},"responses":{"200":{"description":"Metrics toggle applied"},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/latest":{"get":{"tags":["Metrics"],"summary":"Fetch the most-recent value for every tracked metric on an external service.","operationId":"ExternalServiceMetricsGetLatest","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Map of metric name to latest value","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"number","format":"double"},"propertyNames":{"type":"string"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/status":{"get":{"tags":["Metrics"],"summary":"Return the freshness status (last-received timestamp) for a service.","description":"Cheap O(1) lookup against `service_metrics_status` — used by the UI to show\n\"last received at …\" without scanning the metrics hypertable.","operationId":"ExternalServiceMetricsStatus","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Metrics freshness status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetricsStatusResponse"}}}},"503":{"description":"Metrics not available"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/parameters/{param_name}":{"get":{"tags":["External Services"],"summary":"Reveal one sensitive service parameter. Service detail responses never\ncontain plaintext values; every successful reveal is recorded separately.","operationId":"reveal_service_parameter","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"param_name","in":"path","description":"Sensitive parameter name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sensitive parameter value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensitiveValueResponse"}}}},"400":{"description":"Parameter is not sensitive"},"403":{"description":"Caller cannot access a project linked to this service"},"404":{"description":"Service or parameter not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/preview-environment-masked":{"get":{"tags":["External Services"],"summary":"Get environment variables preview with masked sensitive values","operationId":"get_service_preview_environment_variables_masked","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Preview of environment variables with sensitive values masked as ***","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/preview-environment-names":{"get":{"tags":["External Services"],"summary":"Get environment variable names preview (safe - no sensitive values)","operationId":"get_service_preview_environment_variable_names","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environment variable names that would be provided","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"}}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/projects":{"get":{"tags":["External Services"],"summary":"List projects linked to service","operationId":"list_service_projects","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of linked projects","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectServiceInfo"}}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["External Services"],"summary":"Link service to project","operationId":"link_service_to_project","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkServiceRequest"}}},"required":true},"responses":{"201":{"description":"Service linked to project successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectServiceInfo"}}}},"404":{"description":"Service or project not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/projects/{project_id}":{"delete":{"tags":["External Services"],"summary":"Unlink service from project","operationId":"unlink_service_from_project","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Service unlinked from project successfully"},"404":{"description":"Service link not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/projects/{project_id}/environment":{"get":{"tags":["External Services"],"summary":"Get all environment variables for a service-project pair","operationId":"get_service_environment_variables","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environment variables","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentVariableInfo"}}}}},"404":{"description":"Service or project not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/projects/{project_id}/environment/{var_name}":{"get":{"tags":["External Services"],"summary":"Get specific environment variable for a service-project pair","operationId":"get_service_environment_variable","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"var_name","in":"path","description":"Environment variable name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Environment variable value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableInfo"}}}},"403":{"description":"Plaintext secret access is not permitted"},"404":{"description":"Service, project, or variable not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/resources":{"patch":{"tags":["External Services"],"summary":"Update a service's resource limits (memory, CPU caps).","description":"Persists the new caps to the encrypted config AND live-applies them\nvia Docker's update API. Memory and CPU can be hot-changed without a\nrestart on running containers; stopped containers also accept the\nupdate and pick up the new caps on next start.\n\nPass `null` (or omit) any field to leave it unlimited. A request where\nevery field is `null` removes any existing limits.\n\nThe response includes a per-container `applied[]` list so the caller\ncan tell which members got the update and which were skipped (e.g.,\ncontainer not yet created, or `docker update` rejected because the\nnew memory cap is below current usage).","operationId":"update_service_resources","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceResourceLimits"}}},"required":true},"responses":{"200":{"description":"Updated resource limits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceLimitsUpdateResponse"}}}},"400":{"description":"Invalid resource limits"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/restore":{"post":{"tags":["Restore"],"operationId":"start_restore","parameters":[{"name":"id","in":"path","description":"External service id (source for the restore)","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartRestoreRequest"}}},"required":true},"responses":{"202":{"description":"Restore run started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestoreRunView"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup or service not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/restore-capabilities":{"get":{"tags":["Restore"],"operationId":"get_restore_capabilities","parameters":[{"name":"id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Capabilities declared by the service","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestoreCapabilitiesResponse"}}}},"404":{"description":"Service not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/restore-plan":{"post":{"tags":["Restore"],"operationId":"plan_restore","parameters":[{"name":"id","in":"path","description":"Target service id","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartRestoreRequest"}}},"required":true},"responses":{"200":{"description":"Preview of what the restore will do","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestorePlan"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup or service not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/restore-runs":{"get":{"tags":["Restore"],"operationId":"list_restore_runs_for_service","parameters":[{"name":"id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Recent restore runs for the service","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RestoreRunView"}}}}}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/retry":{"post":{"tags":["External Services"],"summary":"Retry a failed cluster service initialization.","description":"Cleans up any leftover containers from the previous attempt and\nre-runs cluster initialization with the provided member specifications.","operationId":"retry_cluster","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RetryClusterRequest"}}},"required":true},"responses":{"200":{"description":"Cluster retry initiated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Service is not a failed cluster"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/runtime":{"get":{"tags":["External Services"],"summary":"Inspect a service's container(s): status, restart count, OOM-killed flag,\nexit code, and the cgroup limits actually applied.","operationId":"get_service_runtime","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Container runtime snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceRuntimeReport"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/start":{"post":{"tags":["External Services"],"summary":"Start an external service","operationId":"start_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Service started successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"404":{"description":"Service not found"},"409":{"description":"A Postgres major upgrade is in progress for this service"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/stats":{"get":{"tags":["External Services"],"summary":"Sample current CPU/memory usage from each of a service's containers.\nOne-shot sample, no streaming. Cheap to call (single Docker round-trip\nper member) so the UI can poll on a 5–10s interval.","operationId":"get_service_stats","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Container stats snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceStatsReport"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/stop":{"post":{"tags":["External Services"],"summary":"Stop an external service","operationId":"stop_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Service stopped successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/upgrade":{"post":{"tags":["External Services"],"summary":"Upgrade external service to new Docker image with data migration\nThis endpoint uses service-specific upgrade procedures (e.g., pg_upgrade for PostgreSQL)","operationId":"upgrade_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpgradeExternalServiceRequest"}}},"required":true},"responses":{"200":{"description":"Service upgraded successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Invalid request or upgrade not supported"},"404":{"description":"Service not found"},"409":{"description":"A major upgrade is already in progress for this service"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/wal-health":{"get":{"tags":["External Services"],"summary":"Postgres WAL & archive health snapshot","description":"Returns the latest WAL/archive health snapshot recorded by the background\nhealth monitor for a Postgres external service. Powers the warning banner\non the service detail page when the disk is filling up due to stale\nreplication slots, archive backlog, or misconfigured `archive_command`.\n\nReturns 404 when no snapshot exists yet (probe hasn't run, or the service\nisn't Postgres).","operationId":"getPostgresWalHealth","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Latest WAL health snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostgresWalHealth"}}}},"404":{"description":"Service not found, or no WAL snapshot available"},"500":{"description":"Internal server error"}}}},"/external-services/{service_id}/pg-stat-statements/enable":{"post":{"tags":["External Services"],"summary":"Enable `pg_stat_statements` on a standalone Postgres service.","description":"Stops the container and restarts it so that the\n`shared_preload_libraries=pg_stat_statements` CMD flag (baked into every\nnew standalone Postgres container) takes effect. The named data volume is\nreused unchanged — no data is lost.\n\n**Clustered (HA) services are rejected** with 422 — a blind single-container\nrestart bypasses controlled failover. For clustered services the response\nbody describes the manual rolling-restart steps.\n\nConfirmation is the caller's responsibility (UI dialog / CLI `--yes` flag)\nbefore invoking this endpoint.","operationId":"ExternalServiceEnablePgStatStatements","parameters":[{"name":"service_id","in":"path","description":"ID of the provisioned standalone Postgres service","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Container restarted; pg_stat_statements now active","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnablePgStatStatementsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions (requires external_services:write)"},"404":{"description":"Service not found"},"422":{"description":"Service is not standalone Postgres (cluster or wrong type)"},"500":{"description":"Restart failed"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/pg-stat-statements/reset":{"post":{"tags":["External Services"],"summary":"Reset all statistics accumulated by `pg_stat_statements` for a Postgres\nservice. This affects every user, database, and normalized query tracked by\nthe target Postgres instance and cannot be undone.","operationId":"ExternalServiceResetPgStatStatements","parameters":[{"name":"service_id","in":"path","description":"ID of the provisioned Postgres service","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"Explicit confirmation of the global, irreversible reset","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPgStatStatementsRequest"}}},"required":true},"responses":{"200":{"description":"All accumulated pg_stat_statements statistics cleared","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPgStatStatementsResponse"}}}},"400":{"description":"Missing or invalid reset confirmation"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions (requires external_services:write)"},"404":{"description":"Service not found"},"422":{"description":"Service is not Postgres"},"502":{"description":"Target Postgres rejected or failed the reset operation"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/pg-stat-statements/slow-queries":{"get":{"tags":["External Services"],"operationId":"get_slow_queries","parameters":[{"name":"service_id","in":"path","description":"ID of the provisioned Postgres service","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based). Defaults to 1.","required":false,"schema":{"type":["integer","null"],"format":"int32","minimum":0}},{"name":"page_size","in":"query","description":"Number of rows per page (1–100). Defaults to 20.","required":false,"schema":{"type":["integer","null"],"format":"int32","minimum":0}},{"name":"sort_by","in":"query","description":"Column to sort by: one of `calls`, `total_exec_time_ms`,\n`mean_exec_time_ms`, `rows`, `cache_hit_ratio`. Defaults to\n`mean_exec_time_ms`. Applied server-side so ordering stays\nconsistent across pages.","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","description":"Sort direction: `asc` or `desc`. Defaults to `desc`.","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Paginated slow queries from pg_stat_statements","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SlowQueriesResponse"}}}},"400":{"description":"Invalid pagination or sort parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions (requires external_services:read)"},"404":{"description":"Service not found"},"422":{"description":"Service is not a Postgres service"},"503":{"description":"pg_stat_statements extension not available (container restart required)"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers":{"get":{"tags":["External Services - Query"],"summary":"List containers at the root level (databases, keyspaces, etc.)","operationId":"list_root_containers","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of root containers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ContainerResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}":{"get":{"tags":["External Services - Query"],"summary":"List containers at a specific path\nPath segments are separated by forward slashes\nExample: /external-services/1/query/containers/mydb lists schemas in database \"mydb\"","operationId":"list_containers_at_path","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of containers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ContainerResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/entities":{"get":{"tags":["External Services - Query"],"summary":"List entities (tables, collections, etc.) in a container\nExample: /external-services/1/query/containers/mydb/public/entities lists tables in the public schema","operationId":"list_entities","parameters":[{"name":"limit","in":"query","description":"Maximum number of entities to return (default: 100, max: 1000)","required":false,"schema":{"type":"integer","minimum":0}},{"name":"token","in":"query","description":"Continuation token for pagination","required":false,"schema":{"type":"string"}},{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated list of entities","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedEntitiesResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/entities/{entity}":{"get":{"tags":["External Services - Query"],"summary":"Get detailed information about an entity (table schema)","operationId":"get_entity_info","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}},{"name":"entity","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Entity details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntityInfoResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service, container, or entity not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/entities/{entity}/data":{"post":{"tags":["External Services - Query"],"summary":"Query data from an entity with optional filters, pagination, and sorting","operationId":"query_data","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}},{"name":"entity","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryDataRequest"}}},"required":true},"responses":{"200":{"description":"Query results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryDataResponse"}}}},"400":{"description":"Invalid query"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service, container, or entity not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/entities/{entity}/download":{"get":{"tags":["External Services - Query"],"summary":"Download an object (S3 only) as a streaming response","operationId":"download_object","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}},{"name":"entity","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Object data stream","content":{"application/octet-stream":{}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Object not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/info":{"get":{"tags":["External Services - Query"],"summary":"Get information about a specific container","operationId":"get_container_info","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/explorer-support":{"get":{"tags":["External Services - Query"],"summary":"Check if a service supports query explorer functionality","operationId":"check_explorer_support","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Explorer support information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExplorerSupportResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades":{"get":{"tags":["Postgres Upgrades"],"summary":"List recent upgrades for a single service (newest first, page size 50).","operationId":"list_pg_upgrades","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Recent upgrades","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}}},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Postgres Upgrades"],"summary":"Start a new PostgreSQL major-version upgrade for a service.","operationId":"start_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartPgUpgradeRequest"}}},"required":true},"responses":{"201":{"description":"Upgrade started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"400":{"description":"Invalid request"},"409":{"description":"An upgrade is already running for this service"},"412":{"description":"No default S3 source configured"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}":{"get":{"tags":["Postgres Upgrades"],"summary":"Get a single upgrade by id, scoped to a service.","operationId":"get_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Upgrade","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"404":{"description":"Not found"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}/cancel":{"post":{"tags":["Postgres Upgrades"],"summary":"Cancel an in-flight upgrade. The orchestrator stops at its next phase\nboundary; already-terminal upgrades return 409.","operationId":"cancel_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Cancellation requested","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Upgrade already terminal"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}/logs":{"get":{"tags":["Postgres Upgrades"],"summary":"Get the accumulated JSONL log content for an upgrade (for dashboard display).","operationId":"get_pg_upgrade_logs","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Log content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeLogResponse"}}}},"404":{"description":"Not found"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}/retry":{"post":{"tags":["Postgres Upgrades"],"summary":"Retry a failed upgrade. The phase is preserved, so the state machine\nresumes from where it failed.","operationId":"retry_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Retry scheduled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"400":{"description":"Upgrade is not in a retriable state"},"404":{"description":"Not found"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}/rollback":{"post":{"tags":["Postgres Upgrades"],"summary":"Roll a completed upgrade back to its pre-upgrade PGDATA volume and old image.\nOnly valid while the rollback retention window is still open (see\n`ROLLBACK_RETENTION_DAYS`) and the rollback volume has not been swept.","operationId":"rollback_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Rollback complete","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Upgrade is not in a rollbackable state (not completed, volume swept, or retention expired)"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/files/{file_path}":{"get":{"tags":["Files"],"operationId":"get_file","parameters":[{"name":"file_path","in":"path","description":"Relative path to the file from static directory","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"File content retrieved successfully","content":{"application/octet-stream":{}}},"401":{"description":"Authentication required"},"403":{"description":"Access denied - path outside static directory or insufficient permissions"},"404":{"description":"File not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/flags/exposure":{"post":{"tags":["Feature Flags"],"summary":"Record which flags a running app actually evaluated.","description":"This is what makes `last_evaluated_at` mean something. The snapshot\nendpoint hands the SDK every flag in the environment and evaluation then\nhappens locally, so the control plane cannot otherwise tell a flag that is\nreferenced by live code from one nothing has called in a year. Stamping on\nsnapshot fetch would mark every flag as freshly used and defeat the point.\n\nScope comes from the deployment token, never the body. The endpoint writes\nonly `last_evaluated_at` — never a flag's value — so \"a deployment token\ncannot change what a flag serves\" still holds despite this being a write.","operationId":"record_flag_exposure","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecordExposureRequest"}}},"required":true},"responses":{"200":{"description":"Exposure recorded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecordExposureResponse"}}}},"400":{"description":"Deployment token required"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/flags/snapshot":{"get":{"tags":["Feature Flags"],"summary":"Every flag for the caller's environment, collapsed to what the evaluator\nneeds.","description":"Scope comes from the deployment token, never from the URL: a container's\nbaked-in `TEMPS_API_TOKEN` identifies exactly one project (and usually one\nenvironment), so a compromised app cannot read another tenant's flags by\nchanging a path parameter.\n\nSupports `If-None-Match`, so the SDK's background poll is a 304 in the\ncommon case.","operationId":"get_flag_snapshot","parameters":[{"name":"environment_id","in":"query","description":"Required only when the calling token is project-wide rather than scoped\nto a single environment.","required":false,"schema":{"type":["integer","null"],"format":"int32"}}],"responses":{"200":{"description":"Snapshot for the environment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagSnapshotResponse"}}}},"304":{"description":"Snapshot unchanged"},"400":{"description":"Environment could not be determined"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/geo/{ip}":{"get":{"tags":["geo"],"summary":"Get geolocation information for an IP address","operationId":"get_ip_geolocation","parameters":[{"name":"ip","in":"path","description":"IP address to geolocate (IPv4 or IPv6)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Geolocation information retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeoLocationResponse"}}}},"400":{"description":"Invalid IP address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"IP address not found in database","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/git-connections":{"get":{"tags":["Git Providers"],"summary":"List user's git provider connections","operationId":"list_connections","parameters":[{"name":"page","in":"query","description":"Page number for pagination (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Number of items per page (default: 30, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"sort","in":"query","description":"Sort field (created_at, updated_at, account_name)","required":false,"schema":{"type":"string"}},{"name":"direction","in":"query","description":"Sort direction (asc, desc), default: desc","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of connections","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionListResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}":{"delete":{"tags":["Git Providers"],"summary":"Permanently delete a git provider connection","operationId":"delete_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Connection deleted successfully"},"400":{"description":"Connection is in use by projects and cannot be deleted"},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/activate":{"post":{"tags":["Git Providers"],"summary":"Activate a git provider connection","operationId":"activate_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection activated successfully"},"400":{"description":"Provider is deactivated and connection cannot be activated"},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/deactivate":{"post":{"tags":["Git Providers"],"summary":"Deactivate a git provider connection","operationId":"deactivate_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection deactivated successfully"},"400":{"description":"Connection is in use by projects and cannot be deactivated"},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/health-check":{"post":{"tags":["Git Provider Connections"],"summary":"Run an on-demand health check for a git connection.","description":"Probes the upstream (GitHub App, PAT, or OAuth token), persists the result,\nand fires admin notifications on status transitions. Returns the updated\nconnection.","operationId":"run_connection_health_check","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Health check completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/repositories":{"get":{"tags":["Git Providers"],"summary":"List repositories for a specific connection","description":"Fetches repositories from the connected git provider with support for pagination, search, and filtering.\nThis endpoint calls the provider's API directly to get the most up-to-date repository list.","operationId":"list_repositories_by_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"sort","in":"query","description":"Sort field (name, created_at, updated_at, stars, etc.)","required":false,"schema":{"type":"string"}},{"name":"direction","in":"query","description":"Sort direction (asc, desc)","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Search term to filter repositories","required":false,"schema":{"type":"string"}},{"name":"owner","in":"query","description":"Filter by repository owner","required":false,"schema":{"type":"string"}},{"name":"language","in":"query","description":"Filter by programming language","required":false,"schema":{"type":"string"}},{"name":"private","in":"query","description":"Filter by private status (true/false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of repositories","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/sync":{"post":{"tags":["Git Providers"],"summary":"Start a repository sync for a connection","description":"Kicks off a background sync of the connection's repositories from the\nprovider. Returns `202 Accepted` immediately — the caller should poll\nthe connection endpoint for `syncing` / `synced_repository_count`\nupdates rather than waiting on this response. The sync is guarded by\na hard deadline and always releases the `syncing` flag on exit, so a\nclient that disconnects mid-sync will not leave the connection stuck.","operationId":"sync_repositories","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Repository sync started in background","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositorySyncStartedResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"409":{"description":"Sync already in progress"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/update-token":{"post":{"tags":["Git Provider Connections"],"summary":"Update access token for a connection (when tokens expire or are rotated)","operationId":"update_connection_token","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTokenRequest"}}},"required":true},"responses":{"200":{"description":"Token updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTokenResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/validate":{"get":{"tags":["Git Provider Connections"],"summary":"Validate a connection by testing the access token","operationId":"validate_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection validation result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers":{"get":{"tags":["Git Providers"],"summary":"List all git providers","operationId":"list_git_providers","responses":{"200":{"description":"List of providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderResponse"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Git Providers"],"summary":"Create a new git provider configuration","operationId":"create_git_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProviderRequest"}}},"required":true},"responses":{"201":{"description":"Provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/bitbucket":{"post":{"tags":["Git Providers"],"summary":"Create a Bitbucket Cloud provider with access token or app password authentication","operationId":"create_bitbucket_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBitbucketRequest"}}},"required":true},"responses":{"201":{"description":"Bitbucket provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request — missing or invalid auth fields"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/generic":{"post":{"tags":["Git Providers"],"summary":"Create a Generic git provider for self-hosted or arbitrary HTTPS git hosts.\nSupports public repositories (no token) and private repositories (token-based).","operationId":"create_generic_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGenericRequest"}}},"required":true},"responses":{"201":{"description":"Generic git provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request — invalid clone URL or missing fields"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/gitea/pat":{"post":{"tags":["Git Providers"],"summary":"Create a Gitea Personal Access Token provider","operationId":"create_gitea_pat_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGiteaPATRequest"}}},"required":true},"responses":{"201":{"description":"Gitea PAT provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request — invalid URL or missing fields"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/github/pat":{"post":{"tags":["Git Providers"],"summary":"Create a GitHub Personal Access Token provider","operationId":"create_github_pat_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGitHubPATRequest"}}},"required":true},"responses":{"201":{"description":"GitHub PAT provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/gitlab/oauth":{"post":{"tags":["Git Providers"],"summary":"Create a GitLab OAuth provider","operationId":"create_gitlab_oauth_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGitLabOAuthRequest"}}},"required":true},"responses":{"201":{"description":"GitLab OAuth provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/gitlab/pat":{"post":{"tags":["Git Providers"],"summary":"Create a GitLab PAT provider","operationId":"create_gitlab_pat_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGitLabPATRequest"}}},"required":true},"responses":{"201":{"description":"GitLab PAT provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}":{"get":{"tags":["Git Providers"],"summary":"Get a specific git provider","operationId":"get_git_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Provider details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Git Providers"],"summary":"Permanently delete a git provider","operationId":"delete_git_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Provider deleted successfully"},"400":{"description":"Provider has connections and cannot be deleted"},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/activate":{"post":{"tags":["Git Providers"],"summary":"Activate a git provider","operationId":"activate_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Provider activated successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/callback":{"get":{"tags":["Git Providers"],"summary":"Handle OAuth callback for a git provider","operationId":"handle_git_provider_oauth_callback","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"code","in":"query","description":"OAuth authorization code","required":true,"schema":{"type":"string"}},{"name":"state","in":"query","description":"CSRF state token","required":true,"schema":{"type":"string"}}],"responses":{"302":{"description":"Redirect to success page"},"400":{"description":"Bad request"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}}}},"/git-providers/{provider_id}/connections":{"get":{"tags":["Git Providers"],"summary":"Get connections for a specific git provider","operationId":"get_provider_connections","parameters":[{"name":"provider_id","in":"path","description":"Provider ID to get connections for","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of connections for the provider","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ConnectionResponse"}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/credentials":{"patch":{"tags":["Git Providers"],"summary":"Partially update credentials for an existing git provider. Only the fields\nyou send are replaced; omitted fields keep their stored values. Fields that\ndon't apply to the provider's auth method are ignored on the service side.","operationId":"update_git_provider_credentials","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProviderCredentialsRequest"}}},"required":true},"responses":{"200":{"description":"Credentials updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/deactivate":{"post":{"tags":["Git Providers"],"summary":"Deactivate a git provider","operationId":"deactivate_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Provider deactivated successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/deletion-check":{"get":{"tags":["Git Providers"],"summary":"Check if a git provider can be safely deleted","operationId":"check_provider_deletion_safety","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deletion check result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderDeletionCheckResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/oauth/authorize":{"get":{"tags":["Git Providers"],"summary":"Start OAuth flow for a git provider","operationId":"start_git_provider_oauth","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"302":{"description":"Redirect to OAuth provider"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/repositories":{"get":{"tags":["Git Providers"],"summary":"List all repositories for a specific provider","description":"Lists repositories synced to the database across every connection under\nthis provider, with the same pagination/filtering as `/repositories`.","operationId":"list_repositories_by_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"sort","in":"query","description":"Sort field (name, created_at, updated_at, stars, watchers, size, issues)","required":false,"schema":{"type":"string"}},{"name":"direction","in":"query","description":"Sort direction (asc, desc)","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Search term to filter repositories","required":false,"schema":{"type":"string"}},{"name":"owner","in":"query","description":"Filter by repository owner","required":false,"schema":{"type":"string"}},{"name":"language","in":"query","description":"Filter by programming language","required":false,"schema":{"type":"string"}},{"name":"private","in":"query","description":"Filter by private status (true/false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of repositories","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/safe-delete":{"delete":{"tags":["Git Providers"],"summary":"Safely delete a git provider (only if no projects are using it)","operationId":"delete_provider_safely","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Provider successfully deleted"},"400":{"description":"Cannot delete provider because it's in use"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git/public/{provider}/{owner}/{repo}":{"get":{"tags":["Public Repositories"],"summary":"Get information about a public repository (supports GitHub and GitLab)","operationId":"get_public_repository","parameters":[{"name":"provider","in":"path","description":"Git provider (github or gitlab)","required":true,"schema":{"type":"string"}},{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Repository information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicRepositoryInfo"}}}},"400":{"description":"Provider not supported"},"404":{"description":"Repository not found"},"429":{"description":"API rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/git/public/{provider}/{owner}/{repo}/branches":{"get":{"tags":["Public Repositories"],"summary":"Get branches for a public repository (supports GitHub and GitLab)","operationId":"get_public_branches","parameters":[{"name":"provider","in":"path","description":"Git provider (github or gitlab)","required":true,"schema":{"type":"string"}},{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of branches","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BranchListResponse"}}}},"400":{"description":"Provider not supported"},"404":{"description":"Repository not found"},"429":{"description":"API rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/git/public/{provider}/{owner}/{repo}/presets":{"get":{"tags":["Public Repositories"],"summary":"Detect presets for a public repository (supports GitHub and GitLab)","operationId":"detect_public_presets","parameters":[{"name":"provider","in":"path","description":"Git provider (github or gitlab)","required":true,"schema":{"type":"string"}},{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"branch","in":"query","description":"Branch name to detect presets for (default: repository's default branch)","required":false,"schema":{"type":["string","null"]}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Detected presets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicPresetResponse"}}}},"400":{"description":"Provider not supported"},"404":{"description":"Repository or branch not found"},"429":{"description":"API rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/imports/discover":{"post":{"tags":["Imports"],"summary":"Discover workloads from a source","operationId":"discover_workloads","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscoverRequest"}}},"required":true},"responses":{"200":{"description":"List of discovered workloads","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscoverResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/imports/execute":{"post":{"tags":["Imports"],"summary":"Execute an import","operationId":"execute_import","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteImportRequest"}}},"required":true},"responses":{"202":{"description":"Import execution started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteImportResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/imports/plan":{"post":{"tags":["Imports"],"summary":"Create an import plan","operationId":"create_plan","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePlanRequest"}}},"required":true},"responses":{"200":{"description":"Import plan created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePlanResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/imports/sources":{"get":{"tags":["Imports"],"summary":"List available import sources","operationId":"list_sources","responses":{"200":{"description":"List of available import sources","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ImportSourceInfo"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/imports/{session_id}":{"get":{"tags":["Imports"],"summary":"Get import status","operationId":"get_import_status","parameters":[{"name":"session_id","in":"path","description":"Import session ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Import status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Import session not found"}},"security":[{"bearer_auth":[]}]}},"/incidents/{incident_id}":{"get":{"tags":["Status Page"],"summary":"Get an incident by ID","operationId":"get_incident","parameters":[{"name":"incident_id","in":"path","description":"Incident ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved incident","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Incident not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/incidents/{incident_id}/status":{"patch":{"tags":["Status Page"],"summary":"Update incident status","operationId":"update_incident_status","parameters":[{"name":"incident_id","in":"path","description":"Incident ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateIncidentStatusRequest"}}},"required":true},"responses":{"200":{"description":"Incident status updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Incident not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/incidents/{incident_id}/updates":{"get":{"tags":["Status Page"],"summary":"Get incident updates","operationId":"get_incident_updates","parameters":[{"name":"incident_id","in":"path","description":"Incident ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved incident updates","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/IncidentUpdateResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Incident not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes":{"get":{"tags":["Nodes"],"summary":"List all registered nodes (admin — session auth via RequireAuth)","operationId":"admin_list_nodes","responses":{"200":{"description":"List of nodes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodeListResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes/register":{"post":{"tags":["Nodes"],"summary":"Register a new worker node or reconnect an existing one","operationId":"register_node","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterNodeApiRequest"}}},"required":true},"responses":{"200":{"description":"Node reconnected successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterNodeResponse"}}}},"201":{"description":"Node registered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterNodeResponse"}}}},"400":{"description":"Validation error"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}":{"get":{"tags":["Nodes"],"summary":"Get a specific node by ID (admin — session auth via RequireAuth)","operationId":"admin_get_node","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Node details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodeInfoResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Nodes"],"summary":"Remove a node from the cluster entirely. The node should be drained first\nto ensure containers have been rescheduled. If the node still has active\ncontainers, it will be drained automatically before removal.","operationId":"admin_remove_node","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Node removed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoveNodeResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"409":{"description":"Node still has active containers"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes/{node_id}/containers":{"get":{"tags":["Nodes"],"summary":"List all containers running on a specific node","operationId":"admin_list_node_containers","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Containers on this node","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodeContainerListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes/{node_id}/dns/ack":{"post":{"tags":["Internal DNS"],"summary":"`POST /internal/nodes/{node_id}/dns/ack`","operationId":"post_dns_ack","parameters":[{"name":"node_id","in":"path","description":"Node id, must match the bearer token's node","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsAckRequest"}}},"required":true},"responses":{"200":{"description":"ACK accepted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsAckResponse"}}}},"400":{"description":"ACK higher than server generation"},"401":{"description":"Missing or invalid bearer token"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}/dns/changes":{"get":{"tags":["Internal DNS"],"summary":"`GET /internal/nodes/{node_id}/dns/changes?since=N`","operationId":"get_dns_changes","parameters":[{"name":"node_id","in":"path","description":"Node id, must match the bearer token's node","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"since","in":"query","description":"Highest generation the agent has already applied. Pass `0` to\nrequest a full zone snapshot. Defaults to `0` if omitted.","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Diff or full snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsChangesResponse"}}}},"401":{"description":"Missing or invalid bearer token"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}/drain":{"get":{"tags":["Nodes"],"summary":"Get the drain status for a node, including migration progress.","description":"Returns container counts and whether the drain is complete.\nCan be polled to track drain progress.","operationId":"admin_drain_status","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Drain status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DrainStatusResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Nodes"],"summary":"Drain a node: mark it as \"draining\" so no new replicas are scheduled on it,\nand trigger redeployment of all affected environments so their containers\nare rescheduled to healthy nodes.","operationId":"admin_drain_node","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Node drain initiated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DrainNodeResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Nodes"],"summary":"Undrain (reactivate) a node so it can accept new deployments again.\nOnly works for nodes in \"draining\" or \"drained\" status.","operationId":"admin_undrain_node","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Node reactivated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UndrainNodeResponse"}}}},"400":{"description":"Node not in drainable state"},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes/{node_id}/heartbeat":{"post":{"tags":["Nodes"],"summary":"Receive a heartbeat from a worker node","operationId":"node_heartbeat","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HeartbeatApiRequest"}}},"required":true},"responses":{"200":{"description":"Heartbeat received","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HeartbeatResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}/network/peers":{"get":{"tags":["Nodes"],"summary":"`GET /internal/nodes/{node_id}/network/peers`","operationId":"list_peers","parameters":[{"name":"node_id","in":"path","description":"Node id, must match the bearer token's node","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Peer list and self-allocation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PeerListResponse"}}}},"401":{"description":"Missing or invalid bearer token"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}/s3-credentials/{s3_source_id}":{"get":{"tags":["Nodes"],"summary":"Get decrypted S3 credentials for a backup/restore operation.","description":"Agents call this endpoint to receive the S3 credentials they need to upload\nor download backups. The credentials are decrypted from the stored S3 source\nand returned over the authenticated TLS/WireGuard channel.","operationId":"get_s3_credentials","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"s3_source_id","in":"path","description":"S3 source ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"S3 credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3CredentialsResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"S3 source not found"},"500":{"description":"Internal server error"}}}},"/ip-access-control":{"get":{"tags":["IP Access Control"],"summary":"List all IP access control rules","operationId":"list_ip_access_control","parameters":[{"name":"action","in":"query","description":"Filter by action (\"block\" or \"allow\")","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of IP access control rules","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/IpAccessControlResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["IP Access Control"],"summary":"Create a new IP access control rule","operationId":"create_ip_access_control","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIpAccessControlRequest"}}},"required":true},"responses":{"201":{"description":"IP access control rule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IpAccessControlResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"409":{"description":"Duplicate IP address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ip-access-control/check/{ip}":{"get":{"tags":["IP Access Control"],"summary":"Check if an IP address is blocked","operationId":"check_ip_blocked","parameters":[{"name":"ip","in":"path","description":"IP address to check","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"IP block status"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ip-access-control/{id}":{"get":{"tags":["IP Access Control"],"summary":"Get a single IP access control rule by ID","operationId":"get_ip_access_control","parameters":[{"name":"id","in":"path","description":"IP access control rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"IP access control rule details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IpAccessControlResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"IP access control rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["IP Access Control"],"summary":"Delete an IP access control rule","operationId":"delete_ip_access_control","parameters":[{"name":"id","in":"path","description":"IP access control rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"IP access control rule deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"IP access control rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["IP Access Control"],"summary":"Update an IP access control rule","operationId":"update_ip_access_control","parameters":[{"name":"id","in":"path","description":"IP access control rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateIpAccessControlRequest"}}},"required":true},"responses":{"200":{"description":"IP access control rule updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IpAccessControlResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"IP access control rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/kv/del":{"post":{"tags":["KV Store"],"summary":"Delete one or more keys","operationId":"kv_del","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DelRequest"}}},"required":true},"responses":{"200":{"description":"Keys deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DelResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/disable":{"delete":{"tags":["KV Management"],"summary":"Disable KV service","operationId":"kv_disable","responses":{"200":{"description":"KV service disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DisableKvResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"KV service not enabled"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/enable":{"post":{"tags":["KV Management"],"summary":"Enable KV service","operationId":"kv_enable","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnableKvRequest"}}},"required":true},"responses":{"200":{"description":"KV service enabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnableKvResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/expire":{"post":{"tags":["KV Store"],"summary":"Set expiration on a key","operationId":"kv_expire","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExpireRequest"}}},"required":true},"responses":{"200":{"description":"Expiration set","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExpireResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/get":{"post":{"tags":["KV Store"],"summary":"Get a value by key","operationId":"kv_get","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetRequest"}}},"required":true},"responses":{"200":{"description":"Value retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/incr":{"post":{"tags":["KV Store"],"summary":"Increment a numeric value","operationId":"kv_incr","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncrRequest"}}},"required":true},"responses":{"200":{"description":"Value incremented","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncrResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/keys":{"post":{"tags":["KV Store"],"summary":"Get keys matching a pattern","operationId":"kv_keys","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeysRequest"}}},"required":true},"responses":{"200":{"description":"Keys retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeysResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/set":{"post":{"tags":["KV Store"],"summary":"Set a value with optional expiration","operationId":"kv_set","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetRequest"}}},"required":true},"responses":{"200":{"description":"Value set","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/status":{"get":{"tags":["KV Management"],"summary":"Get KV service status","operationId":"kv_status","responses":{"200":{"description":"KV service status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KvStatusResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/ttl":{"post":{"tags":["KV Store"],"summary":"Get time-to-live for a key","operationId":"kv_ttl","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TtlRequest"}}},"required":true},"responses":{"200":{"description":"TTL retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TtlResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/update":{"patch":{"tags":["KV Management"],"summary":"Update KV service configuration","operationId":"kv_update","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateKvRequest"}}},"required":true},"responses":{"200":{"description":"KV service updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateKvResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"KV service not enabled"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/lb/routes":{"get":{"tags":["Load Balancer"],"operationId":"list_routes","responses":{"200":{"description":"List of routes","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RouteResponse"}}}}},"500":{"description":"Internal server error"}}},"post":{"tags":["Load Balancer"],"operationId":"create_route","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRouteRequest"}}},"required":true},"responses":{"201":{"description":"Route created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteResponse"}}}},"400":{"description":"Invalid request"}}}},"/lb/routes/{domain}":{"get":{"tags":["Load Balancer"],"operationId":"get_route","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Route found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteResponse"}}}},"404":{"description":"Route not found"}}},"put":{"tags":["Load Balancer"],"operationId":"update_route","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRouteRequest"}}},"required":true},"responses":{"200":{"description":"Route updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteResponse"}}}},"404":{"description":"Route not found"}}},"delete":{"tags":["Load Balancer"],"operationId":"delete_route","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Route deleted successfully"},"404":{"description":"Route not found"}}}},"/logout":{"post":{"tags":["Authentication"],"operationId":"logout","responses":{"200":{"description":"Successfully logged out"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/logs/context":{"get":{"tags":["Logs"],"summary":"Get context lines surrounding a specific log line","operationId":"get_log_context","parameters":[{"name":"chunk_id","in":"query","description":"Chunk ID","required":true,"schema":{"type":"string"}},{"name":"line_offset","in":"query","description":"Line offset within the chunk","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"lines","in":"query","description":"Context lines before and after (default: 25)","required":false,"schema":{"type":"integer","format":"int32","minimum":0}}],"responses":{"200":{"description":"Context lines","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContextLogsResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Chunk not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/logs/search":{"post":{"tags":["Logs"],"summary":"Search logs with structured filters and full text search","operationId":"search_logs","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchLogsRequest"}}},"required":true},"responses":{"200":{"description":"Search results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchLogsResponse"}}}},"400":{"description":"Invalid search parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/logs/tail":{"get":{"tags":["Logs"],"summary":"Live tail logs via Server-Sent Events","operationId":"tail_logs","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"string"}},{"name":"service","in":"query","description":"Service name","required":true,"schema":{"type":"string"}},{"name":"env","in":"query","description":"Environment","required":true,"schema":{"type":"string"}},{"name":"levels","in":"query","description":"Optional level filters","required":true,"schema":{"type":"array","items":{"type":"string"}}},{"name":"text","in":"query","description":"Optional text filter","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"SSE stream of log lines"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/monitors-health/projects":{"get":{"tags":["Status Page"],"summary":"Get monitor-based health summaries for multiple projects in a single query","operationId":"get_projects_monitor_health","parameters":[{"name":"project_ids","in":"query","description":"Comma-separated list of project IDs","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Health summaries per project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectsMonitorHealthResponse"}}}},"400":{"description":"Invalid parameters"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/monitors/{monitor_id}":{"get":{"tags":["Status Page"],"summary":"Get a monitor by ID","operationId":"get_monitor","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved monitor","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Status Page"],"summary":"Delete a monitor","operationId":"delete_monitor","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Monitor deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/monitors/{monitor_id}/bucketed":{"get":{"tags":["Status Page"],"summary":"Get bucketed status data for a monitor using TimescaleDB","operationId":"get_bucketed_status","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"interval","in":"query","description":"Bucket interval: '5min', 'hourly', or 'daily' (default: hourly)","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601) (default: 24 hours ago)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (ISO 8601) (default: now)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved bucketed status data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusBucketedResponse"}}}},"400":{"description":"Invalid parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/monitors/{monitor_id}/current-status":{"get":{"tags":["Status Page"],"summary":"Get current status and uptime metrics for a monitor","operationId":"get_current_monitor_status","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","description":"Custom start time (ISO 8601) - overrides timeframe","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"Custom end time (ISO 8601)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved current status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CurrentStatusResponse"}}}},"400":{"description":"Invalid time parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/monitors/{monitor_id}/uptime":{"get":{"tags":["Status Page"],"summary":"Get uptime history for a monitor","operationId":"get_uptime_history","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"days","in":"query","description":"Number of days of history (default: 60) - ignored if start_time/end_time provided","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601) - overrides days parameter","required":true,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (ISO 8601) - defaults to now","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved uptime history","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UptimeHistoryResponse"}}}},"400":{"description":"Invalid time parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/nodes/{id}/metrics":{"get":{"tags":["Metrics"],"summary":"Fetch a time-series range for a single metric on a node.","operationId":"NodeMetricsGetRange","parameters":[{"name":"id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric","in":"query","description":"Metric name, e.g. `\"pg.connections_active\"`.","required":true,"schema":{"type":"string"}},{"name":"range","in":"query","description":"Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`.","required":false,"schema":{"type":"string"}},{"name":"percentile","in":"query","description":"Optional histogram percentile (0–100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile.","required":false,"schema":{"type":["number","null"],"format":"double"}}],"responses":{"200":{"description":"Metric time series data points","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MetricDataPoint"}}}}},"400":{"description":"Invalid query parameters"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/notification-preferences":{"get":{"tags":["Notification Preferences"],"summary":"Get notification preferences","operationId":"get_preferences","responses":{"200":{"description":"Successfully retrieved preferences","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationPreferencesResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Notification Preferences"],"summary":"Update notification preferences","operationId":"update_preferences","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePreferencesRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated preferences","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationPreferencesResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Notification Preferences"],"summary":"Delete notification preferences","operationId":"delete_preferences","responses":{"204":{"description":"Successfully deleted preferences"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers":{"get":{"tags":["Notification Providers"],"summary":"List all notification providers","operationId":"list_notification_providers","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Successfully retrieved providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}}},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Notification Providers"],"summary":"Create a new notification provider","operationId":"create_notification_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/cloudflare":{"post":{"tags":["Notification Providers"],"summary":"Create a new Cloudflare Email Sending notification provider","operationId":"create_cloudflare_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCloudflareProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created Cloudflare provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/cloudflare/{id}":{"put":{"tags":["Notification Providers"],"summary":"Update a Cloudflare Email Sending notification provider","operationId":"update_cloudflare_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCloudflareProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated Cloudflare provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/email":{"post":{"tags":["Notification Providers"],"summary":"Create a new Email notification provider","operationId":"create_notification_email_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateNotificationEmailProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created Email provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/email/{id}":{"put":{"tags":["Notification Providers"],"summary":"Update an Email notification provider","operationId":"update_notification_email_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateNotificationEmailProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated Email provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/slack":{"post":{"tags":["Notification Providers"],"summary":"Create a new Slack notification provider","operationId":"create_slack_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSlackProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created Slack provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/slack/{id}":{"put":{"tags":["Notification Providers"],"summary":"Update a Slack notification provider","operationId":"update_slack_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSlackProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated Slack provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/webhook":{"post":{"tags":["Notification Providers"],"summary":"Create a new Webhook notification provider","description":"Webhook providers send notifications as JSON payloads to any HTTP endpoint.\nYou can configure custom headers for authentication (Bearer tokens, API keys, etc.).\nThe webhook will receive a JSON payload with notification details including:\nid, title, message, type, priority, severity, timestamp, and metadata.","operationId":"create_webhook_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created Webhook provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/webhook/{id}":{"put":{"tags":["Notification Providers"],"summary":"Update a Webhook notification provider","operationId":"update_webhook_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWebhookProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated Webhook provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/{id}":{"get":{"tags":["Notification Providers"],"summary":"Get a single notification provider","operationId":"get_notification_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Notification Providers"],"summary":"Update a notification provider","operationId":"update_notification_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid masked provider configuration"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Notification Providers"],"summary":"Delete a notification provider","operationId":"delete_notification_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Successfully deleted provider"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/{id}/config/{field}":{"get":{"tags":["Notification Providers"],"operationId":"reveal_notification_provider_config","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"field","in":"path","description":"Sensitive field, such as password or headers.Authorization","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sensitive provider configuration value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensitiveConfigValueResponse"}}}},"400":{"description":"Field is not revealable"},"403":{"description":"Missing secrets:read permission"},"404":{"description":"Provider or field not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/{id}/test":{"post":{"tags":["Notification Providers"],"summary":"Test a notification provider","operationId":"test_notification_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/orders":{"get":{"tags":["Domains"],"summary":"List all ACME orders","operationId":"list_orders","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Orders retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListOrdersResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/otel/alerts":{"get":{"tags":["Alerts"],"summary":"List alert rules for a project (newest first, paginated).","operationId":"list_alerts","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Alert rules for the project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricAlertsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Alerts"],"summary":"Create a new alert rule for a project.","operationId":"create_alert","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMetricAlertRequest"}}},"required":true},"responses":{"201":{"description":"Alert rule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricAlertRuleResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/alerts/preview":{"post":{"tags":["Alerts"],"summary":"Backtest an anomaly detector over a time range without saving a rule.","description":"Replays the metric against the same band the evaluator would use, returning\nthe per-bucket band + which points would have fired. Powers the form's\n\"would this have fired?\" preview and the explorer band overlay. Read-only.","operationId":"preview_alert","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnomalyPreviewRequest"}}},"required":true},"responses":{"200":{"description":"Per-bucket band + breach points","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnomalyPreviewResponse"}}}},"400":{"description":"Not an anomaly detector / bad input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/alerts/{id}":{"get":{"tags":["Alerts"],"summary":"Fetch a single alert rule by id.","operationId":"get_alert","parameters":[{"name":"id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the lookup)","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alert rule","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricAlertRuleResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Alert rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Alerts"],"summary":"Delete an alert rule.","operationId":"delete_alert","parameters":[{"name":"id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the delete)","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Alert rule deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Alert rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Alerts"],"summary":"Update an alert rule's fields.","operationId":"update_alert","parameters":[{"name":"id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the update)","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMetricAlertRequest"}}},"required":true},"responses":{"200":{"description":"Alert rule updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricAlertRuleResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Alert rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/dashboards":{"get":{"tags":["Dashboards"],"summary":"List dashboards for a project (newest first, paginated).","operationId":"list_dashboards","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Dashboards for the project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelDashboardsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Dashboards"],"summary":"Create a new dashboard for a project.","operationId":"create_dashboard","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDashboardRequest"}}},"required":true},"responses":{"201":{"description":"Dashboard created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelDashboardResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/dashboards/{id}":{"get":{"tags":["Dashboards"],"summary":"Fetch a single dashboard by id.","operationId":"get_dashboard","parameters":[{"name":"id","in":"path","description":"Dashboard ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the lookup)","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Dashboard","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelDashboardResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Dashboard not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Dashboards"],"summary":"Delete a dashboard.","operationId":"delete_dashboard","parameters":[{"name":"id","in":"path","description":"Dashboard ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the delete)","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Dashboard deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Dashboard not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Dashboards"],"summary":"Update a dashboard's name and/or layout.","operationId":"update_dashboard","parameters":[{"name":"id","in":"path","description":"Dashboard ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the update)","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDashboardRequest"}}},"required":true},"responses":{"200":{"description":"Dashboard updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelDashboardResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Dashboard not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/genai/traces":{"get":{"tags":["GenAI"],"summary":"Query GenAI trace summaries — traces containing spans with `gen_ai.*` attributes.","description":"`duration_ms` is the only field guaranteed to be milliseconds. `gen_ai.*`\nspan attributes (e.g. time-to-first-token, token latency) often follow the\nOTel GenAI semantic conventions, which use **seconds** (a fractional\ndouble), not milliseconds — do not read them as ms without converting.","operationId":"query_genai_traces","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"gen_ai_system","in":"query","description":"Filter by AI system (openai, anthropic, etc.)","required":false,"schema":{"type":"string"}},{"name":"gen_ai_model","in":"query","description":"Filter by model (gpt-4, claude-sonnet-4-20250514, etc.)","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max traces to return (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"GenAI trace summaries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenAiTraceSummariesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/genai/traces/{project_id}/{trace_id}":{"get":{"tags":["GenAI"],"summary":"Get GenAI span details for a specific trace.","description":"`duration_ms` is the only field guaranteed to be milliseconds. `gen_ai.*`\nspan attributes (e.g. time-to-first-token, token latency) often follow the\nOTel GenAI semantic conventions, which use **seconds** (a fractional\ndouble), not milliseconds — do not read them as ms without converting.","operationId":"get_genai_trace","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trace_id","in":"path","description":"Trace ID (hex)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"GenAI trace span details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenAiTraceDetailResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/global/traces/{trace_id}":{"get":{"tags":["Traces"],"summary":"Assemble a unified cross-project span waterfall (Phase 2).","description":"Fans out to every project that holds spans for `trace_id` (up to 20\nprojects, 10,000 total spans). Spans are annotated with\n`project_id`/`project_name` and sorted by `start_time ASC`.\n`truncated: true` signals a hit on either cap; `truncated_projects`\nlists the dropped project IDs. See ADR-027 §4 for the full design.","operationId":"getUnifiedTrace","parameters":[{"name":"trace_id","in":"path","description":"Trace ID (32 lowercase hex characters)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Unified cross-project trace waterfall","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnifiedTrace"}}}},"400":{"description":"trace_id is not 32 lowercase hex characters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions or deployment token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/health/{project_id}":{"get":{"tags":["OTel"],"summary":"Get health summaries for a project.","operationId":"get_health","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Health summaries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/insights/{project_id}":{"get":{"tags":["Insights"],"summary":"List anomaly insights for a project.","operationId":"list_insights","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"status","in":"query","description":"Filter by status (active, resolved)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max insights to return (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Insights list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsightsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/logs":{"get":{"tags":["Telemetry Logs"],"summary":"Query log records with optional filters.","operationId":"query_logs","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"severity","in":"query","description":"Filter by severity (TRACE, DEBUG, INFO, WARN, ERROR, FATAL)","required":false,"schema":{"type":"string"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Full-text search in log body (ILIKE)","required":false,"schema":{"type":"string"}},{"name":"trace_id","in":"query","description":"Filter by correlated trace ID","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max logs to return (default: 100, max: 1000)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Log records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LogsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/metric-label-keys":{"get":{"tags":["Telemetry Metrics"],"summary":"List the attribute (label) keys observed on a metric — powers the\nlabel-filter key autocomplete.","operationId":"list_metric_label_keys","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric_name","in":"query","description":"Metric to inspect","required":true,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Window start (RFC 3339); defaults to 24h before end","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"Window end (RFC 3339); defaults to now","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Distinct label keys","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricLabelKeysResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/metric-label-values":{"get":{"tags":["Telemetry Metrics"],"summary":"List the distinct values seen for a label key on a metric — powers value\nautocomplete once a key is chosen.","operationId":"list_metric_label_values","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric_name","in":"query","description":"Metric to inspect","required":true,"schema":{"type":"string"}},{"name":"label_key","in":"query","description":"Label key whose values to list (must match [a-zA-Z0-9_.:-])","required":true,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Window start (RFC 3339); defaults to 24h before end","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"Window end (RFC 3339); defaults to now","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Distinct label values","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricLabelValuesResponse"}}}},"400":{"description":"Invalid label key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/metric-names/{project_id}":{"get":{"tags":["Telemetry Metrics"],"summary":"List distinct metric names for a project.","operationId":"list_metric_names","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of metric names","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricNamesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/metrics":{"get":{"tags":["Telemetry Metrics"],"summary":"Query metrics with time bucketing.","operationId":"query_metrics","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric_name","in":"query","description":"Filter by metric name","required":false,"schema":{"type":"string"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"environment","in":"query","description":"Filter by deployment environment","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"bucket_interval","in":"query","description":"Bucket interval (e.g. '1 hour', '5 minutes')","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max buckets to return (default: 1000)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"metric_type","in":"query","description":"Filter by metric type (gauge, sum, histogram, exponential_histogram, summary)","required":false,"schema":{"type":"string"}},{"name":"aggregation","in":"query","description":"Per-bucket aggregation: avg (default), sum, min, max, count, rate, p50/p95/p99, quantile:0.95","required":false,"schema":{"type":"string"}},{"name":"label_filters","in":"query","description":"Comma-separated key=value data-point label filters (keys must match [a-zA-Z0-9_.:-])","required":false,"schema":{"type":"string"}},{"name":"group_by","in":"query","description":"Comma-separated label keys to group series by","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Metrics data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricsResponse"}}}},"400":{"description":"Invalid label key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/pipeline-stats":{"get":{"tags":["OTel"],"summary":"Get OTel pipeline statistics (admin/system view).","operationId":"get_pipeline_stats","responses":{"200":{"description":"Pipeline statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PipelineStatsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/quota/{project_id}":{"get":{"tags":["OTel"],"summary":"Get storage quota for a project.","operationId":"get_quota","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Storage quota","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuotaResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/trace-summaries":{"get":{"tags":["Traces"],"summary":"Query trace summaries — one row per trace with span count, error count,\nroot span info, and proper trace-level pagination.","operationId":"query_trace_summaries","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trace_id","in":"query","description":"Filter by trace ID","required":false,"schema":{"type":"string"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Filter by status (OK, ERROR)","required":false,"schema":{"type":"string"}},{"name":"min_duration_ms","in":"query","description":"Minimum trace duration in ms","required":false,"schema":{"type":"number","format":"double"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"name_pattern","in":"query","description":"Filter by span name pattern (ILIKE)","required":false,"schema":{"type":"string"}},{"name":"sort_by","in":"query","description":"Sort field: 'start_time' (default) or 'duration'","required":false,"schema":{"type":"string"}},{"name":"sort_order","in":"query","description":"Sort direction: 'asc' or 'desc' (default)","required":false,"schema":{"type":"string"}},{"name":"include_total","in":"query","description":"Compute the `total` count (default: true). Set false to skip the second aggregation when only the page is needed","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Max traces to return (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Trace summaries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TraceSummariesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/traces":{"get":{"tags":["Traces"],"summary":"Query trace spans with optional filters.","description":"Each returned span has a `duration_ms` field (float, milliseconds) — this is\nthe ONLY field guaranteed to be in milliseconds. Spans also carry an\n`attributes` map of raw key/value pairs exactly as reported by the\ninstrumenting library: numeric attribute values may be seconds, milliseconds,\nmicroseconds, or nanoseconds depending on that library's convention, and\nnothing in this response labels the unit. Never assume an attribute's\nnumeric value shares `duration_ms`'s unit, and never state a duration in\nmilliseconds unless it came from a `duration_ms` field.","operationId":"query_traces","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trace_id","in":"query","description":"Filter by trace ID","required":false,"schema":{"type":"string"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Filter by status (OK, ERROR, UNSET)","required":false,"schema":{"type":"string"}},{"name":"min_duration_ms","in":"query","description":"Minimum span duration in ms","required":false,"schema":{"type":"number","format":"double"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Max spans to return (default: 100, max: 1000)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Trace spans","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TracesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/traces/cross-project/{trace_id}":{"get":{"tags":["Traces"],"summary":"Discover sibling projects that share the same `trace_id` (Phase 1 banner).","description":"Returns an empty `siblings` list when the trace is single-project — never\n404. Project names are included so the UI can render navigation links\nwithout a second round-trip. See ADR-027 §3 for the full auth model and\ntopology-disclosure trade-offs.","operationId":"getCrossProjectTraceSiblings","parameters":[{"name":"trace_id","in":"path","description":"Trace ID (32 lowercase hex characters)","required":true,"schema":{"type":"string"}},{"name":"exclude_project_id","in":"query","description":"Project ID to exclude (the caller's own project) so the UI does not render a self-link","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Sibling projects sharing this trace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrossProjectTraceResponse"}}}},"400":{"description":"trace_id is not 32 lowercase hex characters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions or deployment token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/traces/{project_id}/{trace_id}":{"get":{"tags":["Traces"],"summary":"Get all spans for a specific trace.","description":"Each span has a `duration_ms` field (float, milliseconds) — the ONLY field\nguaranteed to be in milliseconds — plus an `attributes` map of raw\nkey/value pairs exactly as the instrumenting library reported them.\nNumeric attribute values (e.g. connection-pool wait times, queue delays)\nmay be in seconds, milliseconds, microseconds, or nanoseconds depending on\nthat library's own convention; this response never labels the unit. When\nexplaining what a span spent time on, only quote milliseconds from\n`duration_ms` (or from `start_time`/`end_time` deltas) — never assume a raw\nattribute number is already in milliseconds.","operationId":"get_trace","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trace_id","in":"path","description":"Trace ID (hex)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Trace spans tree","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TracesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/v1/logs":{"post":{"tags":["OTel Ingest"],"summary":"Ingest log records via OTLP/HTTP protobuf.","description":"Authenticates via API key in header, decompresses, decodes protobuf,\nchecks rate limit and storage quota, routes high-severity logs\nto DB and all logs to S3.","operationId":"ingest_logs","requestBody":{"description":"OTLP ExportLogsServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Logs accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/metrics":{"post":{"tags":["OTel Ingest"],"summary":"Ingest metrics via OTLP/HTTP protobuf.","description":"Authenticates via API key in header, decompresses, decodes protobuf,\nchecks rate limit and storage quota, then stores.","operationId":"ingest_metrics","requestBody":{"description":"OTLP ExportMetricsServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Metrics accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/traces":{"post":{"tags":["OTel Ingest"],"summary":"Ingest trace spans via OTLP/HTTP protobuf.","description":"Authenticates via API key in header, decompresses, decodes protobuf,\nchecks rate limit and storage quota, then stores spans.","operationId":"ingest_traces","requestBody":{"description":"OTLP ExportTraceServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Traces accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/{project_id}/{environment_id}/{deployment_id}/logs":{"post":{"tags":["OTel Ingest"],"summary":"Ingest log records with project/environment/deployment in the URL path.","operationId":"ingest_logs_by_path","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"OTLP ExportLogsServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Logs accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/{project_id}/{environment_id}/{deployment_id}/metrics":{"post":{"tags":["OTel Ingest"],"summary":"Ingest metrics with project/environment/deployment in the URL path.","operationId":"ingest_metrics_by_path","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"OTLP ExportMetricsServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Metrics accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/{project_id}/{environment_id}/{deployment_id}/traces":{"post":{"tags":["OTel Ingest"],"summary":"Ingest trace spans with project/environment/deployment in the URL path.","operationId":"ingest_traces_by_path","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"OTLP ExportTraceServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Traces accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/performance/has-metrics":{"get":{"tags":["Performance"],"summary":"Check if performance metrics exist for a project","operationId":"has_performance_metrics","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully checked performance metrics availability","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HasMetricsResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/performance/metrics":{"get":{"tags":["Performance"],"summary":"Get performance metrics","operationId":"get_performance_metrics","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Deployment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"device_type","in":"query","description":"Device type filter: desktop or mobile (optional)","required":false,"schema":{"type":"string"}},{"name":"include_bots","in":"query","description":"Include crawler/datacenter bot samples (default false)","required":false,"schema":{"type":"boolean"}},{"name":"filter_path","in":"query","description":"Filter to one page pathname (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_country","in":"query","description":"Filter to one country (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Filter to one region (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Filter to one city (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_browser","in":"query","description":"Filter to one browser (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_operating_system","in":"query","description":"Filter to one operating system (optional)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved performance metrics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PerformanceMetricsResponse"}}}},"400":{"description":"Invalid date format or missing parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/performance/metrics-over-time":{"get":{"tags":["Performance"],"summary":"Get metrics over time","operationId":"get_metrics_over_time","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DDTHH:MM:SSZ","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DDTHH:MM:SSZ","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Deployment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"device_type","in":"query","description":"Device type filter: desktop or mobile (optional)","required":false,"schema":{"type":"string"}},{"name":"include_bots","in":"query","description":"Include crawler/datacenter bot samples (default false)","required":false,"schema":{"type":"boolean"}},{"name":"filter_path","in":"query","description":"Filter to one page pathname (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_country","in":"query","description":"Filter to one country (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Filter to one region (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Filter to one city (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_browser","in":"query","description":"Filter to one browser (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_operating_system","in":"query","description":"Filter to one operating system (optional)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved metrics over time","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetricsOverTimeResponse"}}}},"400":{"description":"Invalid date format or missing parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/performance/page-metrics":{"get":{"tags":["Performance"],"summary":"Get grouped page metrics","operationId":"get_grouped_page_metrics","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DDTHH:MM:SSZ","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DDTHH:MM:SSZ","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Deployment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"group_by","in":"query","description":"Group by: path, country, region, city, device_type, browser, operating_system","required":true,"schema":{"type":"string"}},{"name":"device_type","in":"query","description":"Device type filter: desktop or mobile (optional)","required":false,"schema":{"type":"string"}},{"name":"include_bots","in":"query","description":"Include crawler/datacenter bot samples (default false)","required":false,"schema":{"type":"boolean"}},{"name":"filter_path","in":"query","description":"Filter to one page pathname (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_country","in":"query","description":"Filter to one country (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Filter to one region (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Filter to one city (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_browser","in":"query","description":"Filter to one browser (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_operating_system","in":"query","description":"Filter to one operating system (optional)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved grouped page metrics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroupedPageMetricsResponse"}}}},"400":{"description":"Invalid date format, missing parameters, or invalid group_by value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/platform/access-info":{"get":{"tags":["Platform"],"summary":"Get information about how the service is being accessed","description":"Returns details about the server's access mode, public IP address, private IP address,\nand domain creation capabilities. Both IP addresses are always included when available.","operationId":"get_access_info","responses":{"200":{"description":"Service access information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceAccessInfo"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/platform/private-ip":{"get":{"tags":["Platform"],"summary":"Get private/local IP address of the server","operationId":"get_private_ip","responses":{"200":{"description":"Successfully retrieved private IP address"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/platform/public-ip":{"get":{"tags":["Platform"],"summary":"Get public IP address of the server","operationId":"get_public_ip","responses":{"200":{"description":"Successfully retrieved public IP address"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/presets":{"get":{"tags":["Presets"],"summary":"List all available presets","operationId":"list_presets","responses":{"200":{"description":"List of available presets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListPresetsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/presets/{slug}/dockerfile":{"post":{"tags":["Presets"],"summary":"Generate a Dockerfile from a preset","description":"Returns the Dockerfile content and build arguments for a given preset slug.\nThe CLI can use this to build Docker images locally without needing a Dockerfile\nin the project directory, enabling zero-config deployments.","operationId":"generate_preset_dockerfile","parameters":[{"name":"slug","in":"path","description":"Preset slug (e.g., nextjs, vite, python)","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateDockerfileRequest"}}},"required":true},"responses":{"200":{"description":"Generated Dockerfile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateDockerfileResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Preset not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/logs":{"get":{"tags":["Preview Gateway"],"operationId":"get_preview_gateway_logs","parameters":[{"name":"tail","in":"query","description":"Lines to tail (default 200, max 2000)","required":false,"schema":{"type":"integer","minimum":0}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LogsResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/restart":{"post":{"tags":["Preview Gateway"],"operationId":"restart_preview_gateway","responses":{"204":{"description":"Gateway restarted"}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/settings":{"get":{"tags":["Preview Gateway"],"operationId":"get_preview_gateway_settings","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewGatewaySettingsResponse"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Preview Gateway"],"operationId":"patch_preview_gateway_settings","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PatchSettingsRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewGatewaySettingsResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/status":{"get":{"tags":["Preview Gateway"],"operationId":"get_preview_gateway_status","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayStatus"}}}}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/upgrade":{"post":{"tags":["Preview Gateway"],"operationId":"upgrade_preview_gateway","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpgradeRequest"}}},"required":true},"responses":{"204":{"description":"Gateway upgraded"}},"security":[{"bearer_auth":[]}]}},"/projects":{"get":{"tags":["Projects"],"summary":"Get a list of all projects","operationId":"get_projects","parameters":[{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"per_page","in":"query","description":"Number of items per page","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"List of projects","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedProjectList"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Projects"],"summary":"Create a new project","operationId":"create_project","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectRequest"}}},"required":true},"responses":{"200":{"description":"Project created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"400":{"description":"Invalid input"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/by-slug/{slug}":{"get":{"tags":["Projects"],"summary":"Get details of a specific project by slug","operationId":"get_project_by_slug","parameters":[{"name":"slug","in":"path","description":"Project slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Project details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]}},"/projects/from-template":{"post":{"tags":["Projects"],"summary":"Create a new project from a template","description":"Creates a new repository from a template and sets up the project with the\nspecified configuration. The template is cloned to a new repository under\nthe authenticated user's account or specified organization.","operationId":"create_project_from_template","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectFromTemplateRequest"}}},"required":true},"responses":{"201":{"description":"Project created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectFromTemplateResponse"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Template not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/statistics":{"get":{"tags":["Projects"],"summary":"Get project statistics","operationId":"get_project_statistics","responses":{"200":{"description":"Project statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectStatisticsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{id}":{"get":{"tags":["Projects"],"summary":"Get details of a specific project","operationId":"get_project","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Project details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Projects"],"operationId":"update_project","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectRequest"}}},"required":true},"responses":{"200":{"description":"Project updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Projects"],"operationId":"delete_project","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Project deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{id}/deployments":{"get":{"tags":["Projects"],"operationId":"get_project_deployments","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"per_page","in":"query","description":"Items per page","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"environment_id","in":"query","description":"Environment ID filter","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of deployments","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentListResponse"}}}},"404":{"description":"Project not found"}}}},"/projects/{id}/last-deployment":{"get":{"tags":["Deployments"],"summary":"Get the last deployment for a specific project","operationId":"get_last_deployment","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Last deployment details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentResponse"}}}},"404":{"description":"Project not found or no deployments"},"500":{"description":"Internal server error"}}}},"/projects/{id}/source":{"patch":{"tags":["Projects"],"summary":"Change a project's source type to a Git-less type (docker_image /\nstatic_files / manual). Switching TO Git is done via the Git settings\nendpoint (`POST /projects/{id}/git`), which also supplies the repository and\nprovider connection.","operationId":"change_project_source","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeProjectSourceRequest"}}},"required":true},"responses":{"200":{"description":"Source type changed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"400":{"description":"Invalid source type change (e.g. switching to Git here)"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{id}/trigger-pipeline":{"post":{"tags":["Projects"],"summary":"Trigger pipeline for a specific project","operationId":"trigger_project_pipeline","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerPipelinePayload"}}},"required":true},"responses":{"200":{"description":"Pipeline triggered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerPipelineResponse"}}}},"400":{"description":"Invalid request"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/access":{"get":{"tags":["Teams"],"operationId":"list_project_access","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Access grants","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectAccessResponse"}}}}},"403":{"description":"Insufficient permissions or no access to this project"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Teams"],"operationId":"grant_project_access","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectAccessRequest"}}},"required":true},"responses":{"201":{"description":"Access granted (idempotent upsert)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectAccessResponse"}}}},"403":{"description":"Insufficient permissions or no access to this project"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/access/{team_id}":{"delete":{"tags":["Teams"],"operationId":"revoke_project_access","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Access revoked"},"403":{"description":"Insufficient permissions or no access to this project"},"404":{"description":"Grant not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/active-visitors":{"get":{"tags":["Events"],"summary":"Get active visitors count","operationId":"get_active_visitors","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved active visitors count","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActiveVisitorsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents":{"get":{"tags":["Agents"],"operationId":"list_agents","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of agents for project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListAgentsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertAgentRequest"}}},"required":true},"responses":{"201":{"description":"Agent created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentConfigResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/cli-status":{"get":{"tags":["Agents"],"operationId":"get_cli_status","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"provider","in":"query","description":"AI provider: claude_cli or codex_cli","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"CLI status"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs":{"get":{"tags":["Agents"],"operationId":"list_all_runs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of all agent runs for a project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListRunsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/latest-for-source":{"get":{"tags":["Agents"],"operationId":"latest_run_for_source","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trigger_source_type","in":"query","description":"Trigger source type, e.g. 'error_group'","required":true,"schema":{"type":"string"}},{"name":"trigger_source_id","in":"query","description":"Trigger source ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Latest matching run, or null if none","content":{"application/json":{"schema":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AgentRunResponse"}]}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/{run_id}":{"get":{"tags":["Agents"],"operationId":"get_run_with_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Run with logs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunWithLogsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/{run_id}/cancel":{"post":{"tags":["Agents"],"operationId":"cancel_run","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Agent run ID to cancel","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Run cancelled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunResponse"}}}},"400":{"description":"Run is already in a terminal state"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/{run_id}/retry":{"post":{"tags":["Agents"],"summary":"Retry a completed, failed, cancelled, or no_fix run with the same trigger context.\nCreates a new run record and spawns the executor.","operationId":"retry_run","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID to retry","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"New run created from retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunResponse"}}}},"400":{"description":"Run is still active"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/{run_id}/stream":{"get":{"tags":["Agents"],"summary":"SSE endpoint for real-time streaming of run events.\nPolls the agent_run_logs table every 500ms for new entries and streams them.\nCloses when the run reaches a terminal status.","operationId":"stream_run_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Agent run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Server-Sent Events stream of run log events and terminal status","content":{"text/event-stream":{}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/sandbox-status":{"get":{"tags":["Agents"],"operationId":"get_sandbox_status","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Project-scoped sandbox readiness (Docker + agent image)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/smoke-test":{"post":{"tags":["Agents"],"summary":"Run a smoke test to verify the selected AI CLI works in the environment\nwhere agents will actually execute (host or sandbox container). If no\n`provider_id` is supplied the globally active provider is tested.","operationId":"smoke_test_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"provider_id","in":"query","description":"Provider id to test; defaults to the globally active provider","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Smoke test result for the AI CLI in the agent's execution environment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SmokeTestResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/{slug}":{"get":{"tags":["Agents"],"operationId":"get_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Agent config","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentConfigResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertAgentRequest"}}},"required":true},"responses":{"200":{"description":"Agent updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentConfigResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Agent deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/{slug}/runs":{"get":{"tags":["Agents"],"operationId":"list_agent_runs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of runs for a specific agent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListRunsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/{slug}/trigger":{"post":{"tags":["Agents"],"operationId":"trigger_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerAgentRequest"}}},"required":true},"responses":{"202":{"description":"Agent run created and queued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"402":{"description":"Daily budget exceeded"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"},"422":{"description":"AI CLI not installed"},"429":{"description":"Cooldown active"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/aggregated-buckets":{"get":{"tags":["Events"],"summary":"Get aggregated metrics by time bucket","operationId":"get_aggregated_buckets","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for the query range","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for the query range","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Optional environment filter","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Optional deployment filter","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors (default: events)","required":false,"schema":{"type":"string"}},{"name":"bucket_size","in":"query","description":"Time bucket size: '1 hour', '1 day', '1 week', etc. (default: '1 hour')","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved aggregated buckets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AggregatedBucketsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations":{"get":{"tags":["AI Chat"],"summary":"Find the existing chat for a context (returns `null` if none yet). Requires\nthe per-project `ai_debug_chat_enabled` toggle to be on; returns 403 when the\nfeature is disabled so revoking it consistently hides existing chat content.","operationId":"find_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"context_type","in":"query","required":true,"schema":{"type":"string"}},{"name":"context_id","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ConversationResponse"}]}}}},"401":{"description":""},"403":{"description":""}},"security":[{"bearer_auth":[]}]},"post":{"tags":["AI Chat"],"summary":"Get-or-create the chat for a context (seeds it on first open).","operationId":"create_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateConversationRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/list":{"get":{"tags":["AI Chat"],"summary":"List all active conversations for a project, most-recently-active first.\nPowers the conversation switcher in the AI assistant sidebar.","operationId":"list_conversations","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ConversationResponse"}}}}},"401":{"description":""},"403":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/{public_id}":{"get":{"tags":["AI Chat"],"summary":"Full conversation history (excluding the internal system seed).","operationId":"get_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationDetailResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["AI Chat"],"summary":"Rename a conversation (set its human-facing title).","operationId":"rename_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenameConversationRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationResponse"}}}},"400":{"description":""},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/{public_id}/archive":{"post":{"tags":["AI Chat"],"summary":"Archive (soft-delete) a conversation.","operationId":"archive_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":""},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/{public_id}/messages":{"post":{"tags":["AI Chat"],"summary":"Send a user message; stream the assistant reply as Server-Sent Events.","operationId":"send_message","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendMessageRequest"}}},"required":true},"responses":{"200":{"description":"SSE stream of assistant text deltas","content":{"text/event-stream":{}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/{public_id}/pending-actions":{"get":{"tags":["AI Chat"],"summary":"List all pending actions for a conversation (most-recently-proposed first).","operationId":"list_pending_actions","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","description":"Conversation public id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PendingActionResponse"}}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/pending-actions/{action_public_id}":{"get":{"tags":["AI Chat"],"summary":"Get a single pending action by its public id (scoped to the project).","operationId":"get_pending_action","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"action_public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PendingActionResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/pending-actions/{action_public_id}/confirm":{"post":{"tags":["AI Chat"],"summary":"Confirm a proposed AI action: validate permission, atomically claim, execute,\npersist outcome. The execution uses the CONFIRMING user's auth — never the model's.","operationId":"confirm_pending_action","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"action_public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PendingActionResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""},"409":{"description":""},"503":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/pending-actions/{action_public_id}/reject":{"post":{"tags":["AI Chat"],"summary":"Reject a proposed AI action (no execution). Status transitions to \"rejected\".","operationId":"reject_pending_action","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"action_public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PendingActionResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""},"409":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/readiness":{"get":{"tags":["AI Chat"],"summary":"Report which AI prerequisites this project satisfies.","description":"Read-only and cheap, so the UI can decide up front whether to show a working\nentry point, an onboarding path, or nothing — instead of letting the user\nclick something that fails with a 409 they can't act on.","operationId":"get_chat_readiness","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Which AI prerequisites are met","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatReadinessResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/alarms":{"get":{"tags":["Alarms"],"summary":"List alarms for a project with optional filters.","operationId":"listProjectAlarms","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"alarm_type","in":"query","description":"Filter by alarm type (e.g. `container_restart`, `outage`).","required":false,"schema":{"type":["string","null"]}},{"name":"status","in":"query","description":"Filter by status: `firing`, `acknowledged`, or `resolved`.","required":false,"schema":{"type":["string","null"]}},{"name":"severity","in":"query","description":"Filter by severity: `info`, `warning`, or `critical`.","required":false,"schema":{"type":["string","null"]}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"service_id","in":"query","description":"Filter by external service ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based, default 1).","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default 20, max 100).","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"Paginated list of alarms","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlarmListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/alarms/summary":{"get":{"tags":["Alarms"],"summary":"Get alarm counts by status/severity/type for a project (dashboard summary widget).","operationId":"getProjectAlarmsSummary","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alarm summary counts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlarmSummaryResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/alarms/{alarm_id}/acknowledge":{"post":{"tags":["Alarms"],"summary":"Acknowledge a firing alarm (marks it as seen but not resolved).","operationId":"acknowledgeAlarm","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"alarm_id","in":"path","description":"Alarm ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alarm acknowledged"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Alarm not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/alarms/{alarm_id}/resolve":{"post":{"tags":["Alarms"],"summary":"Resolve an alarm.","operationId":"resolveAlarm","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"alarm_id","in":"path","description":"Alarm ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alarm resolved"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Alarm not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/analyze":{"post":{"tags":["Autofixer"],"summary":"Start an autofixer analysis run for the given error group.\nCreates the run record immediately and spawns analysis in the background.","operationId":"start_analysis","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartAnalysisRequest"}}},"required":true},"responses":{"202":{"description":"Analysis started; returns run_id for streaming","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutofixerRunResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}":{"get":{"tags":["Autofixer"],"summary":"Get a single autofixer run with its logs.","operationId":"get_run","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Run with logs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutofixerRunWithLogsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/add-context":{"post":{"tags":["Autofixer"],"summary":"Append a user message to the run's context field.","operationId":"add_context","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddContextRequest"}}},"required":true},"responses":{"200":{"description":"Context appended"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/cancel":{"post":{"tags":["Autofixer"],"summary":"Cancel an autofixer run and clean up the work directory.","operationId":"cancel","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Run cancelled"},"400":{"description":"Run is already in a terminal state"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/create-pr":{"post":{"tags":["Autofixer"],"summary":"Push the fix branch and create a pull request.\nRequires phase == \"fix_ready\".","operationId":"create_pr","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"201":{"description":"PR created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePrResponse"}}}},"400":{"description":"Run not in fix_ready phase"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/fix":{"post":{"tags":["Autofixer"],"summary":"Transition from analysis to fix phase.\nRequires phase == \"analyzed\".","operationId":"start_fix","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Fix generation started"},"400":{"description":"Run not in analyzed phase"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/re-analyze":{"post":{"tags":["Autofixer"],"summary":"Continue the conversation with user feedback.\nUses the same Claude session (--continue) in the existing work directory.\nRequires phase == \"analyzed\".","operationId":"re_analyze","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Conversation continued with feedback"},"400":{"description":"Run not in analyzed phase"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/stream":{"get":{"tags":["Agents"],"summary":"SSE endpoint: streams run log events in real-time.\nPolls every 500 ms. Keeps the connection open through \"analyzed\" and \"fix_ready\"\nwaiting states; closes only on terminal statuses.","operationId":"stream_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Autofixer run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Server-Sent Events stream of autofixer run logs and status updates","content":{"text/event-stream":{}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/automatic-deploy":{"post":{"tags":["Projects"],"summary":"Update automatic deployment setting for a project","operationId":"update_automatic_deploy","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAutomaticDeployRequest"}}},"required":true},"responses":{"200":{"description":"Automatic deployment setting updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/custom-domains":{"get":{"tags":["Custom Domains"],"summary":"List all custom domains for a project","operationId":"list_custom_domains_for_project","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Custom domains retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListCustomDomainsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Custom Domains"],"summary":"Create a custom domain for a project","operationId":"create_custom_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainRequest"}}},"required":true},"responses":{"201":{"description":"Custom domain created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainResponse"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"409":{"description":"Domain already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/custom-domains/{domain_id}":{"get":{"tags":["Custom Domains"],"summary":"Get a custom domain by ID","operationId":"get_custom_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Custom domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Custom domain retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Custom domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Custom Domains"],"summary":"Update a custom domain","operationId":"update_custom_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Custom domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCustomDomainRequest"}}},"required":true},"responses":{"200":{"description":"Custom domain updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainResponse"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"404":{"description":"Custom domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Custom Domains"],"summary":"Delete a custom domain","operationId":"delete_custom_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Custom domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Custom domain deleted successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Custom domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/custom-domains/{domain_id}/link-certificate/{certificate_id}":{"post":{"tags":["Custom Domains"],"summary":"Link a custom domain to a certificate","operationId":"link_custom_domain_to_certificate","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Custom domain ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"certificate_id","in":"path","description":"Certificate ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Custom domain linked to certificate successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Custom domain or certificate not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployment-config":{"patch":{"tags":["Projects"],"summary":"Update deployment configuration for a project","operationId":"update_project_deployment_config","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDeploymentConfigRequest"}}},"required":true},"responses":{"200":{"description":"Deployment configuration updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"400":{"description":"Invalid deployment configuration"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployment-tokens":{"get":{"tags":["Deployment Tokens"],"summary":"List all deployment tokens for a project","operationId":"list_deployment_tokens","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of deployment tokens","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentTokenListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Deployment Tokens"],"summary":"Create a new deployment token for a project","operationId":"create_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDeploymentTokenRequest"}}},"required":true},"responses":{"201":{"description":"Deployment token created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDeploymentTokenResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"409":{"description":"Token with this name already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployment-tokens/{token_id}":{"get":{"tags":["Deployment Tokens"],"summary":"Get a specific deployment token","operationId":"get_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"token_id","in":"path","description":"Deployment token ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment token details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment token not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Deployment Tokens"],"summary":"Delete a deployment token","operationId":"delete_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"token_id","in":"path","description":"Deployment token ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Deployment token deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment token not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Deployment Tokens"],"summary":"Update a deployment token","operationId":"update_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"token_id","in":"path","description":"Deployment token ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDeploymentTokenRequest"}}},"required":true},"responses":{"200":{"description":"Deployment token updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentTokenResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment token not found"},"409":{"description":"Token with this name already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployment-tokens/{token_id}/rotate":{"post":{"tags":["Deployment Tokens"],"summary":"Rotate a deployment token, invalidating its old secret and issuing a new one","operationId":"rotate_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"token_id","in":"path","description":"Deployment token ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment token rotated successfully; the response contains the new plaintext token, shown only once","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDeploymentTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment token not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployments/{deployment_id}":{"get":{"tags":["Deployments"],"summary":"Get a specific deployment by ID for a project (identified by ID or slug)","operationId":"get_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentResponse"}}}},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/cancel":{"post":{"tags":["Projects"],"summary":"Cancel a deployment","operationId":"cancel_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment cancelled successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentStateResponse"}}}},"400":{"description":"Deployment cannot be cancelled (already completed, failed, or cancelled)"},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/container-logs":{"get":{"tags":["Deployments"],"summary":"List the captured (historical) container-log dumps for a deployment.","description":"Container runtime logs are normally only available live from the running\ncontainer. When a deployment is superseded its containers are torn down and\nthose logs would be lost — so just before teardown we capture each\ncontainer's logs to durable storage. This endpoint lists what was captured\nfor a given (often older) deployment, so a user can read the logs of a\ncontainer that no longer exists.","operationId":"list_deployment_container_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Captured container logs for the deployment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentContainerLogsListResponse"}}}},"404":{"description":"Deployment not found in this project"},"500":{"description":"Internal server error"}},"security":[{"bearer_token":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/container-logs/{log_id}":{"get":{"tags":["Deployments"],"summary":"Get the captured text content of a single historical container-log dump.","operationId":"get_deployment_container_log_content","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"log_id","in":"path","description":"Captured log ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Captured container log content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentContainerLogContentResponse"}}}},"404":{"description":"Captured log not found in this project"},"500":{"description":"Internal server error"}},"security":[{"bearer_token":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/jobs":{"get":{"tags":["Deployments"],"summary":"Get jobs for a specific deployment","description":"Returns all jobs (workflow tasks) for a deployment, ordered by execution order.\nThis replaces the old deployment stages endpoint.","operationId":"get_deployment_jobs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Jobs retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentJobsResponse"}}}},"404":{"description":"Deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/jobs/{job_id}/logs":{"get":{"tags":["Deployments"],"summary":"Get logs for a specific deployment job","operationId":"get_deployment_job_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"job_id","in":"path","description":"Job ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Job logs retrieved successfully","content":{"text/plain":{"schema":{"type":"string"}}}},"404":{"description":"Job or logs not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_token":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/jobs/{job_id}/logs/tail":{"get":{"tags":["Deployments"],"summary":"Tail logs for a specific deployment job in real-time via WebSocket","description":"**WebSocket Streaming**: Logs are sent as raw text, one line per WebSocket message.\n\n**Authentication**: Requires authentication via session cookie (browser clients)\nor API key (API clients). For browser-based WebSocket connections, ensure the user\nis logged in - the browser automatically includes session cookies in the WebSocket\nupgrade request.\n\n**API Client Authentication**: Include API key in Authorization header:\n```text\nAuthorization: Bearer tk_your_api_key_here\n```","operationId":"tail_deployment_job_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"job_id","in":"path","description":"Job ID","required":true,"schema":{"type":"string"}}],"responses":{"101":{"description":"WebSocket connection established for streaming deployment job logs"},"404":{"description":"Job or logs not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_token":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/operations":{"get":{"tags":["Deployments"],"summary":"Get all operations for a deployment","operationId":"get_deployment_operations","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of operations","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperationResultsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Deployments"],"summary":"Execute a deployment operation (deploy, mark_complete, take_screenshot)","operationId":"execute_deployment_operation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteOperationRequest"}}},"required":true},"responses":{"202":{"description":"Operation executed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperationResultResponse"}}}},"400":{"description":"Invalid operation"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/operations/{operation_type}":{"get":{"tags":["Deployments"],"summary":"Get the status of a specific operation type","operationId":"get_deployment_operation_status","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","required":true,"schema":{"type":"string"}},{"name":"operation_type","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Operation status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperationResultResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Operation not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/pause":{"post":{"tags":["Projects"],"summary":"Pause a deployment","operationId":"pause_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment paused successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentStateResponse"}}}},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/promote":{"post":{"tags":["Deployments"],"summary":"Promote a deployment to another environment","description":"Creates a new deployment in the target environment using the source deployment's\nDocker image. Useful for promoting a validated preview/staging deployment to production.","operationId":"promote_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Source deployment ID to promote","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromoteDeploymentRequest"}}},"required":true},"responses":{"200":{"description":"Promotion initiated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentResponse"}}}},"400":{"description":"Invalid deployment state for promotion"},"404":{"description":"Project, deployment, or target environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/resume":{"post":{"tags":["Projects"],"summary":"Resume a deployment","operationId":"resume_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment resumed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentStateResponse"}}}},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/rollback":{"post":{"tags":["Projects"],"operationId":"rollback_to_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID to rollback to","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Rollback initiated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentResponse"}}}},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/teardown":{"delete":{"tags":["Projects"],"summary":"Teardown a specific deployment","operationId":"teardown_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Deployment torn down successfully"},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/dsns":{"get":{"tags":[],"summary":"List all DSNs for a project","operationId":"list_dsns","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of DSNs","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectDSNResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":[],"summary":"Create a new DSN for a project","operationId":"create_dsn","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDSNRequest"}}},"required":true},"responses":{"201":{"description":"DSN created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDSNResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/dsns/get-or-create":{"post":{"tags":[],"summary":"Get or create DSN for a project/environment/deployment combination","operationId":"get_or_create_dsn","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetOrCreateDSNRequest"}}},"required":true},"responses":{"200":{"description":"DSN retrieved or created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDSNResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/dsns/{dsn_id}/regenerate":{"post":{"tags":[],"summary":"Regenerate DSN keys (rotate keys)","operationId":"regenerate_dsn","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"dsn_id","in":"path","description":"DSN ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegenerateDSNRequest"}}},"required":true},"responses":{"200":{"description":"DSN keys regenerated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDSNResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"DSN not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/dsns/{dsn_id}/revoke":{"post":{"tags":[],"summary":"Revoke (deactivate) a DSN","operationId":"revoke_dsn","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"dsn_id","in":"path","description":"DSN ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"DSN revoked"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"DSN not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/env-vars":{"get":{"tags":["Projects"],"summary":"Get environment variables for a project, optionally filtered by environment","operationId":"get_environment_variables","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Optional environment ID to filter by","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environment variables","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentVariableResponse"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["Projects"],"summary":"Create a new environment variable","operationId":"create_environment_variable","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEnvironmentVariableRequest"}}},"required":true},"responses":{"201":{"description":"Environment variables created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableResponse"}}}},"400":{"description":"Invalid input"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/env-vars/resolved":{"get":{"tags":["Projects"],"summary":"Resolved env vars for a project (manual + integration-sourced, merged).","description":"Returns the effective set of environment variables a deployment would see,\ncombining manually-defined vars with those contributed by linked external\nservices (Postgres, Redis, S3, etc.). Each entry is tagged with its source\nso the UI can render an integration icon, and manual entries that shadow an\nintegration key carry a reference to the integration they override.\n\nValues are always returned as a masked preview. Use the per-key reveal\nendpoint for plaintext (audit-logged).","operationId":"get_resolved_environment_variables","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Optional environment ID to filter manual vars by","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Resolved environment variables","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ResolvedEnvVarResponse"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/env-vars/resolved/{key}/value":{"get":{"tags":["Projects"],"summary":"Reveal the plaintext value of a resolved environment variable.","description":"Mirrors `GET /projects/{id}/env-vars/{key}/value` but handles keys sourced\nfrom linked integrations (which are not stored in the `env_vars` table).\nResolution order mirrors the merged view:\n\n1. Manual env var with this key — this endpoint reads the manual store when\n the key exists there, then writes its own reveal audit event so callers\n can safely use one endpoint regardless of source.\n2. Integration env var supplied by a linked external service.\n\nReturns 404 when neither a manual var nor an integration produces the key.","operationId":"get_resolved_environment_variable_value","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Environment variable key","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Optional environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"var_id","in":"query","description":"Exact manual environment-variable row ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"service_id","in":"query","description":"Integration service ID shown by the resolved list","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Resolved environment variable value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableValueResponse"}}}},"403":{"description":"Plaintext secret access is not permitted"},"404":{"description":"Project, key, or integration not found"},"409":{"description":"Environment variable key is ambiguous"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/env-vars/{key}/value":{"get":{"tags":["Projects"],"summary":"Get environment variable value by key","operationId":"get_environment_variable_value","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Environment variable key","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Optional environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"var_id","in":"query","description":"Exact environment-variable row ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Environment variable value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableValueResponse"}}}},"403":{"description":"Plaintext secret access is not permitted"},"404":{"description":"Project or variable not found"},"409":{"description":"Environment variable key is ambiguous"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/env-vars/{var_id}":{"put":{"tags":["Projects"],"summary":"Update an environment variable","operationId":"update_environment_variable","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"var_id","in":"path","description":"Environment variable ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEnvironmentVariableRequest"}}},"required":true},"responses":{"200":{"description":"Environment variables updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableResponse"}}}},"400":{"description":"Invalid input"},"404":{"description":"Project or variable not found"},"500":{"description":"Internal server error"}}},"delete":{"tags":["Projects"],"summary":"Delete an environment variable","operationId":"delete_environment_variable","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"var_id","in":"path","description":"Environment variable ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Environment variable deleted successfully"},"404":{"description":"Project or variable not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments":{"get":{"tags":["Projects"],"summary":"Get all environments for a project","operationId":"get_environments","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environments","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentResponse"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["Projects"],"summary":"Create a new environment for a project","operationId":"create_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEnvironmentRequest"}}},"required":true},"responses":{"201":{"description":"Environment created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"400":{"description":"Invalid input"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}":{"get":{"tags":["Projects"],"summary":"Get a specific environment by ID or slug","operationId":"get_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Environment details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}},"delete":{"tags":["Projects"],"summary":"Delete an environment permanently","description":"Permanently deletes an environment and all related data. Cannot delete:\n- Production environments (name = \"Production\")\n\nWarning: This action is permanent and cannot be undone.\nActive deployments are automatically cancelled before deletion.","operationId":"delete_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Environment permanently deleted"},"400":{"description":"Cannot delete production environment"},"404":{"description":"Project or environment not found"},"428":{"description":"Recent MFA verification required"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/crons":{"get":{"tags":["Crons"],"operationId":"get_environment_crons","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of cron jobs","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CronInfo"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/crons/{cron_id}":{"get":{"tags":["Crons"],"operationId":"get_cron_by_id","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"cron_id","in":"path","description":"Cron Job ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Cron job details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CronInfo"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Cron job not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/crons/{cron_id}/executions":{"get":{"tags":["Crons"],"operationId":"get_cron_executions","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"cron_id","in":"path","description":"Cron Job ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"per_page","in":"query","description":"Items per page (default: 20)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"List of cron job executions","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CronExecutionInfo"}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Cron job not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/domains":{"get":{"tags":["Projects"],"summary":"Get all environment domains for a specific environment","operationId":"get_environment_domains","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environment domains","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentDomainResponse"}}}}},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["Projects"],"summary":"Add a new environment domain","operationId":"add_environment_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddEnvironmentDomainRequest"}}},"required":true},"responses":{"201":{"description":"Domain added successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentDomainResponse"}}}},"400":{"description":"Invalid input"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/domains/{domain_id}":{"delete":{"tags":["Projects"],"summary":"Delete an environment domain","operationId":"delete_environment_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Domain deleted successfully"},"404":{"description":"Project, environment, or domain not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/settings":{"put":{"tags":["Projects"],"summary":"Update environment settings","operationId":"update_environment_settings","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEnvironmentSettingsRequest"}}},"required":true},"responses":{"200":{"description":"Environment settings updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/sleep":{"post":{"tags":["Environments"],"summary":"Sleep an on-demand environment","description":"Manually put an on-demand environment to sleep. Stops containers and sets\n`sleeping = true`. If no OnDemandWaker is available, falls back to DB flag only.","operationId":"sleep_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Environment put to sleep","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"400":{"description":"On-demand not enabled for this environment"},"404":{"description":"Environment not found"},"429":{"description":"Too many state transitions, retry after cooldown"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/subdomain":{"patch":{"tags":["Projects"],"summary":"Rename the auto-managed subdomain for an environment.","description":"Replaces the environment's previous subdomain entirely — the old\nhostname stops resolving once the proxy reloads its route table.\nCustom domains attached to the environment are unaffected.","operationId":"update_environment_subdomain","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEnvironmentSubdomainRequest"}}},"required":true},"responses":{"200":{"description":"Subdomain updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"400":{"description":"Invalid subdomain or conflict with another environment"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/teardown":{"delete":{"tags":["Projects"],"summary":"Teardown an environment and all its active deployments","operationId":"teardown_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Environment torn down successfully"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/wake":{"post":{"tags":["Environments"],"summary":"Wake a sleeping on-demand environment","description":"Manually wake an environment that has been put to sleep by the on-demand\nidle timeout. Starts containers, waits for health checks, then sets\n`sleeping = false`. If no OnDemandWaker is available (proxy not running\nin same process), falls back to setting the DB flag only.","operationId":"wake_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Environment woken up","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"400":{"description":"On-demand not enabled for this environment"},"404":{"description":"Environment not found"},"429":{"description":"Too many state transitions, retry after cooldown"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/container-logs":{"get":{"tags":["Deployments"],"summary":"Get logs for a container in an environment via WebSocket","operationId":"get_container_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for logs","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"end_date","in":"query","description":"End date for logs","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tail","in":"query","description":"Number of lines to tail (or 'all')","required":false,"schema":{"type":"string"}},{"name":"container_name","in":"query","description":"Optional container name (defaults to first/primary container)","required":false,"schema":{"type":"string"}},{"name":"timestamps","in":"query","description":"Include timestamps in log output (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"follow","in":"query","description":"Follow log output in real-time (default: true)","required":false,"schema":{"type":"boolean"}}],"responses":{"101":{"description":"WebSocket connection established for streaming container logs"},"400":{"description":"Not a server-type project"},"404":{"description":"Project, deployment, or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers":{"get":{"tags":["Deployments"],"summary":"List all containers for an environment","operationId":"list_containers","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of containers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerListResponse"}}}},"400":{"description":"Not a server-type project"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}":{"get":{"tags":["Containers"],"summary":"Get detailed information about a specific container","operationId":"get_container_detail","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerDetailResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/environment/{variable_name}":{"get":{"tags":["Containers"],"operationId":"get_container_environment_variable","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}},{"name":"variable_name","in":"path","description":"Environment variable name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Environment variable value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerEnvironmentVariableValueResponse"}}}},"403":{"description":"Plaintext secret access is not permitted"},"404":{"description":"Container or environment variable not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/logs":{"get":{"tags":["Deployments"],"summary":"Get logs for a specific container by container ID via WebSocket","operationId":"get_container_logs_by_id","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}},{"name":"start_date","in":"query","description":"Start date for logs","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"end_date","in":"query","description":"End date for logs","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tail","in":"query","description":"Number of lines to tail (or 'all')","required":false,"schema":{"type":"string"}},{"name":"timestamps","in":"query","description":"Include timestamps in log output (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"follow","in":"query","description":"Follow log output in real-time (default: true)","required":false,"schema":{"type":"boolean"}}],"responses":{"101":{"description":"WebSocket connection established for streaming container logs"},"400":{"description":"Not a server-type project"},"404":{"description":"Project, environment, or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/metrics":{"get":{"tags":["Containers"],"summary":"Get metrics/stats for a specific container","operationId":"get_container_metrics","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container metrics retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerMetricsResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/metrics/history":{"get":{"tags":["Containers"],"summary":"Fetch a time-series range for a single container resource metric\n(recorded by the container health monitor every ~30s).","description":"Useful metric names: `container.cpu_percent`,\n`container.cpu_utilization_percent`, `container.memory_used_bytes`,\n`container.memory_percent`, `container.network_rx_bytes_delta`,\n`container.network_tx_bytes_delta`.","operationId":"ContainerMetricsGetHistory","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}},{"name":"metric","in":"query","description":"Dotted metric name, e.g. `container.cpu_percent` or\n`container.memory_used_bytes`.","required":true,"schema":{"type":"string"}},{"name":"range","in":"query","description":"Time window: `1h`, `6h`, `24h`, or `7d` (defaults to `1h`).","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Metric time series data points","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ContainerMetricHistoryPoint"}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Container not found"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/metrics/stream":{"get":{"tags":["Containers"],"summary":"Stream container metrics via Server-Sent Events (SSE)","operationId":"stream_container_metrics","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}},{"name":"interval","in":"query","description":"Update interval in milliseconds (default: 1000)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Metrics stream established (Server-Sent Events)"},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/restart":{"post":{"tags":["Containers"],"summary":"Restart a container","operationId":"restart_container","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container restarted successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerActionResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/start":{"post":{"tags":["Containers"],"summary":"Start a container","operationId":"start_container","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container started successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerActionResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/stop":{"post":{"tags":["Containers"],"summary":"Stop a specific container","operationId":"stop_container","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container stopped successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerActionResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/deploy/image":{"post":{"tags":["Deployments"],"summary":"Deploy from an external Docker image","description":"Triggers a deployment using a pre-built Docker image from an external registry.\nThe image will be pulled and deployed to the specified environment.","operationId":"deploy_from_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeployFromImageRequest"}}},"required":true},"responses":{"202":{"description":"Deployment started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoteDeploymentResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/deploy/image-upload":{"post":{"tags":["Deployments"],"summary":"Deploy from an uploaded Docker image tarball","description":"Uploads a Docker image tarball (from `docker save`) and deploys it directly.\nThe image is imported using `docker load` and then deployed to the specified environment.\nThis is useful when you want to deploy an image without pushing to a registry first.\n\nThe uploaded file should be a tarball created by `docker save myimage:tag > image.tar`\nor `docker save myimage:tag | gzip > image.tar.gz` (gzip compressed tarballs are also supported).","operationId":"deploy_from_image_upload","parameters":[{"name":"tag","in":"query","description":"Tag to apply to the imported image (e.g., \"myapp:v1.0\")\nIf not provided, a unique tag will be generated","required":false,"schema":{"type":["string","null"]}},{"name":"health_check_path","in":"query","description":"Optional HTTP health-check path override (e.g. \"/api/healthz\").\nMust start with '/'. When omitted, defaults to \"/\".","required":false,"schema":{"type":["string","null"]}},{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Image imported and deployment started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoteDeploymentResponse"}}}},"400":{"description":"Invalid request or unsupported format"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project or environment not found"},"413":{"description":"Image tarball too large"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/deploy/source":{"post":{"tags":["Deployments"],"summary":"Upload source code and immediately start a preset-based deployment.","operationId":"deploy_from_uploaded_source","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/SourceArchiveUpload"}}},"required":true},"responses":{"202":{"description":"Source deployment started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoteDeploymentResponse"}}}},"400":{"description":"Invalid source archive"},"404":{"description":"Project or environment not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/deploy/static":{"post":{"tags":["Deployments"],"summary":"Deploy from an uploaded static bundle","description":"Triggers a deployment using a previously uploaded static file bundle.","operationId":"deploy_from_static","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeployFromStaticRequest"}}},"required":true},"responses":{"202":{"description":"Deployment started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoteDeploymentResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project, environment, or bundle not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/error-alert-rules":{"get":{"tags":["error-alert-rules"],"summary":"List all alert rules for a project","operationId":"list_alert_rules","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of alert rules","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AlertRuleResponse"}}}}},"500":{"description":"Internal server error"}}},"post":{"tags":["error-alert-rules"],"summary":"Create a new alert rule","operationId":"create_alert_rule","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAlertRuleRequest"}}},"required":true},"responses":{"201":{"description":"Alert rule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertRuleResponse"}}}},"400":{"description":"Validation error"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-alert-rules/{rule_id}":{"get":{"tags":["error-alert-rules"],"summary":"Get a specific alert rule","operationId":"get_alert_rule","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alert rule details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertRuleResponse"}}}},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}}},"put":{"tags":["error-alert-rules"],"summary":"Update an existing alert rule","operationId":"update_alert_rule","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAlertRuleRequest"}}},"required":true},"responses":{"200":{"description":"Alert rule updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertRuleResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}}},"delete":{"tags":["error-alert-rules"],"summary":"Delete an alert rule","operationId":"delete_alert_rule","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Alert rule deleted"},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-dashboard-stats":{"get":{"tags":["error-tracking"],"summary":"Get error dashboard statistics","operationId":"get_error_dashboard_stats","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"end_time","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"environment_id","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"compare_to_previous","in":"query","required":false,"schema":{"type":["boolean","null"]}}],"responses":{"200":{"description":"Error dashboard statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDashboardStatsResponse"}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-groups":{"get":{"tags":["error-tracking"],"summary":"List error groups for a project","operationId":"list_error_groups","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"status","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"environment_id","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_date","in":"query","required":false,"schema":{"type":["string","null"],"format":"date-time"}},{"name":"end_date","in":"query","required":false,"schema":{"type":["string","null"],"format":"date-time"}},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated list of error groups","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedErrorGroupsResponse"}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-groups/{group_id}":{"get":{"tags":["error-tracking"],"summary":"Get a specific error group","operationId":"get_error_group","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"group_id","in":"path","description":"Error group ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Error group details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorGroupResponse"}}}},"404":{"description":"Error group not found"},"500":{"description":"Internal server error"}}},"put":{"tags":["error-tracking"],"summary":"Update error group status","operationId":"update_error_group","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"group_id","in":"path","description":"Error group ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateErrorGroupRequest"}}},"required":true},"responses":{"200":{"description":"Error group updated successfully"},"404":{"description":"Error group not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-groups/{group_id}/events":{"get":{"tags":["error-tracking"],"summary":"List error events for a specific group","operationId":"list_error_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"group_id","in":"path","description":"Error group ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Paginated list of error events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedErrorEventsResponse"}}}},"404":{"description":"Error group not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-groups/{group_id}/events/{event_id}":{"get":{"tags":["error-tracking"],"summary":"Get a specific error event","operationId":"get_error_event","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"group_id","in":"path","description":"Error group ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"event_id","in":"path","description":"Error event ID","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Error event details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEventResponse"}}}},"404":{"description":"Event not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-stats":{"get":{"tags":["error-tracking"],"summary":"Get error statistics for a project","operationId":"get_error_stats","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Error statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorGroupStatsResponse"}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-time-series":{"get":{"tags":["error-tracking"],"summary":"Get error time series data for charts","operationId":"get_error_time_series","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"end_time","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"bucket","in":"query","description":"Time bucket size (e.g., \"1h\", \"15m\", \"1d\", \"1 hour\", \"30 minutes\")","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Error time series data","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ErrorTimeSeriesDataResponse"}}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/events":{"get":{"tags":["Events"],"summary":"Get event counts with filtering","operationId":"get_events_count","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering events","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering events","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Maximum number of events to return (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"custom_events_only","in":"query","description":"Only return custom events, excluding system events like page_view, page_leave, heartbeat (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors (default: events)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved event counts","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventCount"}}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/breakdown":{"get":{"tags":["Events"],"summary":"Get event type breakdown","operationId":"get_event_type_breakdown","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering events","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering events","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors (default: events)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved event type breakdown","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventTypeBreakdown"}}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/ingest":{"post":{"tags":["Events"],"summary":"Record an analytics event via the console API with explicit project ID.","description":"The app backend forwards the user's encrypted Temps cookies, so visitor/session\nidentity is resolved automatically by middleware. No geolocation or user-agent\nenrichment is performed — this is a lightweight server-side ingestion path.","operationId":"record_console_event","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsoleEventPayload"}}},"required":true},"responses":{"200":{"description":"Event recorded successfully"},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/properties/breakdown":{"get":{"tags":["Events"],"summary":"Get property breakdown by grouping events by a column","operationId":"get_property_breakdown","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"group_by","in":"query","description":"Column to group by (channel, device_type, browser, etc.)","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"event_name","in":"query","description":"Filter by event name","required":false,"schema":{"type":"string"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors - default: events","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Maximum number of results (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"filter_country","in":"query","description":"Filter by country (for region/city drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Filter by region (for city drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_browser","in":"query","description":"Filter by browser name (for version drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_os","in":"query","description":"Filter by OS name (for version drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_channel","in":"query","description":"Filter by channel name (for channel drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_referrer","in":"query","description":"Filter by referrer hostname (for referrer drill-downs)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved property breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PropertyBreakdownResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/properties/timeline":{"get":{"tags":["Events"],"summary":"Get property timeline by grouping events by a column over time","operationId":"get_property_timeline","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"group_by","in":"query","description":"Column to group by (channel, device_type, browser, etc.)","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"event_name","in":"query","description":"Filter by event name","required":false,"schema":{"type":"string"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors - default: events","required":false,"schema":{"type":"string"}},{"name":"bucket_size","in":"query","description":"Time bucket: hour, day, week, month (default: auto-detect)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved property timeline","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PropertyTimelineResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/timeline":{"get":{"tags":["Events"],"summary":"Get events timeline","operationId":"get_events_timeline","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering events","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering events","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"event_name","in":"query","description":"Filter by specific event name","required":false,"schema":{"type":"string"}},{"name":"bucket_size","in":"query","description":"Bucket size: hour, day, or week (auto-detected if not specified)","required":false,"schema":{"type":"string"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors (default: events)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved events timeline","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventTimeline"}}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/unique":{"get":{"tags":["Funnels"],"summary":"Get all unique/distinct event types for a project (paginated)","operationId":"get_unique_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Unique event types retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventTypesResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/external-images":{"get":{"tags":["External Images"],"summary":"List external images for a project","operationId":"list_remote_external_images","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default: 20)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of external images","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedExternalImagesResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["External Images"],"summary":"Register an external Docker image","description":"Registers an external Docker image reference without triggering a deployment.\nThe image can be deployed later using the deploy/image endpoint.","operationId":"register_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterImageRequest"}}},"required":true},"responses":{"201":{"description":"Image registered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalImageResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/external-images/{image_id}":{"get":{"tags":["External Images"],"summary":"Get details of a specific external image","operationId":"get_remote_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"image_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Image details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalImageResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Image not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["External Images"],"summary":"Delete an external image","operationId":"delete_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"image_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Image deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Image not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/flags":{"get":{"tags":["Feature Flags"],"operationId":"list_flags","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"include_archived","in":"query","description":"Include archived flags. Defaults to false.","required":false,"schema":{"type":"boolean"}},{"name":"page","in":"query","description":"1-indexed page number. Defaults to 1.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page. Defaults to 20, capped at 100.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"Flags listed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Feature Flags"],"operationId":"create_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFlagRequest"}}},"required":true},"responses":{"201":{"description":"Flag created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"409":{"description":"Flag key already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/flags/{key}":{"get":{"tags":["Feature Flags"],"operationId":"get_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Flag retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Feature Flags"],"operationId":"archive_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Flag archived","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArchiveFlagResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Feature Flags"],"operationId":"update_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateFlagRequest"}}},"required":true},"responses":{"200":{"description":"Flag updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/flags/{key}/environments/{environment_id}":{"put":{"tags":["Feature Flags"],"summary":"Set a flag's value in one environment, and/or flip its kill switch.","operationId":"set_flag_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetFlagEnvironmentRequest"}}},"required":true},"responses":{"200":{"description":"Environment value set","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagEnvironmentResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag or environment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/flags/{key}/restore":{"post":{"tags":["Feature Flags"],"summary":"Bring an archived flag back.","description":"Archiving is otherwise one-way: the key stays reserved so the flag cannot\neven be re-created under the same name, which makes an accidental archive\nunrecoverable through the API.","operationId":"restore_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Flag restored","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/funnels":{"get":{"tags":["Funnels"],"summary":"List all funnels for a project","operationId":"list_funnels","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Funnels retrieved successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/FunnelResponse"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Funnels"],"summary":"Create a new funnel","operationId":"create_funnel","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFunnelRequest"}}},"required":true},"responses":{"201":{"description":"Funnel created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFunnelResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/funnels/preview":{"post":{"tags":["Funnels"],"summary":"Preview funnel metrics without creating the funnel","operationId":"preview_funnel_metrics","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFunnelRequest"}}},"required":true},"responses":{"200":{"description":"Funnel metrics preview","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FunnelMetricsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/funnels/{funnel_id}":{"put":{"tags":["Funnels"],"summary":"Update a funnel","operationId":"update_funnel","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"funnel_id","in":"path","description":"Funnel ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFunnelRequest"}}},"required":true},"responses":{"200":{"description":"Funnel updated successfully"},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"404":{"description":"Funnel not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Funnels"],"summary":"Delete a funnel","operationId":"delete_funnel","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"funnel_id","in":"path","description":"Funnel ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Funnel deleted successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Funnel not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/funnels/{funnel_id}/metrics":{"get":{"tags":["Funnels"],"summary":"Get funnel metrics","operationId":"get_funnel_metrics","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"funnel_id","in":"path","description":"Funnel ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID filter","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"country_code","in":"query","description":"Country code filter","required":false,"schema":{"type":"string"}},{"name":"start_date","in":"query","description":"Start date filter (ISO 8601)","required":false,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date filter (ISO 8601)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Funnel metrics retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FunnelMetricsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"404":{"description":"Funnel not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/git":{"post":{"tags":["Projects"],"summary":"Update git settings for a project","operationId":"update_git_settings","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateGitSettingsRequest"}}},"required":true},"responses":{"200":{"description":"Git settings updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"400":{"description":"Invalid git configuration or branch does not exist"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/gitlab/reinstall-webhook":{"post":{"tags":["Projects"],"summary":"Reinstall the GitLab webhook for a project","description":"Removes the existing webhook (if any) and installs a fresh one.\nUse this when a webhook has been manually deleted on the GitLab side\nand automatic deployments have stopped working.","operationId":"reinstall_gitlab_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Webhook reinstalled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReinstallWebhookResponse"}}}},"400":{"description":"Project is not connected to a GitLab repository"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/has-error-groups":{"get":{"tags":["error-tracking"],"summary":"Check if project has any error groups","operationId":"has_error_groups","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Error groups existence check","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HasErrorGroupsResponse"}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/has-events":{"get":{"tags":["Events"],"summary":"Check if project has any analytics events","operationId":"has_analytics_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully checked for events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HasEventsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/hourly-visits":{"get":{"tags":["Events"],"summary":"Get hourly visits","operationId":"get_hourly_visits","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering visits","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering visits","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events (page views), sessions (unique sessions), or visitors (unique visitors) - default: events","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved hourly visits","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventTimeline"}}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/images":{"get":{"tags":["External Images"],"summary":"List all external images for a project","operationId":"list_external_images","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of external images","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PushedExternalImageResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/images/push":{"post":{"tags":["External Images"],"summary":"Push an external Docker image","operationId":"push_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushImageRequest"}}},"required":true},"responses":{"201":{"description":"Image pushed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushedExternalImageResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/images/{image_id}":{"get":{"tags":["External Images"],"summary":"Get details of a specific external image","operationId":"get_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"image_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Image details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushedExternalImageResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Image not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/incidents":{"get":{"tags":["Status Page"],"summary":"List incidents for a project","operationId":"list_incidents","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"status","in":"query","description":"Filter by status","required":false,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Successfully retrieved incidents"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Status Page"],"summary":"Create a new incident","operationId":"create_incident","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIncidentRequest"}}},"required":true},"responses":{"201":{"description":"Incident created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/incidents/bucketed":{"get":{"tags":["Status Page"],"summary":"Get bucketed incident data for a project","operationId":"get_bucketed_incidents","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"interval","in":"query","description":"Bucket interval: '5min', 'hourly', or 'daily' (default: hourly)","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601) (default: 7 days ago)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (ISO 8601) (default: now)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved bucketed incident data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentBucketedResponse"}}}},"400":{"description":"Invalid parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/logs":{"delete":{"tags":["Logs"],"summary":"Purge all logs for a project before a given timestamp","operationId":"purge_project_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurgeLogsRequest"}}},"required":true},"responses":{"200":{"description":"Purge completed"},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/mcp-servers":{"get":{"tags":["Agents"],"operationId":"list_mcps","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListMcpsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_mcp","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMcpRequest"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/mcp-servers/{slug}":{"get":{"tags":["Agents"],"operationId":"get_mcp","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_mcp","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMcpRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_mcp","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"MCP server deleted"},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/mcp-servers/{slug}/config/{field}":{"get":{"tags":["Agents"],"operationId":"reveal_mcp_config","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}},{"name":"field","in":"path","description":"Sensitive field path, such as url or env.API_TOKEN","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensitiveMcpConfigValueResponse"}}}},"400":{"description":"Field is not revealable"},"401":{"description":"Unauthorized"},"403":{"description":"Missing secrets:read permission"},"404":{"description":"MCP server or field not found"},"500":{"description":"Configuration read or audit failed"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/monitors":{"get":{"tags":["Status Page"],"summary":"List monitors for a project","operationId":"list_monitors","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved monitors","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MonitorResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Status Page"],"summary":"Create a new monitor","operationId":"create_monitor","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMonitorRequest"}}},"required":true},"responses":{"201":{"description":"Monitor created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/observe/events":{"get":{"tags":["Observability"],"summary":"List a merged page of observability events for a project.","description":"Each row carries everything the side panel needs to render — no\nfollow-up fetch is required for the common case. Heavy fields\n(stacktraces, headers, span attributes) are truncated server-side and\nexpose a `*_truncated` flag; clients fetch the full row from the\n`/full` endpoint only when the user explicitly clicks \"Show full\".","operationId":"observability_list_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"kinds","in":"query","description":"Comma-separated kinds: `log,request,span,error,revenue`. Empty or\nmissing returns every kind.","required":false,"schema":{"type":"string"}},{"name":"from","in":"query","description":"Inclusive lower bound on event timestamp (ISO 8601, `Z` suffix).","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","description":"Inclusive upper bound on event timestamp.","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"deployment_id","in":"query","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"search","in":"query","description":"Free-text substring matched against per-kind summary fields\n(request path / error class / revenue event_type).","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Page size (default 50, max 200).","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"hide_bots","in":"query","description":"When `true`, exclude bot/crawler request rows. When `false`, only\ninclude bot rows. Omitted means \"include everything\" (default).\nOnly affects the `Request` kind.","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Merged event page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventsResponse"}}}},"400":{"description":"Invalid filter (kinds, time range, …)","content":{"text/plain":{"schema":{"type":"string"}}}},"401":{"description":"Unauthorized","content":{"text/plain":{"schema":{"type":"string"}}}},"403":{"description":"Insufficient permissions","content":{"text/plain":{"schema":{"type":"string"}}}},"500":{"description":"Internal server error","content":{"text/plain":{"schema":{"type":"string"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/observe/events/{kind}/{event_id}/full":{"get":{"tags":["Observability"],"summary":"Fetch the un-truncated form of one event by `(kind, id)`. Side panel\n\"Show full\" action calls this — the list response carries truncated\npreviews + a `*_truncated` flag to let the UI decide whether to fetch.","operationId":"observability_full_event","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"kind","in":"path","description":"Event kind discriminator","required":true,"schema":{"$ref":"#/components/schemas/EventKind"}},{"name":"event_id","in":"path","description":"Per-kind identity: request_id for requests, `{trace_id}:{span_id}` for spans, serial id for errors/revenue","required":true,"schema":{"type":"string"}},{"name":"ts","in":"query","description":"The row's event timestamp as returned by the list endpoint. Optional,\nbut strongly recommended: it bounds the lookup to the storage\npartitions/chunks around that instant instead of scanning the whole\nretention window.","required":false,"schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"Full row","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FullEvent"}}}},"401":{"description":"Unauthorized","content":{"text/plain":{"schema":{"type":"string"}}}},"403":{"description":"Insufficient permissions","content":{"text/plain":{"schema":{"type":"string"}}}},"404":{"description":"Event not found in project","content":{"text/plain":{"schema":{"type":"string"}}}},"500":{"description":"Internal server error","content":{"text/plain":{"schema":{"type":"string"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/releases/{release}/source-files":{"get":{"tags":["source-maps"],"summary":"List uploaded source files for a release (metadata only).","operationId":"list_source_files","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of source files","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceFileListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["source-maps"],"summary":"Upload a raw source file for a release (native symbolication).","description":"Accepts a multipart form with:\n- `file`: the source file bytes (required)\n- `file_path`: the path of the file as it appears in stack frames (required;\n derived from the uploaded filename if omitted). Normalized with the `~`\n prefix convention, matching source-map storage.\n\nRequires the project's `error_source_context_enabled` toggle to be on.\nUpserts on (project, release, file_path).","operationId":"upload_source_file","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"Source file uploaded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceFileResponse"}}}},"400":{"description":"Missing fields"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"409":{"description":"Source context disabled for project"},"413":{"description":"Source file too large"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["source-maps"],"summary":"Delete all uploaded source files for a release.","operationId":"delete_release_source_files","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Source files deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/releases/{release}/source-maps":{"get":{"tags":["source-maps"],"summary":"List all source maps for a specific release","operationId":"list_source_maps","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of source maps","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceMapListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["source-maps"],"summary":"Upload a source map for a release.","description":"Accepts a multipart form with:\n- `file`: The .map file (required)\n- `file_path`: The URL path of the minified file as it appears in stack traces (required).\n Uses the ~ prefix convention (e.g., \"~/assets/main.js\").\n If a full URL is provided, it will be normalized automatically.\n- `dist`: Optional distribution identifier\n\nIf a source map already exists for the same (project, release, file_path), it is replaced.","operationId":"upload_source_map","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"Source map uploaded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceMapResponse"}}}},"400":{"description":"Invalid source map or missing fields"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"413":{"description":"Source map too large"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["source-maps"],"summary":"Delete all source maps for a specific release","operationId":"delete_release_source_maps","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Source maps deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/events":{"get":{"tags":["Revenue"],"summary":"Recent ingested events for the activity feed.","operationId":"revenue_recent_events","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RecentEventResponse"}}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations":{"get":{"tags":["Revenue"],"summary":"List revenue integrations for a project.","operationId":"revenue_list_integrations","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/IntegrationResponse"}}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Revenue"],"summary":"Create a new revenue integration. Response contains the generated\nwebhook path that the user must paste into their provider's dashboard.","operationId":"revenue_create_integration","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIntegrationBody"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationResponse"}}}},"400":{"description":"Validation error"},"409":{"description":"Already connected"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}":{"delete":{"tags":["Revenue"],"summary":"Delete a revenue integration (permanent — use rotate_token to refresh\ncredentials without breaking history).","operationId":"revenue_delete_integration","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/config":{"post":{"tags":["Revenue"],"summary":"Replace the typed provider config on an integration. Passing `null`\nclears the config back to the accept-everything default. The config's\nprovider tag must match the integration's provider.","operationId":"revenue_update_config","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateConfigBody"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Integration not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/import/invoices":{"post":{"tags":["Revenue"],"summary":"Import a Stripe invoices CSV export. Each paid invoice becomes an\n`invoice.paid` event so historical MRR/charge totals populate the\ntimeseries. Ingestion is idempotent: re-uploading the same file is a\nno-op.","operationId":"revenue_import_invoices_csv","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportOutcomeResponse"}}}},"400":{"description":"Malformed CSV or wrong provider"},"404":{"description":"Integration not found"},"413":{"description":"CSV too large"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/import/subscriptions":{"post":{"tags":["Revenue"],"summary":"Import a Stripe subscriptions CSV export. Use this to backfill MRR /\nactive subscriptions when migrating from Stripe without providing\nAPI keys. Webhooks remain the source of truth for live updates —\nCSV rows never overwrite newer webhook state.","operationId":"revenue_import_subscriptions_csv","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportOutcomeResponse"}}}},"400":{"description":"Malformed CSV or wrong provider"},"404":{"description":"Integration not found"},"413":{"description":"CSV too large"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/rotate-token":{"post":{"tags":["Revenue"],"summary":"Rotate the webhook path token. Returns the new integration state —\nthe user must paste the new URL into their provider's dashboard.","operationId":"revenue_rotate_token","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/update-secret":{"post":{"tags":["Revenue"],"summary":"Replace the stored signing secret without rotating the webhook URL.\nUse this after rotating the secret in the provider's dashboard.","operationId":"revenue_update_secret","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSecretBody"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Integration not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/metrics/customers":{"get":{"tags":["Revenue"],"summary":"New + churned customers per bucket.","operationId":"revenue_metrics_customers","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CustomerMovementResponse"}}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/metrics/mrr":{"get":{"tags":["Revenue"],"summary":"Bucketed MRR timeseries for the revenue chart.","operationId":"revenue_metrics_mrr","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MrrBucketResponse"}}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/metrics/summary":{"get":{"tags":["Revenue"],"summary":"Current MRR / ARR / churn / ARPU for a project, in one currency.","operationId":"revenue_metrics_summary","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetricsSummaryResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/secrets":{"get":{"tags":["Secrets"],"summary":"List project secrets (metadata only — values never returned).","operationId":"listProjectSecrets","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Optional environment filter","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of secrets (metadata only, no values)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectSecretResponse"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["Secrets"],"summary":"Create a new secret. The value is encrypted before storage and will be\nmounted as a file at `/run/secrets/` on the next deployment.\nThe plaintext value is NOT returned — the response carries only metadata.","operationId":"createProjectSecret","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectSecretRequest"}}},"required":true},"responses":{"201":{"description":"Secret created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectSecretResponse"}}}},"400":{"description":"Invalid key or value too large"},"409":{"description":"Key already exists in project"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/secrets/{secret_id}":{"put":{"tags":["Secrets"],"summary":"Update a project secret. Value rotation requires a redeploy to take effect —\nrunning containers keep their currently-mounted values until the next\ndeployment.","operationId":"updateProjectSecret","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"secret_id","in":"path","description":"Secret ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProjectSecretRequest"}}},"required":true},"responses":{"200":{"description":"Secret updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectSecretResponse"}}}},"400":{"description":"Value too large"},"404":{"description":"Secret not found"},"500":{"description":"Internal server error"}}},"delete":{"tags":["Secrets"],"summary":"Delete a project secret. Running containers keep their mounted secret files\nuntil they are redeployed.","operationId":"deleteProjectSecret","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"secret_id","in":"path","description":"Secret ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Secret deleted"},"404":{"description":"Secret not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/settings":{"post":{"tags":["Projects"],"summary":"Update project settings","operationId":"update_project_settings","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProjectSettingsRequest"}}},"required":true},"responses":{"200":{"description":"Project settings updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/skills":{"get":{"tags":["Agents"],"operationId":"list_skills","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSkillsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSkillRequest"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/skills/upload":{"post":{"tags":["Agents"],"summary":"Upload a skill with an archive (tar.gz) — project-scoped.","operationId":"upload_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"string"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/skills/{slug}":{"get":{"tags":["Agents"],"operationId":"get_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSkillRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Skill deleted"},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/skills/{slug}/archive":{"get":{"tags":["Agents"],"summary":"Download a skill's archive (tar.gz) — project-scoped.","operationId":"download_skill_archive","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Skill archive tar.gz","content":{"application/gzip":{}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found or has no archive"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/source-map-releases":{"get":{"tags":["source-maps"],"summary":"List all releases that have source maps for a project","operationId":"list_releases","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of releases","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReleaseListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/source-maps/{source_map_id}":{"delete":{"tags":["source-maps"],"summary":"Delete a specific source map by ID","operationId":"delete_source_map","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"source_map_id","in":"path","description":"Source map ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Source map deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Source map not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/static-bundles":{"get":{"tags":["Static Bundles"],"summary":"List static bundles for a project","operationId":"list_static_bundles","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default: 20)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of static bundles","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedStaticBundlesResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/static-bundles/{bundle_id}":{"get":{"tags":["Static Bundles"],"summary":"Get details of a specific static bundle","operationId":"get_static_bundle","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"bundle_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Bundle details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaticBundleResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Bundle not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Static Bundles"],"summary":"Delete a static bundle","operationId":"delete_static_bundle","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"bundle_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Bundle deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Bundle not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/status":{"get":{"tags":["Status Page"],"summary":"Get status page overview","operationId":"get_status_overview","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved status overview","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusPageOverview"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/unique-counts":{"get":{"tags":["Events"],"summary":"Get unique counts over time frame","operationId":"get_unique_counts","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"metric","in":"query","description":"Metric to count: 'sessions' (unique sessions), 'visitors' (unique visitors), 'returning_visitors' (visitors seen before the range), or 'page_views' (total page views) (default: 'sessions')","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved count","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UniqueCountsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/upload/static":{"post":{"tags":["Static Bundles"],"summary":"Upload a static bundle for later deployment","description":"Uploads a tar.gz or zip file containing static assets. The bundle can be\ndeployed later using the deploy/static endpoint.","operationId":"upload_static_bundle","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"201":{"description":"Bundle uploaded successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaticBundleResponse"}}}},"400":{"description":"Invalid request or unsupported format"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"},"413":{"description":"Bundle too large"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/vulnerability-scans":{"get":{"tags":["Vulnerability Scans"],"operationId":"list_project_scans","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of vulnerability scans","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ScanResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Vulnerability Scans"],"operationId":"trigger_scan","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerScanRequest"}}},"required":true},"responses":{"202":{"description":"Scan triggered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerScanResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/vulnerability-scans/environments":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_latest_scans_per_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Latest scans per environment for current deployments","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ScanResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/vulnerability-scans/latest":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_latest_scan","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Latest scan for project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"No scans found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks":{"get":{"tags":["Webhooks"],"summary":"List all webhooks for a project","operationId":"list_webhooks","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of webhooks","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/WebhookResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Webhooks"],"summary":"Create a new webhook","operationId":"create_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookRequestBody"}}},"required":true},"responses":{"201":{"description":"Webhook created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks/{webhook_id}":{"get":{"tags":["Webhooks"],"summary":"Get a specific webhook","operationId":"get_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Webhook details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Webhook not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Webhooks"],"summary":"Update a webhook","operationId":"update_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWebhookRequestBody"}}},"required":true},"responses":{"200":{"description":"Webhook updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Webhook not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Webhooks"],"summary":"Delete a webhook","operationId":"delete_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Webhook deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Webhook not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks/{webhook_id}/deliveries":{"get":{"tags":["Webhook Deliveries"],"summary":"List webhook deliveries","operationId":"list_deliveries","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Number of deliveries to return (default: 50)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of deliveries","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/WebhookDeliveryResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks/{webhook_id}/deliveries/{delivery_id}":{"get":{"tags":["Webhook Deliveries"],"summary":"Get a specific webhook delivery by ID","operationId":"get_delivery","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"delivery_id","in":"path","description":"Delivery ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Delivery details including full payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeliveryResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Delivery not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks/{webhook_id}/deliveries/{delivery_id}/retry":{"post":{"tags":["Webhook Deliveries"],"summary":"Retry a failed delivery","operationId":"retry_delivery","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"delivery_id","in":"path","description":"Delivery ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Delivery retried","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeliveryResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Delivery not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/workflows/dry-run":{"post":{"tags":["Workflows"],"operationId":"workflow_dry_run","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkflowDryRunRequest"}}},"required":true},"responses":{"202":{"description":"Ephemeral run created and queued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunResponse"}}}},"400":{"description":"Validation error (bad YAML, oversized payload, capped limits exceeded)"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/proxy-logs":{"get":{"tags":["Proxy Logs"],"summary":"Get proxy logs with optional filters and pagination","operationId":"get_proxy_logs","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"session_id","in":"query","description":"Filter by session ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"visitor_id","in":"query","description":"Filter by visitor ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering (ISO 8601 format).\n\n**Defaults to 1 hour before `end_date` (or before now) when omitted.**\nThe listing is always time-bounded: an unbounded query would have to\nconsider the entire retention window — 100M+ rows on a busy deployment —\nto return a single page. Pass an explicit `start_date` to widen the\nwindow, up to the configured retention horizon.\n\nThe maximum span between `start_date` and `end_date` is 7 days when\n`project_id` is omitted, or 30 days when a single `project_id` is set —\na project-scoped query is bounded by that project's own row count\nrather than the whole deployment's. A wider request is rejected with a\n400 naming the applicable cap.","required":false,"schema":{"type":["string","null"],"format":"date-time"}},{"name":"end_date","in":"query","description":"End date for filtering (ISO 8601 format). Defaults to now.","required":false,"schema":{"type":["string","null"],"format":"date-time"}},{"name":"method","in":"query","description":"Filter by HTTP method (GET, POST, etc.)","required":false,"schema":{"type":["string","null"]}},{"name":"host","in":"query","description":"Filter by host header","required":false,"schema":{"type":["string","null"]}},{"name":"path","in":"query","description":"Filter by path (supports partial match)","required":false,"schema":{"type":["string","null"]}},{"name":"client_ip","in":"query","description":"Filter by client IP address","required":false,"schema":{"type":["string","null"]}},{"name":"status_code","in":"query","description":"Filter by HTTP status code","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"response_time_min","in":"query","description":"Filter by minimum response time in ms","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"response_time_max","in":"query","description":"Filter by maximum response time in ms","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"routing_status","in":"query","description":"Filter by routing status (routed, no_project, error, pending)","required":false,"schema":{"type":["string","null"]}},{"name":"request_source","in":"query","description":"Filter by request source (proxy, api, console, cli)","required":false,"schema":{"type":["string","null"]}},{"name":"is_system_request","in":"query","description":"Filter by system request flag","required":false,"schema":{"type":["boolean","null"]}},{"name":"user_agent","in":"query","description":"Filter by user agent string (partial match)","required":false,"schema":{"type":["string","null"]}},{"name":"browser","in":"query","description":"Filter by browser name","required":false,"schema":{"type":["string","null"]}},{"name":"operating_system","in":"query","description":"Filter by operating system","required":false,"schema":{"type":["string","null"]}},{"name":"device_type","in":"query","description":"Filter by device type (mobile, desktop, tablet)","required":false,"schema":{"type":["string","null"]}},{"name":"is_bot","in":"query","description":"Filter by bot detection","required":false,"schema":{"type":["boolean","null"]}},{"name":"exclude_bots","in":"query","description":"When `true`, exclude rows flagged as bots while KEEPING rows whose\n`is_bot` is NULL (older rows without detection metadata). This is the\ntri-state complement of `is_bot=false`, which matches only rows\nexplicitly detected as non-bots. `false`/omitted is a no-op.","required":false,"schema":{"type":["boolean","null"]}},{"name":"bot_name","in":"query","description":"Filter by bot name","required":false,"schema":{"type":["string","null"]}},{"name":"ai_provider","in":"query","description":"Filter by AI provider (e.g. `OpenAI`, `Anthropic`, `Perplexity`). Matches\nthe canonical provider returned by the AI agent detector.","required":false,"schema":{"type":["string","null"]}},{"name":"ai_agent","in":"query","description":"Filter by AI agent name (e.g. `GPTBot`, `ChatGPT-User`). Equivalent to\nfiltering `bot_name` against a known AI taxonomy.","required":false,"schema":{"type":["string","null"]}},{"name":"is_ai_agent","in":"query","description":"When `true`, only return requests classified as known AI agents\n(regardless of provider/agent). Mutually compatible with the above.","required":false,"schema":{"type":["boolean","null"]}},{"name":"request_size_min","in":"query","description":"Filter by minimum request size in bytes","required":false,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"request_size_max","in":"query","description":"Filter by maximum request size in bytes","required":false,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"response_size_min","in":"query","description":"Filter by minimum response size in bytes","required":false,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"response_size_max","in":"query","description":"Filter by maximum response size in bytes","required":false,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"cache_status","in":"query","description":"Filter by cache status","required":false,"schema":{"type":["string","null"]}},{"name":"container_id","in":"query","description":"Filter by container ID","required":false,"schema":{"type":["string","null"]}},{"name":"upstream_host","in":"query","description":"Filter by upstream host","required":false,"schema":{"type":["string","null"]}},{"name":"has_error","in":"query","description":"Filter by presence of error message","required":false,"schema":{"type":["boolean","null"]}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"sort_by","in":"query","description":"Sort by field (default: timestamp)","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","description":"Sort order (asc or desc, default: desc)","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of proxy logs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProxyLogsPaginatedResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/ai-agents/known":{"get":{"tags":["Proxy Logs"],"summary":"List every AI agent the detector knows how to classify.","description":"Returned in the same order as the internal taxonomy so the UI can use it as\na stable dropdown.","operationId":"list_known_ai_agents","responses":{"200":{"description":"Known AI agents","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KnownAiAgentsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/request/{request_id}":{"get":{"tags":["Proxy Logs"],"summary":"Get a proxy log by request ID (for tracing)","operationId":"get_proxy_log_by_request_id","parameters":[{"name":"request_id","in":"path","description":"Request ID from pingora","required":true,"schema":{"type":"string"}},{"name":"timestamp","in":"query","description":"Event time of the log row (ISO 8601). When provided, the lookup is\nbounded to the hypertable chunks around this instant instead of\nscanning (and decompressing) the whole retention window. The list\nendpoint already returns this value per row — always pass it when\nnavigating from a list.","required":false,"schema":{"type":["string","null"],"format":"date-time"}}],"responses":{"200":{"description":"Proxy log found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProxyLogResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Proxy log not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-agent-pages":{"get":{"tags":["Proxy Logs"],"summary":"Get the top pages accessed by a specific AI agent over a time window.","description":"Returns page paths ranked by request count, scoped to a single canonical\nagent name (e.g. `ChatGPT-User`). Use `GET /proxy-logs/ai-agents/known` to\nlist all valid agent names. Unknown agent names return an empty items array.","operationId":"get_ai_agent_pages","parameters":[{"name":"agent","in":"query","description":"Canonical agent name to filter by (e.g. `ChatGPT-User`, `ClaudeBot`).\nMust be a name returned by `GET /proxy-logs/ai-agents/known`.","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Filter by project ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"limit","in":"query","description":"Maximum rows to return. Capped at 100 server-side.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"Pages breakdown for the requested agent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiAgentPagesResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-agents":{"get":{"tags":["Proxy Logs"],"summary":"Get the per-AI-agent breakdown for a project over a time window.","operationId":"get_ai_agent_breakdown","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID (recommended for per-project analytics).","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"limit","in":"query","description":"Maximum rows to return. Capped at 100 server-side.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"path","in":"query","description":"Optional exact path filter. Only used by the AI pages breakdown — when\nset, returns the single matching page so callers can ask \"how many AI\nagents hit this page?\".","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"AI agent breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiAgentBreakdownResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-agents/timeline":{"get":{"tags":["Proxy Logs"],"summary":"Time-bucketed AI-agent request volume, split by provider or agent.","description":"Powers the \"AI agents over time\" stacked chart. Same data source as the AI\nagent breakdown (request logs), just bucketed.","operationId":"get_ai_agent_timeline","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"group_by","in":"query","description":"Grouping dimension: `provider` (default) or `agent`.","required":false,"schema":{"type":["string","null"]},"example":"provider"},{"name":"bucket","in":"query","description":"Bucket interval override (e.g. `1 hour`, `1 day`). Auto-selected from the\nwindow width when omitted.","required":false,"schema":{"type":["string","null"]},"example":"1 hour"}],"responses":{"200":{"description":"AI agent timeline","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiAgentTimelineResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-pages":{"get":{"tags":["Proxy Logs"],"summary":"Get the top pages crawled by AI agents over a time window.","operationId":"get_ai_page_breakdown","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID (recommended for per-project analytics).","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"limit","in":"query","description":"Maximum rows to return. Capped at 100 server-side.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"path","in":"query","description":"Optional exact path filter. Only used by the AI pages breakdown — when\nset, returns the single matching page so callers can ask \"how many AI\nagents hit this page?\".","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"AI page breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiPageBreakdownResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-status":{"get":{"tags":["Proxy Logs"],"summary":"HTTP status-class breakdown for AI-agent traffic — are bots being served\n(2xx) or hitting broken/blocked pages (4xx/5xx)?","operationId":"get_ai_status_breakdown","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID (recommended for per-project analytics).","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"limit","in":"query","description":"Maximum rows to return. Capped at 100 server-side.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"path","in":"query","description":"Optional exact path filter. Only used by the AI pages breakdown — when\nset, returns the single matching page so callers can ask \"how many AI\nagents hit this page?\".","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"AI status breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiStatusBreakdownResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/projects-health":{"get":{"tags":["Proxy Logs"],"summary":"Get health summaries for multiple projects (last 1 hour)","operationId":"get_projects_health","parameters":[{"name":"project_ids","in":"query","description":"Comma-separated list of project IDs","required":true,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Optional start time (ISO 8601). Defaults to `end_time - 1h`.","required":false,"schema":{"type":["string","null"]},"example":"2025-10-23T00:00:00Z"},{"name":"end_time","in":"query","description":"Optional end time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2025-10-23T23:59:59Z"},{"name":"is_bot","in":"query","description":"Filter by bot detection. Pass `false` to exclude bots, `true` for bots only.","required":false,"schema":{"type":["boolean","null"]}}],"responses":{"200":{"description":"Health summaries per project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectsHealthResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/time-buckets":{"get":{"tags":["Proxy Logs"],"summary":"Get time-bucketed statistics with optional filters","operationId":"get_time_bucket_stats","parameters":[{"name":"start_time","in":"query","description":"Start time (ISO 8601 format)","required":true,"schema":{"type":"string"},"example":"2025-10-23T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601 format)","required":true,"schema":{"type":"string"},"example":"2025-10-23T23:59:59Z"},{"name":"bucket_interval","in":"query","description":"Bucket interval (e.g., \"1 hour\", \"1 day\", \"5 minutes\")","required":false,"schema":{"type":"string"}},{"name":"method","in":"query","description":"Filter by HTTP method","required":false,"schema":{"type":"string"}},{"name":"client_ip","in":"query","description":"Filter by client IP","required":false,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Filter by project ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"host","in":"query","description":"Filter by host","required":false,"schema":{"type":"string"}},{"name":"status_code","in":"query","description":"Filter by status code","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"status_code_class","in":"query","description":"Filter by status code class (e.g. \"2xx\", \"3xx\", \"4xx\", \"5xx\")","required":false,"schema":{"type":"string"}},{"name":"routing_status","in":"query","description":"Filter by routing status","required":false,"schema":{"type":"string"}},{"name":"request_source","in":"query","description":"Filter by request source","required":false,"schema":{"type":"string"}},{"name":"is_bot","in":"query","description":"Filter by bot detection","required":false,"schema":{"type":"boolean"}},{"name":"device_type","in":"query","description":"Filter by device type","required":false,"schema":{"type":"string"}},{"name":"has_project","in":"query","description":"When true, only count requests that matched a project\n(project_id IS NOT NULL). Makes chart totals line up with the\nper-project health cards.","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Time-bucketed statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimeBucketStatsResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/today":{"get":{"tags":["Proxy Logs"],"summary":"Get today's request count with optional filters","operationId":"get_today_stats","parameters":[{"name":"method","in":"query","description":"Filter by HTTP method","required":false,"schema":{"type":["string","null"]}},{"name":"client_ip","in":"query","description":"Filter by client IP","required":false,"schema":{"type":["string","null"]}},{"name":"project_id","in":"query","description":"Filter by project ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"host","in":"query","description":"Filter by host","required":false,"schema":{"type":["string","null"]}},{"name":"status_code","in":"query","description":"Filter by status code","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"status_code_class","in":"query","description":"Filter by status code class (e.g. \"2xx\", \"3xx\", \"4xx\", \"5xx\")","required":false,"schema":{"type":["string","null"]}},{"name":"routing_status","in":"query","description":"Filter by routing status","required":false,"schema":{"type":["string","null"]}},{"name":"request_source","in":"query","description":"Filter by request source","required":false,"schema":{"type":["string","null"]}},{"name":"is_bot","in":"query","description":"Filter by bot detection","required":false,"schema":{"type":["boolean","null"]}},{"name":"device_type","in":"query","description":"Filter by device type","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Today's request count","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TodayStatsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/{id}":{"get":{"tags":["Proxy Logs"],"summary":"Get a single proxy log by ID","operationId":"get_proxy_log_by_id","parameters":[{"name":"id","in":"path","description":"Proxy log ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"timestamp","in":"query","description":"Event time of the log row (ISO 8601). When provided, the lookup is\nbounded to the hypertable chunks around this instant instead of\nscanning (and decompressing) the whole retention window. The list\nendpoint already returns this value per row — always pass it when\nnavigating from a list.","required":false,"schema":{"type":["string","null"],"format":"date-time"}}],"responses":{"200":{"description":"Proxy log found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProxyLogResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Proxy log not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/repositories":{"get":{"tags":["Git Providers"],"summary":"List synced repositories with advanced filtering","description":"Lists repositories that have been synced to the database with filtering options.\nThis provides fast access to repository metadata with filtering by connection, search, and other criteria.","operationId":"list_synced_repositories","parameters":[{"name":"page","in":"query","description":"Page number for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"sort","in":"query","description":"Sort field (name, created_at, updated_at, stars, watchers, size, issues)","required":false,"schema":{"type":"string"}},{"name":"direction","in":"query","description":"Sort direction (asc, desc)","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Search term to filter repositories","required":false,"schema":{"type":"string"}},{"name":"owner","in":"query","description":"Filter by repository owner","required":false,"schema":{"type":"string"}},{"name":"language","in":"query","description":"Filter by programming language","required":false,"schema":{"type":"string"}},{"name":"private","in":"query","description":"Filter by private status (true/false)","required":false,"schema":{"type":"boolean"}},{"name":"git_provider_connection_id","in":"query","description":"Filter by git provider connection ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of synced repositories","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryListResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{name}":{"get":{"tags":["Git Providers"],"summary":"Get repository by owner and name from any connection","operationId":"get_repository_by_name","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"connection_id","in":"query","description":"Optional specific connection ID to search","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Repository found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryResponse"}}}},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{name}/all":{"get":{"tags":["Git Providers"],"summary":"Get all repositories with same owner/name from all git providers","operationId":"get_all_repositories_by_name","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Repositories found from all providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RepositoryResponse"}}}}},"404":{"description":"No repositories found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{name}/preset":{"get":{"tags":["Git Providers"],"summary":"Get repository preset by owner and name","operationId":"get_repository_preset_by_name","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"branch","in":"query","description":"Git branch to check (defaults to repository's default branch)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Repository preset calculated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryPresetResponse"}}}},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{repo}/branches":{"get":{"tags":["Repositories"],"summary":"Get repository branches","operationId":"get_repository_branches","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"connection_id","in":"query","description":"Git provider connection ID (required when multiple connections have the same repo)","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of branches","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BranchListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{repo}/tags":{"get":{"tags":["Repositories"],"summary":"Get repository tags","operationId":"get_repository_tags","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"connection_id","in":"query","description":"Git provider connection ID (required when multiple connections have the same repo)","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of tags","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"429":{"description":"Fresh tag lookup rate limit exceeded"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{repository_id}/preset/live":{"get":{"tags":["Git Providers"],"operationId":"get_repository_preset_live","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"branch","in":"query","description":"Git branch to check (defaults to repository's default branch)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Repository presets calculated successfully - includes root preset and projects in subdirectories","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryPresetResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"The git provider rejected the stored credential - the connection must be re-authorized"},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}":{"get":{"tags":["Git Providers"],"summary":"Get repository by ID","operationId":"get_repository_by_id","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Repository found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryResponse"}}}},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}/branches":{"get":{"tags":["Repositories"],"summary":"Get repository branches by repository ID","operationId":"get_branches_by_repository_id","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of branches","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BranchListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}/commits":{"get":{"tags":["Repositories"],"summary":"List recent commits for a repository branch","operationId":"list_commits_by_repository_id","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"branch","in":"query","description":"Branch name to list commits for","required":true,"schema":{"type":"string"}},{"name":"per_page","in":"query","description":"Number of commits to return (default: 20, max: 100)","required":false,"schema":{"type":["integer","null"],"format":"int32","minimum":0}}],"responses":{"200":{"description":"List of commits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommitListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}/commits/{commit_sha}":{"get":{"tags":["Repositories"],"summary":"Check if a commit exists in a repository","operationId":"check_commit_exists","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"commit_sha","in":"path","description":"Commit SHA to check","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Commit existence check result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommitExistsResponse"}}}},"400":{"description":"Invalid commit SHA"},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"429":{"description":"Commit lookup rate limit exceeded"},"500":{"description":"Internal server error"},"502":{"description":"Git provider request failed"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}/tags":{"get":{"tags":["Repositories"],"summary":"Get repository tags by repository ID","operationId":"get_tags_by_repository_id","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of tags","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"429":{"description":"Fresh tag lookup rate limit exceeded"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/restore-runs/{id}":{"get":{"tags":["Restore"],"operationId":"get_restore_run","parameters":[{"name":"id","in":"path","description":"Restore run id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Restore run progress","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestoreRunView"}}}},"404":{"description":"Restore run not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/revenue/events":{"get":{"tags":["Revenue"],"summary":"Org-wide revenue events across every project. Powers the revenue\ntransactions page. Supports filtering by project, date range, and\nevent type.","operationId":"revenue_global_events","parameters":[{"name":"project_id","in":"query","description":"Filter to a single project","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"from","in":"query","description":"Lower bound (inclusive), ISO-8601","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"Upper bound (inclusive), ISO-8601","required":false,"schema":{"type":"string"}},{"name":"event_types","in":"query","description":"Comma-separated event types (e.g. `invoice.paid,charge.succeeded`)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max rows, default 100, max 500","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GlobalRecentEventResponse"}}}}}},"security":[{"bearer_auth":[]}]}},"/revenue/metrics/global-mrr":{"get":{"tags":["Revenue"],"summary":"Org-wide MRR total, summed across every project in the install.\nPowers the single-number MRR card on the main dashboard.","operationId":"revenue_metrics_global_mrr","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlobalMrrResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/revenue/metrics/global-summary":{"get":{"tags":["Revenue"],"summary":"Org-wide revenue summary: MRR, paid cash (30d + all-time), refunds,\nactive subscriptions/customers, and transaction count. Powers the\nheader on the Revenue transactions page.","operationId":"revenue_metrics_global_summary","parameters":[{"name":"currency","in":"query","description":"ISO-4217 currency code, default USD","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlobalRevenueSummaryResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/revenue/providers":{"get":{"tags":["Revenue"],"summary":"List registered providers (what the UI needs to render the \"Connect\"\ndropdown + its wizard instructions).","operationId":"revenue_list_providers","responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderDescriptor"}}}}}},"security":[{"bearer_auth":[]}]}},"/session-replays":{"get":{"tags":["Analytics"],"summary":"Get session replays for a project","operationId":"get_project_session_replays","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Session replays retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetProjectSessionReplaysResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/sessions/{session_id}/events":{"get":{"tags":["Events"],"summary":"Get events for a specific session","operationId":"get_session_events","parameters":[{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved session events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsSessionEventsResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Session not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings":{"get":{"tags":["Settings"],"summary":"Get application settings","operationId":"get_settings","responses":{"200":{"description":"Application settings with masked sensitive fields","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppSettingsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Settings"],"summary":"Update application settings","operationId":"update_settings","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppSettings"}}},"required":true},"responses":{"200":{"description":"Settings updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsUpdateResponse"}}}},"400":{"description":"Bad request - invalid settings"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/agent-token":{"post":{"tags":["Agents"],"summary":"Save an encrypted AI provider token for use in sandbox containers.","operationId":"save_agent_token","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveAgentTokenRequest"}}},"required":true},"responses":{"200":{"description":"Token encrypted and persisted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveAgentTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Encryption or database error"}},"security":[{"bearer_auth":[]}]}},"/settings/ai-providers":{"get":{"tags":["Agents"],"summary":"List the AI provider catalog. Includes per-provider \"is a credential\nconfigured?\" so the settings UI can render configured/not-configured\nbadges without leaking the encrypted credential.","operationId":"list_ai_providers","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderCatalogResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/ai-providers/{provider_id}":{"patch":{"tags":["Agents"],"summary":"Update provider-scoped settings without touching the saved credential.\nToday that means just `default_model`; future per-provider settings\n(base URL overrides, request headers, etc.) can land here too without\nchanging the shape of `save_credential`.","operationId":"update_ai_provider","parameters":[{"name":"provider_id","in":"path","description":"AI provider ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAiProviderRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAiProviderResponse"}}}},"400":{"description":"Unknown provider"},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/ai-providers/{provider_id}/activate":{"post":{"tags":["Agents"],"summary":"Activate a provider as the platform-wide default. Refuses to activate a\nprovider that doesn't have a credential saved yet — the UI enforces the\nsame rule on the button, but we re-check server-side so a stale tab\ncan't bypass it.","operationId":"activate_ai_provider","parameters":[{"name":"provider_id","in":"path","description":"AI provider ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivateProviderResponse"}}}},"400":{"description":"Provider not configured"},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/ai-providers/{provider_id}/credential":{"post":{"tags":["Agents"],"summary":"Save (or replace) a provider's credential. The credential is encrypted\nwith `EncryptionService` and stored inside\n`agent_sandbox.providers[provider_id].credentials_encrypted`.","description":"The plaintext shape depends on the flavor's `credential_format`:\n - `ApiKey` / `OauthToken`: the key/token string.\n - `ConfigFile`: the full file body (e.g. OpenCode's `auth.json`).","operationId":"save_ai_provider_credential","parameters":[{"name":"provider_id","in":"path","description":"AI provider ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveCredentialRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveCredentialResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/disk-status":{"get":{"tags":["Settings"],"summary":"Get current disk usage for the control-plane server","description":"Returns live disk usage for the monitored path along with any disks that\nmeet or exceed the configured alert threshold. Read-only — does not send\nnotifications. Used by the dashboard to surface a low-disk-space warning.","operationId":"get_disk_status","responses":{"200":{"description":"Current disk usage and threshold alerts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiskSpaceCheckResult"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/enrollment-tokens":{"get":{"tags":["Settings"],"summary":"List currently-valid node enrollment tokens (hashes elided).","operationId":"list_enrollment_tokens","responses":{"200":{"description":"Active enrollment tokens","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnrollmentTokenListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Settings"],"summary":"Mint a short-lived, single-use node enrollment token.","operationId":"mint_enrollment_token","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MintEnrollmentTokenRequest"}}},"required":true},"responses":{"200":{"description":"Enrollment token minted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MintEnrollmentTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/enrollment-tokens/{id}":{"delete":{"tags":["Settings"],"summary":"Revoke a node enrollment token by id.","operationId":"revoke_enrollment_token","parameters":[{"name":"id","in":"path","description":"Enrollment token id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Enrollment token revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsUpdateResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Enrollment token not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/join-token":{"delete":{"tags":["Settings"],"summary":"Revoke the current join token","description":"Removes the stored join token hash, allowing any node to register\n(if no other authentication is in place).","operationId":"revoke_join_token","responses":{"200":{"description":"Join token revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsUpdateResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/join-token/generate":{"post":{"tags":["Settings"],"summary":"Generate a new join token for multi-node cluster registration","description":"Creates a random 32-byte hex token, stores the SHA-256 hash in settings,\nand returns the plaintext exactly once. If a token already exists, it is replaced.","operationId":"generate_join_token","responses":{"200":{"description":"Join token generated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateJoinTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/join-token/status":{"get":{"tags":["Settings"],"summary":"Check whether a join token is currently configured","operationId":"get_join_token_status","responses":{"200":{"description":"Join token status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JoinTokenStatusResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/mcp-servers":{"get":{"tags":["Agents"],"operationId":"list_global_mcps","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListMcpsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_global_mcp","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMcpRequest"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/mcp-servers/{slug}":{"get":{"tags":["Agents"],"operationId":"get_global_mcp","parameters":[{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_global_mcp","parameters":[{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMcpRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_global_mcp","parameters":[{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"MCP server deleted"},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]}},"/settings/mcp-servers/{slug}/config/{field}":{"get":{"tags":["Agents"],"operationId":"reveal_global_mcp_config","parameters":[{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}},{"name":"field","in":"path","description":"Sensitive field path, such as url or env.API_TOKEN","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensitiveMcpConfigValueResponse"}}}},"400":{"description":"Field is not revealable"},"401":{"description":"Unauthorized"},"403":{"description":"Missing secrets:read permission"},"404":{"description":"MCP server or field not found"},"500":{"description":"Configuration read or audit failed"}},"security":[{"bearer_auth":[]}]}},"/settings/routes/refresh":{"post":{"tags":["Settings"],"summary":"Manually refresh the proxy route table","description":"Reloads all routes from the database into the in-memory proxy cache.\nUseful as a workaround when routes are out of sync.","operationId":"refresh_route_table","responses":{"200":{"description":"Route table refreshed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteRefreshResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/sandbox-rebuild":{"post":{"tags":["Agents"],"operationId":"rebuild_sandbox_image","responses":{"200":{"description":"Server-Sent Events stream of rebuild progress; final event `{\"type\":\"done\",\"success\":bool,...}`","content":{"text/event-stream":{}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/settings/sandbox-status":{"get":{"tags":["Agents"],"operationId":"get_global_sandbox_status","responses":{"200":{"description":"Global sandbox readiness for the settings page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/settings/secrets":{"get":{"tags":["Secrets"],"operationId":"list_secrets","responses":{"200":{"description":"List of global agent secrets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSecretsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Secrets"],"operationId":"upsert_secret","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertSecretRequest"}}},"required":true},"responses":{"201":{"description":"Secret created/updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecretResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/settings/secrets/{name}":{"delete":{"tags":["Secrets"],"operationId":"delete_secret","parameters":[{"name":"name","in":"path","description":"Secret name","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Secret deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Secret not found"}},"security":[{"bearer_auth":[]}]}},"/settings/skills":{"get":{"tags":["Agents"],"operationId":"list_global_skills","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSkillsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_global_skill","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSkillRequest"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/skills/upload":{"post":{"tags":["Agents"],"summary":"Upload a skill with an archive (tar.gz) — global.","operationId":"upload_global_skill","requestBody":{"content":{"multipart/form-data":{"schema":{"type":"string"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/skills/{slug}":{"get":{"tags":["Agents"],"operationId":"get_global_skill","parameters":[{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_global_skill","parameters":[{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSkillRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_global_skill","parameters":[{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Skill deleted"},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]}},"/settings/skills/{slug}/archive":{"get":{"tags":["Agents"],"summary":"Download a skill's archive (tar.gz) — global.","operationId":"download_global_skill_archive","parameters":[{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Skill archive tar.gz","content":{"application/gzip":{}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found or has no archive"}},"security":[{"bearer_auth":[]}]}},"/settings/update-status":{"get":{"tags":["Settings"],"summary":"Report whether a newer temps release is available for this install.","operationId":"get_update_status","responses":{"200":{"description":"Release update status for this install","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/teams":{"get":{"tags":["Teams"],"operationId":"list_teams","parameters":[{"name":"page","in":"query","description":"1-indexed page","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"default 20, max 100","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Paginated teams","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Teams"],"operationId":"create_team","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTeamRequest"}}},"required":true},"responses":{"201":{"description":"Team created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamResponse"}}}},"400":{"description":"Validation error"},"403":{"description":"Insufficient permissions"},"409":{"description":"Slug already taken"}},"security":[{"bearer_auth":[]}]}},"/teams/{team_id}":{"get":{"tags":["Teams"],"operationId":"get_team","parameters":[{"name":"team_id","in":"path","description":"Team id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Team","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamResponse"}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Teams"],"operationId":"delete_team","parameters":[{"name":"team_id","in":"path","description":"Team id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Team deleted"},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Teams"],"operationId":"update_team","parameters":[{"name":"team_id","in":"path","description":"Team id","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTeamRequest"}}},"required":true},"responses":{"200":{"description":"Updated team","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamResponse"}}}},"400":{"description":"Validation error"},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]}},"/teams/{team_id}/members":{"get":{"tags":["Teams"],"operationId":"list_team_members","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Members","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TeamMemberResponse"}}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Teams"],"operationId":"add_team_member","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTeamMemberRequest"}}},"required":true},"responses":{"201":{"description":"Member added","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamMemberResponse"}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"},"409":{"description":"User already a member"}},"security":[{"bearer_auth":[]}]}},"/teams/{team_id}/members/{user_id}":{"delete":{"tags":["Teams"],"operationId":"remove_team_member","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Member removed"},"403":{"description":"Insufficient permissions"},"404":{"description":"Member not found"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Teams"],"operationId":"update_team_member_role","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMemberRoleRequest"}}},"required":true},"responses":{"200":{"description":"Updated membership","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamMemberResponse"}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Member not found"}},"security":[{"bearer_auth":[]}]}},"/teams/{team_id}/projects":{"get":{"tags":["Teams"],"operationId":"list_team_projects","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Projects this team has access to","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectAccessResponse"}}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]}},"/templates":{"get":{"tags":["Templates"],"summary":"List all available templates","description":"Returns a list of all public templates, optionally filtered by tag or featured status.","operationId":"list_project_templates","parameters":[{"name":"tag","in":"query","description":"Filter templates by tag","required":false,"schema":{"type":"string"}},{"name":"featured","in":"query","description":"Only return featured templates","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of templates","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListTemplatesResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/templates/tags":{"get":{"tags":["Templates"],"summary":"List all available template tags","description":"Returns a list of all unique tags used by public templates.","operationId":"list_project_template_tags","responses":{"200":{"description":"List of tags","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListTagsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/templates/{slug}":{"get":{"tags":["Templates"],"summary":"Get a specific template by slug","description":"Returns detailed information about a single template.","operationId":"get_project_template","parameters":[{"name":"slug","in":"path","description":"Template slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Template details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Template not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/user/me":{"get":{"tags":["Authentication"],"operationId":"get_current_user","responses":{"200":{"description":"Successfully retrieved user information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/users":{"get":{"tags":["Users"],"operationId":"list_users","parameters":[{"name":"include_deleted","in":"query","description":"Include deleted users in the response","required":true,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List all users with their roles","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}}},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Users"],"summary":"Create a new user with roles","operationId":"create_user","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserRequest"}}},"required":true},"responses":{"201":{"description":"User created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}},"400":{"description":"Invalid input"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me":{"patch":{"tags":["Users"],"summary":"Update current user's information","operationId":"update_self","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSelfRequest"}}},"required":true},"responses":{"200":{"description":"User updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me/mfa":{"delete":{"tags":["Users"],"operationId":"disable_mfa","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DisableMfaRequest"}}},"required":true},"responses":{"204":{"description":"MFA disabled"},"400":{"description":"Invalid verification code"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me/mfa/setup":{"post":{"tags":["Users"],"operationId":"setup_mfa","responses":{"200":{"description":"MFA setup data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaSetupResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me/mfa/verify":{"post":{"tags":["Users"],"operationId":"verify_and_enable_mfa","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyMfaRequest"}}},"required":true},"responses":{"204":{"description":"MFA verified and enabled"},"400":{"description":"Invalid code"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me/password":{"post":{"tags":["Users"],"operationId":"change_password_self","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangePasswordRequest"}}},"required":true},"responses":{"204":{"description":"Password updated"},"400":{"description":"Validation error (weak password, same as current, MFA missing)"},"401":{"description":"Current password incorrect or MFA code invalid"},"403":{"description":"Account has no password set (SSO only)"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/{user_id}":{"delete":{"tags":["Users"],"summary":"Delete a user","operationId":"delete_user","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"User deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Cannot delete yourself or non-admin attempt"},"404":{"description":"User not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Users"],"summary":"Update user information (admin only)","operationId":"update_user","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserRequest"}}},"required":true},"responses":{"200":{"description":"User updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Non-admin attempt"},"404":{"description":"User not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/{user_id}/restore":{"post":{"tags":["Users"],"operationId":"restore_user","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"User restored successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}},"400":{"description":"User is not deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Non-admin attempt"},"404":{"description":"User not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/{user_id}/roles":{"post":{"tags":["Users"],"operationId":"assign_role","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignRoleRequest"}}},"required":true},"responses":{"200":{"description":"Role assigned successfully"},"400":{"description":"Invalid role type"},"401":{"description":"Unauthorized"},"403":{"description":"Admin role required or self-modification forbidden"},"404":{"description":"User or role not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/{user_id}/roles/{role_type}":{"delete":{"tags":["Users"],"operationId":"remove_role","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"role_type","in":"path","description":"Role type to remove","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Role removed successfully"},"400":{"description":"Invalid role type"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Cannot modify own roles or non-admin attempt"},"404":{"description":"User or role not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes":{"get":{"tags":["Sandboxes"],"operationId":"list_sandboxes","parameters":[{"name":"page","in":"query","description":"Page (1-indexed)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default 20, max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List sandboxes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSandboxesResponse"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Sandboxes"],"operationId":"create_sandbox","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSandboxBody"}}},"required":true},"responses":{"201":{"description":"Sandbox created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/rootfs":{"get":{"tags":["Sandboxes"],"summary":"Inspect rootfs storage: the Firecracker digest-keyed cache (with which\nsandboxes reference each entry) and per-VM disks. Empty on Docker-only\nhosts. Admin/read scope — this exposes host storage layout.","operationId":"rootfs_report","responses":{"200":{"description":"Rootfs storage report"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/rootfs/gc":{"post":{"tags":["Sandboxes"],"summary":"Reclaim rootfs cache entries not backing any live sandbox. Idempotent;\nsafe to call any time (live VMs hold their own per-VM disks).","operationId":"rootfs_gc","responses":{"200":{"description":"Reclaimed cache entries"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}":{"get":{"tags":["Sandboxes"],"operationId":"get_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sandbox details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"404":{"description":"Not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/cmd":{"post":{"tags":["Sandboxes"],"summary":"Run a command inside the sandbox (`@vercel/sandbox`-compatible).","description":"`wait=false` (default) returns `{ command: {..., exitCode: null} }`\nimmediately once the background task is spawned.\n\n`wait=true` streams `application/x-ndjson`: the first line is the\nrunning envelope, the second is the finished envelope with `exitCode`.","operationId":"cmd","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdBody"}}},"required":true},"responses":{"200":{"description":"Command started (wait=false) or finished (wait=true)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdResponse"}}}},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/cmd/{cmd_id}":{"get":{"tags":["Sandboxes"],"operationId":"get_cmd","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"cmd_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Command snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdResponse"}}}},"404":{"description":"Sandbox or command not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/cmd/{cmd_id}/logs":{"get":{"tags":["Sandboxes"],"summary":"Stream a command's stdout/stderr as `application/x-ndjson`\n(`@vercel/sandbox`-compatible). Each line is either\n`{stream:\"stdout\"|\"stderr\", data:\"...\"}` or\n`{stream:\"error\", data:{code, message}}`.","operationId":"cmd_logs","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"cmd_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"NDJSON stream of log events"},"404":{"description":"Sandbox or command not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/destroy":{"post":{"tags":["Sandboxes"],"operationId":"destroy_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Sandbox destroyed (alias for `/stop` with an explicit verb)"},"404":{"description":"Not found"},"409":{"description":"Sandbox belongs to an active agent run — stop the run instead"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/domain":{"get":{"tags":["Sandboxes"],"operationId":"domain","parameters":[{"name":"port","in":"query","description":"Port inside the sandbox (1..=65535)","required":true,"schema":{"type":"integer","format":"int32","minimum":0}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Preview URL for the port","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxDomainResponse"}}}},"400":{"description":"Invalid port"},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/events":{"get":{"tags":["Sandboxes"],"summary":"The operations timeline for a sandbox (lifecycle events only — never\nshell/exec activity), newest first.","operationId":"list_events","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Operations timeline","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxEventsResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/exec":{"post":{"tags":["Sandboxes"],"operationId":"exec","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecBody"}}},"required":true},"responses":{"200":{"description":"Command finished (non-zero exit is NOT an error)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecResponse"}}}},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/exec-detached":{"post":{"tags":["Sandboxes"],"operationId":"exec_detached","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecBody"}}},"required":true},"responses":{"202":{"description":"Command accepted; poll /jobs/{job_id}","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecDetachedResponse"}}}},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/extend-timeout":{"post":{"tags":["Sandboxes"],"operationId":"extend_timeout","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExtendTimeoutBody"}}},"required":true},"responses":{"200":{"description":"Timeout extended","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/mkdir":{"post":{"tags":["Sandboxes"],"operationId":"mkdir","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MkdirBody"}}},"required":true},"responses":{"204":{"description":"Directory created (or already existed)"},"400":{"description":"Validation error"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/read":{"get":{"tags":["Sandboxes"],"operationId":"read_file","parameters":[{"name":"path","in":"query","description":"Absolute file path inside the sandbox","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"File contents (base64)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReadFileResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Sandbox or file not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/stat":{"get":{"tags":["Sandboxes"],"operationId":"stat_path","parameters":[{"name":"path","in":"query","description":"Absolute path inside the sandbox","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Stat info (exists=false when missing — not an error)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatResponse"}}}},"400":{"description":"Validation error"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/write":{"post":{"tags":["Sandboxes"],"summary":"Write a file into the sandbox. Accepts two body shapes — the SDK\npicks one based on `Content-Type`:","description":"- **`application/json`** (temps-native): `{path, contents_b64, mode}`\n — one file, base64-encoded.\n- **`application/gzip`** (`@vercel/sandbox`): a gzipped tarball of\n one-or-more entries, with the target extract dir carried in the\n `x-cwd` header. The SDK's `writeFile` and `writeFiles` both post\n here; they differ only in how many entries the tarball contains.\n\nWhy merge them on one route: the SDK is hardcoded to\n`POST /fs/write`, so splitting tar uploads onto a separate path would\nforce us to break SDK compat. Instead we dispatch on Content-Type,\npreserve JSON for native callers, and add tar for SDK callers.","operationId":"write_file","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WriteFileBody"}}},"required":true},"responses":{"204":{"description":"File(s) written"},"400":{"description":"Validation error or invalid base64"},"404":{"description":"Sandbox not found"},"415":{"description":"Unsupported Content-Type (expected application/json or application/gzip)"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/write-batch":{"post":{"tags":["Sandboxes"],"summary":"Batch-write multiple files in a single request. Mirrors\n`@vercel/sandbox` `writeFiles()`. Semantics are fail-fast: if any\nfile errors, previously-written entries are left in place and the\nerror describes which file broke.","operationId":"write_files","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WriteFilesBody"}}},"required":true},"responses":{"200":{"description":"All files written","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WriteFilesResponse"}}}},"400":{"description":"Validation error or invalid base64"},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/jobs":{"get":{"tags":["Sandboxes"],"operationId":"list_jobs","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Detached jobs for this sandbox","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListJobsResponse"}}}},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/jobs/{job_id}":{"get":{"tags":["Sandboxes"],"operationId":"job_status","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"job_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Job status snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobStatusResponse"}}}},"404":{"description":"Sandbox or job not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/jobs/{job_id}/kill":{"post":{"tags":["Sandboxes"],"summary":"Terminate a detached job. Aborts the server-side tracking task and\nsends SIGTERM (or SIGKILL if `force=true`) to any matching processes\ninside the sandbox container. Returns 204 on success; 404 if the\nsandbox or job is unknown.","operationId":"kill_job","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"job_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KillJobBody"}}},"required":true},"responses":{"204":{"description":"Job killed"},"404":{"description":"Sandbox or job not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/jobs/{job_id}/logs":{"get":{"tags":["Sandboxes"],"summary":"SSE endpoint streaming each stdout/stderr line from a detached job\nas it's produced. Mirrors the `Command.logs()` async iterator shape\non `@vercel/sandbox` — events carry `{ stream, data }`.","description":"Late subscribers only see events produced after they connect. The\nJobState snapshot (`GET /jobs/{job_id}`) covers the history.\n\nA \"done\" sentinel event fires when the broadcast channel closes\n(the exec task has exited and dropped the sender), signalling\ncallers they can stop reading.","operationId":"job_logs","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"job_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"SSE stream of log events"},"404":{"description":"Sandbox or job not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/pause":{"post":{"tags":["Sandboxes"],"operationId":"pause_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sandbox paused (container stopped, state preserved)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Sandbox is in an incompatible state (e.g. already destroyed)"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/preview-link":{"post":{"tags":["Sandboxes"],"summary":"Mint a shareable link to a sandbox preview.","description":"`GET /domain` returns the bare preview URL, which is useless to anyone who\ndoes not already hold the sandbox's preview password — so sharing a\nprotected preview meant sharing that password, which is the same secret for\nevery recipient and can only be withdrawn by rotating it for all of them.\n\nThis returns the same URL carrying a short-lived, sandbox-scoped grant. The\nrecipient's browser exchanges it for the ordinary preview cookie and lands\non `path`. The grant never reaches the sandbox, so preview application code\ncannot read it and re-share it.\n\nAnyone holding the returned URL can view the preview until it expires;\nthere is no per-link revocation short of rotating the preview password.","operationId":"sandbox_create_preview_link","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewShareLinkBody"}}},"required":true},"responses":{"200":{"description":"Shareable preview link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewShareLinkResponse"}}}},"400":{"description":"Invalid port"},"404":{"description":"Sandbox not found"},"409":{"description":"Sandbox has no preview password"},"500":{"description":"Preview grant minting failed"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/preview-password":{"put":{"tags":["Sandboxes"],"operationId":"set_preview_password","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPreviewPasswordBody"}}},"required":true},"responses":{"200":{"description":"Preview password set or rotated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPreviewPasswordResponse"}}}},"400":{"description":"Password too short or too long"},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Sandboxes"],"operationId":"clear_preview_password","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Preview password removed (sandbox is now URL-only protected)"},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/resize":{"post":{"tags":["Sandboxes"],"summary":"Grow a Firecracker sandbox's root disk. Offline resize — the VM reboots\n(filesystem/data persist) rather than resizing fully live.","operationId":"resize_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResizeSandboxBody"}}},"required":true},"responses":{"200":{"description":"Resized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"400":{"description":"Invalid size or unsupported backend"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/restart":{"post":{"tags":["Sandboxes"],"operationId":"restart_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sandbox container restarted in place","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Sandbox is stopped (use /resume) or already destroyed"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/resume":{"post":{"tags":["Sandboxes"],"operationId":"resume_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sandbox resumed; expires_at refreshed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Sandbox is not in a resumable state"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/source":{"post":{"tags":["Sandboxes"],"operationId":"source_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceBody"}}},"required":true},"responses":{"200":{"description":"Source content seeded into the sandbox work dir","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"400":{"description":"Validation error (embedded creds, conflicting fields, etc.)"},"404":{"description":"Sandbox not found"},"409":{"description":"Sandbox is not running"},"500":{"description":"Source seed failed inside sandbox"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/stop":{"post":{"tags":["Sandboxes"],"operationId":"stop_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Sandbox stopped and destroyed"},"404":{"description":"Not found"},"409":{"description":"Sandbox belongs to an active agent run — stop the run instead"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/{cmd_id}/kill":{"post":{"tags":["Sandboxes"],"summary":"Kill a running command (`@vercel/sandbox`-compatible). The SDK\ncalls `POST /v1/sandboxes/{id}/{cmdId}/kill` — note the path has the\ncommand ID directly under the sandbox, NOT under `/jobs/` or `/cmd/`.","operationId":"cmd_kill","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"cmd_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdKillBody"}}}},"responses":{"200":{"description":"Command killed; returns final snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdResponse"}}}},"404":{"description":"Sandbox or command not found"}},"security":[{"bearer_auth":[]}]}},"/visitors/{visitor_id}/session-replays":{"get":{"tags":["Analytics"],"summary":"Get session replays for a visitor","operationId":"get_visitor_sessions","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Session replays retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetVisitorSessionsResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/visitors/{visitor_id}/session-replays/{session_id}":{"get":{"tags":["Analytics"],"summary":"Get session replay data with visitor info (without events)","operationId":"get_session_replay","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Session replay retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetSessionReplayResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Analytics"],"summary":"Delete a session replay","operationId":"delete_session_replay","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Session replay deleted successfully"},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/visitors/{visitor_id}/session-replays/{session_id}/duration":{"put":{"tags":["Analytics"],"summary":"Update session duration","operationId":"update_session_duration","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSessionDurationRequest"}}},"required":true},"responses":{"200":{"description":"Session duration updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSessionDurationResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/visitors/{visitor_id}/session-replays/{session_id}/events":{"get":{"tags":["Analytics"],"summary":"Get session replay events (with session and visitor metadata)","operationId":"get_session_replay_events","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Session replay with events retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionReplayWithEventsDto"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Analytics"],"summary":"Add events to an existing session","operationId":"add_events","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddEventsRequest"}}},"required":true},"responses":{"200":{"description":"Events added successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddEventsResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/vulnerability-scans/{scan_id}":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_scan","parameters":[{"name":"scan_id","in":"path","description":"Scan ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Scan details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Scan not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Vulnerability Scans"],"operationId":"delete_scan","parameters":[{"name":"scan_id","in":"path","description":"Scan ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Scan deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Scan not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/vulnerability-scans/{scan_id}/vulnerabilities":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_scan_vulnerabilities","parameters":[{"name":"scan_id","in":"path","description":"Scan ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"severity","in":"query","description":"Filter by severity (CRITICAL, HIGH, MEDIUM, LOW)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of vulnerabilities","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/VulnerabilityResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Scan not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/webhook-event-types":{"get":{"tags":["Webhooks"],"summary":"List available event types","operationId":"list_event_types","responses":{"200":{"description":"List of available event types","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventTypeResponse"}}}}}}}},"/weekly-digest/trigger":{"post":{"tags":["Notification Preferences"],"summary":"Trigger weekly digest generation manually","operationId":"trigger_weekly_digest","responses":{"200":{"description":"Weekly digest triggered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerDigestResponse"}}}},"500":{"description":"Failed to generate digest"}},"security":[{"bearer_auth":[]}]}},"/x/plugins":{"get":{"tags":["External Plugins"],"summary":"List all running external plugins and their manifests.","description":"Requires only a valid session/token (no specific permission) since the\nmanifest drives sidebar navigation rendering for every authenticated\nuser, not just admins.","operationId":"list_external_plugins","responses":{"200":{"description":"List of all running external plugins","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PluginManifest"}}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/x/plugins/reload":{"post":{"tags":["External Plugins"],"summary":"Reload all external plugins.","description":"Stops all running plugin processes, re-scans the plugins directory,\nstarts any discovered binaries, and hot-swaps the proxy router so new\nand removed plugins take effect immediately without a server restart.\n\nRequires `SystemAdmin` permission.","operationId":"reload_plugins","responses":{"200":{"description":"Plugins reloaded successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReloadResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/{project_id}/envelope/":{"post":{"tags":["sentry-ingestor"],"summary":"Ingest a Sentry envelope (binary payload)","operationId":"ingest_sentry_envelope","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"Sentry envelope as binary data","content":{"application/octet-stream":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Envelope ingested"},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"413":{"description":"Request body too large (exceeds 2 MiB)"}}}},"/{project_id}/store/":{"post":{"tags":["sentry-ingestor"],"summary":"Ingest a Sentry event (JSON payload)","operationId":"ingest_sentry_event","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryEventRequest"}}},"required":true},"responses":{"200":{"description":"Event ingested","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryEventResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"413":{"description":"Request body too large (exceeds 2 MiB)"}}}},"audit/logs":{"get":{"tags":["Audit Logs"],"summary":"List audit logs with optional filtering","operationId":"list_audit_logs","parameters":[{"name":"operation_type","in":"query","description":"Filter logs by operation type (omit for all)","required":false,"schema":{"type":"string"},"example":"user.login"},{"name":"user_id","in":"query","description":"Filter logs by user ID (omit for all users)","required":false,"schema":{"type":"integer","format":"int32"},"example":1},{"name":"from","in":"query","description":"Start timestamp (milliseconds since epoch)","required":false,"schema":{"type":"string","format":"date-time"},"example":1},{"name":"to","in":"query","description":"End timestamp (milliseconds since epoch)","required":false,"schema":{"type":"string","format":"date-time"},"example":1},{"name":"limit","in":"query","description":"Maximum number of logs to return","required":false,"schema":{"type":"integer","format":"int32"},"example":100},{"name":"offset","in":"query","description":"Number of logs to skip","required":false,"schema":{"type":"integer","format":"int32"},"example":0}],"responses":{"200":{"description":"List of audit logs","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AuditLogResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"api_key":[]}]}},"audit/logs/{id}":{"get":{"tags":["Audit Logs"],"summary":"Get a specific audit log entry by ID","operationId":"get_audit_log","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Audit log details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuditLogResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Audit log not found"},"500":{"description":"Internal server error"}},"security":[{"api_key":[]}]}}},"components":{"schemas":{"AcmeOrderResponse":{"type":"object","required":["id","order_url","domain_id","email","status","identifiers","created_at","updated_at"],"properties":{"authorizations":{},"certificate_url":{"type":["string","null"]},"challenge_validation":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ChallengeValidationStatus","description":"Live challenge validation status fetched from Let's Encrypt"}]},"created_at":{"type":"integer","format":"int64"},"domain_id":{"type":"integer","format":"int32"},"email":{"type":"string"},"error":{"type":["string","null"]},"error_type":{"type":["string","null"]},"expires_at":{"type":["integer","null"],"format":"int64"},"finalize_url":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"identifiers":{},"order_url":{"type":"string"},"status":{"type":"string"},"updated_at":{"type":"integer","format":"int64"}}},"ActivateProviderResponse":{"type":"object","required":["default_provider"],"properties":{"default_provider":{"type":"string"}}},"ActiveVisitor":{"type":"object","required":["session_id","session_start","last_activity","page_count","event_count","duration_seconds","is_active"],"properties":{"current_page":{"type":["string","null"]},"duration_seconds":{"type":"integer","format":"int64"},"event_count":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"last_activity":{"type":"string"},"page_count":{"type":"integer","format":"int32"},"session_id":{"type":"string"},"session_start":{"type":"string"},"visitor_id":{"type":["string","null"]}}},"ActiveVisitorsQuery":{"type":"object","properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"}}},"ActiveVisitorsResponse":{"type":"object","required":["active_visitors","window_minutes"],"properties":{"active_visitors":{"type":"integer","format":"int64"},"window_minutes":{"type":"integer","format":"int32"}}},"ActivityDay":{"type":"object","description":"Daily activity count for a single day","required":["date","count","level"],"properties":{"count":{"type":"integer","format":"int64","description":"Number of deployments on this day"},"date":{"type":"string","description":"Date in YYYY-MM-DD format","example":"2024-06-15"},"level":{"type":"integer","format":"int32","description":"Intensity level (0-4) for visualization\n0: No activity, 1: Low (1-2), 2: Medium (3-5), 3: High (6-10), 4: Very High (11+)","example":2}}},"ActivityEvent":{"type":"object","description":"A single activity event for the real-time activity feed","required":["id","timestamp","event_type","page_path","is_crawler"],"properties":{"browser":{"type":["string","null"],"description":"Browser"},"city":{"type":["string","null"],"description":"Visitor's city (from ip_geolocations)"},"country":{"type":["string","null"],"description":"Visitor's country (from ip_geolocations)"},"country_code":{"type":["string","null"],"description":"Visitor's country code (from ip_geolocations)"},"device_type":{"type":["string","null"],"description":"Device type"},"event_name":{"type":["string","null"],"description":"Event name (for custom events)"},"event_type":{"type":"string","description":"Event type: \"page_view\", \"custom\", etc."},"id":{"type":"integer","format":"int64","description":"Event ID"},"is_crawler":{"type":"boolean","description":"Whether this event was from a crawler"},"latitude":{"type":["number","null"],"format":"double","description":"Latitude"},"longitude":{"type":["number","null"],"format":"double","description":"Longitude"},"operating_system":{"type":["string","null"],"description":"Operating system"},"page_path":{"type":"string","description":"Page path where the event happened"},"page_title":{"type":["string","null"],"description":"Page title"},"referrer":{"type":["string","null"],"description":"Referrer"},"timestamp":{"type":"string","format":"date-time","description":"When the event occurred"},"visitor_id":{"type":["integer","null"],"format":"int32","description":"Visitor numeric ID"}}},"ActivityGraphQuery":{"type":"object","description":"Query parameters for activity graph endpoint","properties":{"days":{"type":"integer","format":"int32","description":"Number of days to include (default: 365 for last year)"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment ID to filter activity"},"project_id":{"type":["integer","null"],"format":"int32","description":"Optional project ID to filter activity"}}},"ActivityGraphResponse":{"type":"object","description":"Response for activity graph showing daily deployment activity","required":["days","total_count","start_date","end_date"],"properties":{"days":{"type":"array","items":{"$ref":"#/components/schemas/ActivityDay"},"description":"Array of daily activity counts"},"end_date":{"type":"string","description":"Date range end (YYYY-MM-DD)","example":"2024-12-31"},"start_date":{"type":"string","description":"Date range start (YYYY-MM-DD)","example":"2024-01-01"},"total_count":{"type":"integer","format":"int64","description":"Total count of activities across all days"}}},"AddClusterMemberRequest":{"type":"object","description":"Request body for adding a single member to a running cluster.","required":["role"],"properties":{"node_id":{"type":["integer","null"],"format":"int32","description":"Target worker node ID. Omit or null to run on the control plane."},"role":{"type":"string","description":"Member role. Currently only `replica` is accepted at runtime —\nmonitor is a singleton, primary is elected by pg_auto_failover.","example":"replica"}}},"AddContextRequest":{"type":"object","required":["message"],"properties":{"message":{"type":"string"}}},"AddEnvironmentDomainRequest":{"type":"object","required":["domain","is_primary"],"properties":{"domain":{"type":"string"},"is_primary":{"type":"boolean"}}},"AddEventsRequest":{"type":"object","required":["events"],"properties":{"events":{"type":"string"}}},"AddEventsResponse":{"type":"object","required":["event_count","message"],"properties":{"event_count":{"type":"integer","minimum":0},"message":{"type":"string"}}},"AddManagedDomainApiRequest":{"type":"object","description":"Request to add a managed domain","required":["domain"],"properties":{"auto_manage":{"type":"boolean"},"domain":{"type":"string","example":"example.com"},"generated_hostname_mode":{"type":["string","null"],"description":"Generated hostname layout: `\"standard\"` (default) or `\"flat\"`."},"sync_generated_records":{"type":"boolean","description":"Opt in to reconciling generated hostnames into this domain's DNS zone."}}},"AdminGateResponse":{"type":"object","required":["allowed_ips","allowed_hosts","trust_forwarded_for","source","editable"],"properties":{"allowed_hosts":{"type":"array","items":{"type":"string"},"description":"`Host` header values allowed. Empty = any host."},"allowed_ips":{"type":"array","items":{"type":"string"},"description":"IPs / CIDRs allowed to reach the admin listener. Empty = any source."},"editable":{"type":"boolean","description":"True when the config is writable through this API. False when env\nvars are dictating the active config."},"source":{"$ref":"#/components/schemas/AdminGateSource","description":"Where the active config came from."},"trust_forwarded_for":{"type":"boolean","description":"When true, the gate trusts `X-Forwarded-For` from loopback peers."}}},"AdminGateSource":{"type":"string","description":"Where the active gate configuration came from. Env-supplied configs are\nfrozen at the process level — the UI shows them read-only and refuses to\npersist DB writes. DB-supplied configs are editable at runtime.","enum":["default","db","env"]},"AgentConfigResponse":{"type":"object","description":"Response DTO for a single agent — masks the encrypted API key.","required":["id","project_id","slug","name","source","enabled","trigger_config","ai_provider","api_key_set","max_turns","timeout_seconds","daily_budget_cents","cooldown_minutes","branch_prefix","deliverable","created_at","updated_at"],"properties":{"ai_model":{"type":["string","null"],"description":"Preferred model for the CLI (e.g. \"sonnet\", \"gpt-5-codex\"). `None` means default."},"ai_provider":{"type":"string"},"ai_provider_key_id":{"type":["integer","null"],"format":"int32"},"api_key_set":{"type":"boolean","description":"`true` if an API key is set; `false` otherwise."},"branch_prefix":{"type":"string"},"config_repo_branch":{"type":["string","null"],"description":"Branch of the config repo to use."},"config_repo_url":{"type":["string","null"],"description":"Private config repo containing .claude/ directory (skills, MCP, plugins)."},"cooldown_minutes":{"type":"integer","format":"int32"},"created_at":{"type":"string"},"daily_budget_cents":{"type":"integer","format":"int32"},"deliverable":{"type":"string"},"description":{"type":["string","null"]},"enabled":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"max_turns":{"type":"integer","format":"int32"},"mcp_servers_config":{"description":"MCP servers config (Claude Code settings.json mcpServers format).\nCredential-bearing legacy inline values are write-only and appear as\n`***`. Omit this field on update to preserve their stored values."},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"prompt":{"type":["string","null"]},"sandbox_enabled":{"type":["boolean","null"],"description":"None = use global sandbox setting, true = force on, false = force off"},"skills_config":{"description":"Skills config as JSON array."},"slug":{"type":"string"},"source":{"type":"string"},"timeout_seconds":{"type":"integer","format":"int32"},"tools_config":{"description":"Tools config as JSON array. Legacy custom-tool webhook URLs and headers\nare write-only and appear as `***`. Omit this field on update to\npreserve their stored values."},"trigger_config":{},"updated_at":{"type":"string"},"webhook_token":{"type":["string","null"],"description":"Secret token for the `X-Webhook-Token` header. Shown once when created,\nmasked with `***` prefix in subsequent reads."},"webhook_url":{"type":["string","null"],"description":"Public webhook URL for triggering this agent externally.\nOnly set when `on: { webhook: true }` is configured.\nUsage: `POST {webhook_url}` with header `X-Webhook-Token: {webhook_token}`"}}},"AgentRunLogResponse":{"type":"object","required":["id","run_id","level","message","created_at"],"properties":{"created_at":{"type":"string"},"id":{"type":"integer","format":"int64"},"level":{"type":"string"},"message":{"type":"string"},"metadata":{},"run_id":{"type":"integer","format":"int32"}}},"AgentRunResponse":{"type":"object","required":["id","project_id","source","trigger_type","status","tokens_input","tokens_output","estimated_cost_cents","files_changed","created_at","sandbox_enabled"],"properties":{"agent_name":{"type":["string","null"],"description":"Name of the agent that created this run, if available."},"agent_slug":{"type":["string","null"],"description":"Slug of the agent that created this run, if available."},"ai_model":{"type":["string","null"]},"ai_output":{"type":["string","null"]},"ai_provider":{"type":["string","null"],"description":"AI provider slug that executed this run (e.g. claude_cli, codex_cli, opencode)."},"ai_reasoning":{"type":["string","null"]},"ai_session_id":{"type":["string","null"],"description":"Claude CLI session UUID for resuming conversations via `--resume`."},"analysis":{"type":["string","null"],"description":"Report / analysis text produced by the agent (used for report/notification deliverables)."},"branch_name":{"type":["string","null"]},"commit_sha":{"type":["string","null"]},"completed_at":{"type":["string","null"]},"config_id":{"type":["integer","null"],"format":"int32","description":"Optional. NULL for ephemeral CLI runs (`source = \"cli_ephemeral\"`) and\nhistorical autofixer runs that pre-date the agent_id column."},"created_at":{"type":"string"},"ephemeral_yaml":{"type":["string","null"],"description":"Full WorkflowYamlConfig as YAML text. Populated only when\n`source = \"cli_ephemeral\"`. Used by the web UI to show a \"View YAML\"\nmodal so the user can see exactly what the executor ran."},"error_message":{"type":["string","null"]},"estimated_cost_cents":{"type":"integer","format":"int32"},"files_changed":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"phase":{"type":["string","null"],"description":"Autofixer phase: \"analyzing\", \"analyzed\", \"fixing\", \"fix_ready\", \"no_fix\",\n\"pr_created\", or NULL for non-autofixer runs."},"pr_number":{"type":["integer","null"],"format":"int32"},"pr_url":{"type":["string","null"]},"preview_url":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"prompt_text":{"type":["string","null"],"description":"Final assembled prompt the AI CLI actually saw (trigger context block +\nYAML prompt, with error-group fields interpolated). Captured once per\nrun. `None` for pre-migration rows."},"run_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AutofixRunConfig","description":"Per-run AI options the user chose when starting an autofixer run\n(provider, model, max_turns, branch). NULL for generic agent runs\nand historical rows. Used to prefill the retry dialog."}]},"sandbox_enabled":{"type":"boolean","description":"Legacy field — all runs now execute in a sandbox. Kept for\nbackwards-compatible JSON shape; always `true`."},"source":{"type":"string","description":"`committed` (the run's config lives in `project_agents`) or\n`cli_ephemeral` (the config was uploaded via the CLI for a one-off\ndry run; see `ephemeral_yaml`)."},"started_at":{"type":["string","null"]},"status":{"type":"string"},"tokens_input":{"type":"integer","format":"int32"},"tokens_output":{"type":"integer","format":"int32"},"trigger_source_id":{"type":["integer","null"],"format":"int32"},"trigger_source_type":{"type":["string","null"]},"trigger_type":{"type":"string"},"user_context":{"type":["string","null"],"description":"User-provided context for this run (e.g. webhook payload, manual instructions)."}}},"AgentRunWithLogsResponse":{"type":"object","required":["run","logs"],"properties":{"logs":{"type":"array","items":{"$ref":"#/components/schemas/AgentRunLogResponse"}},"run":{"$ref":"#/components/schemas/AgentRunResponse"}}},"AgentSandboxSettings":{"type":"object","description":"Global agent sandbox settings. Controls whether agent runs are isolated\ninside Docker containers by default. Individual agents can override this.","properties":{"api_key_encrypted":{"type":["string","null"],"description":"DEPRECATED: use `providers[default_provider].credentials_encrypted` instead.","default":null},"auth_type":{"type":"string","description":"DEPRECATED: use `providers[default_provider].auth_type` instead.","default":"subscription"},"cpu_limit":{"type":"number","format":"double","description":"CPU limit in cores for sandbox containers","default":4.0,"example":4.0},"custom_image":{"type":"string","description":"Custom Docker image (only used when runtime is \"custom\").\nMust have git and claude CLI installed.","default":"","example":""},"default_provider":{"type":"string","description":"Default AI provider for agents: \"claude_cli\", \"opencode\", or \"codex_cli\".\nWorkspaces always use this provider — no per-session override.","default":"claude_cli","example":"claude_cli"},"enabled":{"type":"boolean","description":"Sandbox is always enabled — the executor refuses to run any agent\noutside a sandboxed container. Field is retained so existing settings\nrows still deserialize, but it is ignored at runtime.","default":true},"memory_limit_mb":{"type":"integer","format":"int64","description":"Memory limit in MB for sandbox containers","default":8192,"example":8192,"minimum":0},"network_mode":{"type":"string","description":"Network access level: \"full\" (unrestricted), \"restricted\" (Temps network only), \"none\" (no network)","default":"full","example":"full"},"providers":{"type":"object","description":"Per-provider auth + config. Keyed by provider id (e.g. `claude_cli`,\n`codex_cli`, `opencode`). Adding a new provider only requires a new\ncatalog entry on the Rust side — the JSON column stays migration-free.","default":{},"additionalProperties":{"$ref":"#/components/schemas/ProviderConfig"},"propertyNames":{"type":"string"}},"runtime":{"type":"string","description":"Runtime preset: \"node\", \"bun\", \"python\", \"rust\", \"go\", \"full\", or \"custom\"","default":"node","example":"node"},"sandbox_backend":{"type":["string","null"],"description":"Default isolation backend for sandboxes: \"docker\" (default) or\n\"firecracker\" (ADR-029; requires `temps firecracker setup`). Only\nconsulted when the Firecracker backend probes available — otherwise\nDocker is used regardless.","default":null,"example":"docker"}}},"AgentSandboxSettingsMasked":{"type":"object","description":"Agent sandbox settings with masked per-provider credentials.\nEach provider entry reports only whether a credential is saved, not\nthe encrypted blob itself. Non-sensitive fields (auth_type, default_model,\nextra) are passed through so the UI can render provider-specific state.","required":["default_provider","providers","api_key_saved","auth_type","enabled","runtime","custom_image","cpu_limit","memory_limit_mb","network_mode","sandbox_backend"],"properties":{"api_key_saved":{"type":"boolean"},"auth_type":{"type":"string"},"cpu_limit":{"type":"number","format":"double"},"custom_image":{"type":"string"},"default_provider":{"type":"string"},"enabled":{"type":"boolean"},"memory_limit_mb":{"type":"integer","format":"int64","minimum":0},"network_mode":{"type":"string"},"providers":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/ProviderConfigMasked"},"propertyNames":{"type":"string"}},"runtime":{"type":"string"},"sandbox_backend":{"type":"string"}}},"AggregatedBucketItem":{"type":"object","required":["timestamp","count"],"properties":{"count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"}}},"AggregatedBucketsQuery":{"type":"object","description":"Query parameters for aggregated metrics by time bucket","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events, sessions, or visitors"},"bucket_size":{"type":"string","description":"Time bucket size: \"1 hour\", \"1 day\", \"1 week\", etc. (default: \"1 hour\")"},"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment filter"},"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment filter"},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"AggregatedBucketsResponse":{"type":"object","required":["bucket_size","aggregation_level","items","total"],"properties":{"aggregation_level":{"type":"string"},"bucket_size":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AggregatedBucketItem"}},"total":{"type":"integer","format":"int64"}}},"AggregationLevel":{"type":"string","enum":["events","sessions","visitors"]},"AggregationTemporality":{"type":"string","description":"The aggregation temporality of a Sum/Histogram/ExponentialHistogram metric.\n\nMirrors OTel's `AggregationTemporality` proto enum: whether reported values\nare cumulative since the start of the series (Cumulative) or only the delta\nsince the previous report (Delta).","enum":["unspecified","delta","cumulative"]},"AiAgentBreakdownResponse":{"type":"object","description":"Response wrapping the AI agent breakdown rows.","required":["items","start_time","end_time"],"properties":{"end_time":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiAgentBreakdownRow"}},"start_time":{"type":"string"}}},"AiAgentBreakdownRow":{"type":"object","description":"One row in the AI-agent analytics breakdown. `agent` is the canonical\ncrawler name (e.g. `GPTBot`, `Claude-User`), `provider` is the vendor used\nfor grouping + logos. The UI mirrors the browsers card and ranks by\n`request_count`.","required":["provider","agent","purpose","request_count","unique_ips"],"properties":{"agent":{"type":"string"},"last_seen":{"type":["string","null"],"description":"Last-seen timestamp in RFC3339 format, or `None` if no rows matched.","example":"2026-05-29T12:00:00Z"},"provider":{"type":"string"},"purpose":{"type":"string"},"request_count":{"type":"integer","format":"int64"},"unique_ips":{"type":"integer","format":"int64"}}},"AiAgentDescriptor":{"type":"object","description":"Static descriptor for one entry in the known-AI-agents taxonomy.","required":["provider","agent","purpose"],"properties":{"agent":{"type":"string"},"provider":{"type":"string"},"purpose":{"type":"string"}}},"AiAgentPageRow":{"type":"object","description":"One row in the pages-by-agent breakdown. Returned by\n[`ProxyLogService::get_ai_agent_pages`] for a single named agent.\n`unique_ips` counts distinct client IPs that hit this path via that agent\n(same definition as the per-agent unique-IPs in [`AiAgentBreakdownRow`]).","required":["path","request_count","unique_ips"],"properties":{"last_seen":{"type":["string","null"],"description":"Last-seen timestamp in RFC3339 format, or `None` if no rows matched.","example":"2026-05-29T12:00:00Z"},"path":{"type":"string"},"request_count":{"type":"integer","format":"int64"},"unique_ips":{"type":"integer","format":"int64"}}},"AiAgentPagesResponse":{"type":"object","description":"Response wrapping the per-agent pages breakdown rows.","required":["agent","items","start_time","end_time"],"properties":{"agent":{"type":"string","description":"The agent name this breakdown is scoped to."},"end_time":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiAgentPageRow"}},"start_time":{"type":"string"}}},"AiAgentTimelineResponse":{"type":"object","description":"Response wrapping the AI agent timeline rows.","required":["items","start_time","end_time","bucket","group_by"],"properties":{"bucket":{"type":"string","description":"Bucket interval used for the buckets (so the UI can label the x-axis).","example":"1 hour"},"end_time":{"type":"string"},"group_by":{"type":"string","description":"Echoes the grouping dimension actually applied.","example":"provider"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiAgentTimelineRow"}},"start_time":{"type":"string"}}},"AiAgentTimelineRow":{"type":"object","description":"One point in the AI-agent timeline: the request count for a single\n(`bucket`, `key`) pair, where `key` is a provider or agent name depending on\nthe requested grouping. The UI pivots these into one stacked series per\n`key` across the shared bucket x-axis.","required":["bucket","key","request_count"],"properties":{"bucket":{"type":"string","description":"Bucket start in RFC3339 format.","example":"2026-05-29T12:00:00Z"},"key":{"type":"string","description":"Provider or agent name this count belongs to.","example":"OpenAI"},"request_count":{"type":"integer","format":"int64"}}},"AiChatLimitsSettings":{"type":"object","description":"Bounds on one AI chat turn.\n\nA turn is bounded by TIME rather than by a number of steps. A step count\nsays nothing about cost or about how long someone has been watching a\nspinner, and it cuts short exactly the long, productive turns the chat\nexists for. The user can already see each tool call and press Stop; the\ndeadline is what guarantees an *unattended* turn still ends.\n\nThe right value is a property of the model, which is why it is configurable\nrather than compiled in: a full alert-suggestion turn takes ~10 minutes\nagainst a slow local model and seconds against a hosted one.","properties":{"turn_timeout_secs":{"type":"integer","format":"int32","description":"How long one turn may run before it is stopped and the partial answer\nreturned, in seconds. The user is told the turn was cut short.\n\nChecked between steps, not mid-call: a model round already in flight\nfinishes, so a turn can overrun by up to one round. Against a slow\nself-hosted model that is a minute or two. Aborting mid-stream would cut\nthe answer off in the middle of a sentence and throw away work already\npaid for, which is worse than a late stop.","default":900,"example":900,"maximum":3600,"minimum":30}}},"AiConfigSettings":{"type":"object","description":"Global AI configuration settings. Controls the default config repo\ncontaining `.claude/` directory (skills, MCP servers, plugins) that\ngets overlaid into every agent sandbox.","properties":{"config_repo":{"type":"string","description":"Global config repo URL in \"owner/repo\" format (e.g. \"myorg/claude-config\").\nCloned at agent run time and overlaid into the sandbox's `.claude/` directory.","default":"","example":""},"config_repo_branch":{"type":"string","description":"Branch of the config repo to use.","default":"main","example":"main"}}},"AiPageBreakdownResponse":{"type":"object","description":"Response wrapping the AI page breakdown rows.","required":["items","start_time","end_time"],"properties":{"end_time":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiPageBreakdownRow"}},"start_time":{"type":"string"}}},"AiPageBreakdownRow":{"type":"object","description":"One row in the AI-crawled-pages breakdown. `agent_count` is the number of\n*distinct* AI agents that hit this path, so the UI can show both how heavily\nand how broadly a page is being crawled.","required":["path","request_count","agent_count"],"properties":{"agent_count":{"type":"integer","format":"int64"},"last_seen":{"type":["string","null"],"description":"Last-seen timestamp in RFC3339 format, or `None` if no rows matched.","example":"2026-05-29T12:00:00Z"},"path":{"type":"string"},"request_count":{"type":"integer","format":"int64"}}},"AiStatusBreakdownResponse":{"type":"object","description":"Response wrapping the AI status breakdown rows.","required":["items","start_time","end_time"],"properties":{"end_time":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiStatusBreakdownRow"}},"start_time":{"type":"string"}}},"AiStatusBreakdownRow":{"type":"object","description":"One row in the AI-agent HTTP status breakdown: the request count for a\nstatus class (`2xx`/`3xx`/`4xx`/`5xx`/`other`) across crawler traffic.","required":["status_class","request_count"],"properties":{"request_count":{"type":"integer","format":"int64"},"status_class":{"type":"string","description":"Status class label.","example":"2xx"}}},"AlarmListResponse":{"type":"object","description":"Paginated list of alarms.","required":["items","total","page","page_size"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AlarmResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"AlarmResponse":{"type":"object","description":"Full alarm representation returned by list/summary endpoints.","required":["id","project_id","alarm_type","severity","status","title","fired_at","created_at","updated_at"],"properties":{"acknowledged_at":{"type":["string","null"],"description":"ISO-8601 UTC timestamp when the alarm was acknowledged, if any."},"acknowledged_by":{"type":["integer","null"],"format":"int32","description":"User ID who acknowledged the alarm, if any."},"alarm_type":{"type":"string"},"container_id":{"type":["integer","null"],"format":"int32"},"created_at":{"type":"string","description":"ISO-8601 UTC timestamp when the row was created."},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"fired_at":{"type":"string","description":"ISO-8601 UTC timestamp when the alarm fired."},"id":{"type":"integer","format":"int32"},"message":{"type":["string","null"]},"metadata":{"description":"Arbitrary JSON metadata attached by the alarm source."},"project_id":{"type":"integer","format":"int32"},"resolved_at":{"type":["string","null"],"description":"ISO-8601 UTC timestamp when the alarm was resolved, if any."},"service_id":{"type":["integer","null"],"format":"int32"},"severity":{"type":"string"},"status":{"type":"string"},"title":{"type":"string"},"updated_at":{"type":"string","description":"ISO-8601 UTC timestamp when the row was last updated."}}},"AlarmSummaryResponse":{"type":"object","description":"Re-export AlarmSummary for the OpenAPI schema.","required":["total_active","firing","acknowledged","critical","warning","by_type"],"properties":{"acknowledged":{"type":"integer","format":"int32","minimum":0},"by_type":{"type":"object","additionalProperties":{"type":"integer","format":"int32","minimum":0},"propertyNames":{"type":"string"}},"critical":{"type":"integer","format":"int32","minimum":0},"firing":{"type":"integer","format":"int32","minimum":0},"total_active":{"type":"integer","format":"int32","minimum":0},"warning":{"type":"integer","format":"int32","minimum":0}}},"AlertRuleResponse":{"type":"object","required":["id","project_id","name","trigger_type","trigger_config","notification_priority","cooldown_minutes","enabled","created_at","updated_at"],"properties":{"cooldown_minutes":{"type":"integer","format":"int32"},"created_at":{"type":"string"},"enabled":{"type":"boolean"},"environment_filter":{"type":["integer","null"],"format":"int32"},"error_level_filter":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"notification_priority":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"trigger_config":{},"trigger_type":{"type":"string"},"updated_at":{"type":"string"}}},"AllocEntry":{"type":"object","description":"Wire-format allocation. `null` in the JSON when the node hasn't been\nallocated yet — workers should treat that as \"single-host mode, do\nnot bring up the overlay\".","required":["node_id","compute_cidr","bridge_address","underlay_address"],"properties":{"bridge_address":{"type":"string"},"compute_cidr":{"type":"string"},"node_id":{"type":"string","description":"Stable v5 UUID derived from the database node id."},"underlay_address":{"type":"string"}}},"AnalyticsSessionEventsResponse":{"type":"object","required":["session_id","events","total_events"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/SessionEvent"}},"session_id":{"type":"string"},"total_events":{"type":"integer","minimum":0}}},"AnnotatedSpan":{"type":"object","description":"A single span annotated with the project that originally stored it.\nUsed in `UnifiedTrace` to let the UI colour-code spans by project.","required":["project_id","project_name","span"],"properties":{"project_id":{"type":"integer","format":"int32","description":"The project that stored this span (same as `span.project_id`)."},"project_name":{"type":"string","description":"Human-readable project name for waterfall colour-coding and legend."},"span":{"$ref":"#/components/schemas/SpanRecord","description":"Original span data verbatim from storage."}}},"AnomalyAlgorithm":{"type":"string","description":"Anomaly baseline algorithm. Adding one (e.g. a new robust variant) is a\ncode-only enum addition — no migration, since it lives inside the blob.","enum":["robust","basic","agile","ewma"]},"AnomalyParams":{"type":"object","description":"Seasonal anomaly-band detector parameters (stub — not yet evaluated).","properties":{"algorithm":{"$ref":"#/components/schemas/AnomalyAlgorithm","description":"Baseline model. `robust` is the default (seasonal, stable, flags level\nshifts); `ewma`/`agile` adopt level shifts; `basic` is non-seasonal."},"baseline_lookback_days":{"type":["integer","null"],"format":"int32","description":"How far back to build the baseline. `None` = an evaluator default."},"deviations":{"type":"number","format":"double","description":"Band width in robust standard deviations (Datadog's `bounds`)."},"direction":{"$ref":"#/components/schemas/Direction","description":"Which side(s) of the band a deviation must be on to count."},"pct_anomalous":{"type":"number","format":"double","description":"Fraction (0..=1) of points in the window that must be anomalous to fire."},"seasonality":{"$ref":"#/components/schemas/Seasonality","description":"Seasonality model for the baseline."}}},"AnomalyPreviewPointResponse":{"type":"object","required":["bucket","value","lower","upper","breaching"],"properties":{"breaching":{"type":"boolean"},"bucket":{"type":"string","example":"2025-10-12T12:15:47Z"},"lower":{"type":"number","format":"double","description":"Lower edge of the expected band at this point."},"upper":{"type":"number","format":"double","description":"Upper edge of the expected band at this point."},"value":{"type":"number","format":"double"}}},"AnomalyPreviewRequest":{"type":"object","required":["project_id","metric_name","aggregation","window_secs","detection_config"],"properties":{"aggregation":{"type":"string","description":"One of `avg|sum|min|max|count|rate|p50|p90|p95|p99`."},"detection_config":{"$ref":"#/components/schemas/DetectionConfig","description":"The detector to backtest. `static` and `anomaly` are supported — the\nkinds the evaluator actually runs."},"end_time":{"type":["string","null"],"description":"RFC 3339; defaults to now.","example":"2025-10-12T12:15:47Z"},"metric_name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"start_time":{"type":["string","null"],"description":"RFC 3339; defaults to 7 days before `end_time`.","example":"2025-10-12T12:15:47Z"},"window_secs":{"type":"integer","format":"int32"}}},"AnomalyPreviewResponse":{"type":"object","required":["points","breach_count","baseline_samples","sufficient"],"properties":{"baseline_samples":{"type":"integer","format":"int64","description":"Baseline sample count (drives the `sufficient` flag)."},"breach_count":{"type":"integer","format":"int64","description":"How many points in the range would have fired."},"points":{"type":"array","items":{"$ref":"#/components/schemas/AnomalyPreviewPointResponse"}},"sufficient":{"type":"boolean","description":"Whether the baseline had enough history for a trustworthy band."}}},"ApiKeyListResponse":{"type":"object","required":["api_keys","total"],"properties":{"api_keys":{"type":"array","items":{"$ref":"#/components/schemas/ApiKeyResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"ApiKeyResponse":{"type":"object","required":["id","name","key_prefix","role_type","is_active","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00Z"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"key_prefix":{"type":"string"},"last_used_at":{"type":["string","null"],"format":"date-time","example":"2024-01-01T00:00:00Z"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"}},"role_type":{"type":"string"}}},"AppSettings":{"type":"object","description":"Application settings stored in the database\nAll fields have sensible defaults for easy onboarding","properties":{"agent_sandbox":{"oneOf":[{"$ref":"#/components/schemas/AgentSandboxSettings"}],"default":{"default_provider":"claude_cli","providers":{},"auth_type":"subscription","api_key_encrypted":null,"enabled":true,"runtime":"node","custom_image":"","cpu_limit":4.0,"memory_limit_mb":8192,"network_mode":"full","sandbox_backend":null}},"ai_chat_limits":{"oneOf":[{"$ref":"#/components/schemas/AiChatLimitsSettings","description":"Limits on a single AI chat turn. Operator-tunable because the right\nvalue depends on the model: a turn against a slow self-hosted model can\nlegitimately take ten minutes, while a hosted one finishes in seconds\nand a shorter ceiling keeps costs predictable."}],"default":{"turn_timeout_secs":900}},"ai_config":{"oneOf":[{"$ref":"#/components/schemas/AiConfigSettings"}],"default":{"config_repo":"","config_repo_branch":"main"}},"build_limits":{"oneOf":[{"$ref":"#/components/schemas/BuildLimitsSettings","description":"Build-time resource limits applied on the control plane to prevent\n`docker build` from saturating host CPU/RAM. Worker nodes are\nintentionally NOT subject to these limits (each worker is dedicated\nhardware that already has its own per-host headroom)."}],"default":{"max_concurrent":2,"cpu_limit_cores":0.0,"memory_limit_mb":0}},"cloud":{"oneOf":[{"$ref":"#/components/schemas/CloudSettings","description":"Managed control-plane connection. Credentials are deliberately not\nstored here; they live in the owner-only cloud-link state file."}],"default":{"backend_url":"https://app.temps.sh"}},"cluster_dns":{"oneOf":[{"$ref":"#/components/schemas/ClusterDnsSettings","description":"Cluster-DNS resolver settings (ADR-024, experimental beta). Off by\ndefault — see `ClusterDnsSettings` for the incident background and\ntrade-offs. Must be explicitly enabled by operators who need\n`*.temps.local` service-to-service resolution inside containers."}],"default":{"enabled":false}},"console_version":{"type":["string","null"],"description":"Binary version tag (e.g. \"v0.1.0\") of the *console* process\n(`temps serve`, role=all or role=console) that last started. Written\non console startup; read by the standalone `temps proxy` to detect\nversion skew during a rolling upgrade (ADR-017 Phase 3). `None` on\ninstalls that never ran a console build carrying this field.\n\nThis is informational state written by the binary itself — NOT an\noperator-tunable setting. It is intentionally absent from\n`AppSettingsResponse` and the PATCH path so an operator cannot\naccidentally overwrite the self-recorded value.","default":null},"container_logs":{"oneOf":[{"$ref":"#/components/schemas/ContainerLogSettings"}],"default":{"max_size":"50m","max_file":3,"service_max_size":"20m","service_max_file":3}},"disk_space_alert":{"oneOf":[{"$ref":"#/components/schemas/DiskSpaceAlertSettings"}],"default":{"enabled":true,"threshold_percent":80,"check_interval_seconds":300,"monitor_path":null}},"dns_provider":{"oneOf":[{"$ref":"#/components/schemas/DnsProviderSettings"}],"default":{"provider":"manual","cloudflare_api_key":null}},"docker_registry":{"oneOf":[{"$ref":"#/components/schemas/DockerRegistrySettings"}],"default":{"enabled":false,"registry_url":null,"username":null,"password":null,"tls_verify":true,"ca_certificate":null}},"edge_target":{"type":["string","null"],"description":"Public edge target that generated DNS records point at when a managed\ndomain opts into automatic record sync. An IPv4/IPv6 address produces an\n`A`/`AAAA` record; anything else is treated as a `CNAME` target. `None`\ndisables DNS record sync regardless of per-domain opt-in.","default":null},"external_url":{"type":["string","null"],"default":null},"insecure_tls":{"type":"boolean","description":"Skip TLS certificate verification on outbound HTTP clients built by the\nserver (deployer, agent, remote service client). Strictly opt-in for\noperators running self-signed control plane / worker certs on a trusted\ninternal network. Worker→control-plane traffic that traverses the public\ninternet must keep this `false` — otherwise a MitM steals the join token.","default":false},"internal_url":{"type":["string","null"],"description":"URL that service containers use to reach the Temps API from *inside*\nthe Docker network (OTLP metrics ingest, agent callbacks, etc.). On\nDocker Desktop this defaults to `http://host.docker.internal:`;\non Linux it requires the `host.docker.internal:host-gateway` host\nmapping (which Temps adds to provisioned containers). Distinct from\n`external_url`, which is the public-facing address.","default":null},"letsencrypt":{"oneOf":[{"$ref":"#/components/schemas/LetsEncryptSettings"}],"default":{"email":null,"environment":"production"}},"monitoring":{"oneOf":[{"$ref":"#/components/schemas/MonitoringSettings","description":"Metrics observability settings. Controls the MetricsStore backend,\nscrape interval, and tiered retention windows."}],"default":{"enabled":false,"store":"timescale_db","scrape_interval_secs":30,"retention_raw_days":7,"retention_hourly_days":90,"retention_daily_years":2,"clickhouse_url":null}},"multi_node":{"oneOf":[{"$ref":"#/components/schemas/MultiNodeSettings"}],"default":{"join_token_hash":null,"private_address":null,"legacy_shared_token_enabled":true,"cluster_ca_cert_pem":null,"cluster_ca_key_encrypted":null,"require_mtls":false,"node_cpu_alert_percent":90.0,"node_memory_alert_percent":90.0,"node_disk_alert_percent":90.0}},"observability_compression":{"oneOf":[{"$ref":"#/components/schemas/ObservabilityCompressionSettings","description":"TimescaleDB compression delays for immutable observability data.\nChanges are applied at runtime by the Settings API."}],"default":{"proxy_logs_after_hours":24,"otel_spans_after_hours":24}},"observability_retention":{"oneOf":[{"$ref":"#/components/schemas/ObservabilityRetentionSettings","description":"Retention windows for raw proxy and OpenTelemetry telemetry.\nTimescaleDB policies are updated at runtime by the Settings API."}],"default":{"proxy_logs_days":30,"otel_spans_days":90,"otel_logs_days":90,"otel_metrics_days":90}},"on_demand_tls":{"oneOf":[{"$ref":"#/components/schemas/OnDemandTlsSettings"}],"default":{"enabled":false,"zone":null,"max_concurrent":3,"hourly_cap":10,"deployment_url_mode":"http"}},"preview_domain":{"type":"string","default":"localho.st"},"preview_gateway":{"oneOf":[{"$ref":"#/components/schemas/PreviewGatewaySettings"}],"default":{"image":"ghcr.io/gotempsh/temps-preview-gateway:latest","host_port":8090,"auto_upgrade":true}},"rate_limiting":{"oneOf":[{"$ref":"#/components/schemas/RateLimitSettings"}],"default":{"enabled":false,"max_requests_per_minute":60,"max_requests_per_hour":1000,"whitelist_ips":[],"blacklist_ips":[]}},"require_mfa_for_admins":{"type":"boolean","description":"When `true`, any user holding the `Admin` role must have MFA enrolled\n(`users.mfa_enabled = true`) to complete a **password** login. Users\nwithout MFA enrolled are rejected with a typed error instructing them\nto enroll before retrying. This only gates the password-login path\n(`AuthService::login`) -- SSO/OIDC logins are handled by a separate\ncode path (`OidcService::resolve_user` + `oidc_handler`) and are\nintentionally unaffected, since federating identity to a\nproperly-hardened IdP is itself an acceptable alternative to local\nTOTP MFA. Modeled as a settings row (not an env var) per CLAUDE.md so\nan operator can flip it at runtime via the Settings API without\nrestarting the binary.","default":false},"screenshots":{"oneOf":[{"$ref":"#/components/schemas/ScreenshotSettings"}],"default":{"enabled":false,"provider":"local","url":""}},"security_headers":{"oneOf":[{"$ref":"#/components/schemas/SecurityHeadersSettings"}],"default":{"enabled":false,"preset":"moderate","content_security_policy":"default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'self'","x_frame_options":"SAMEORIGIN","x_content_type_options":"nosniff","x_xss_protection":"1; mode=block","strict_transport_security":"max-age=31536000; includeSubDomains","referrer_policy":"strict-origin-when-cross-origin","permissions_policy":"geolocation=(), microphone=(), camera=()"}},"setup_complete":{"type":"boolean","description":"Set to `true` by `temps setup` (all modes) once initial configuration\nhas been applied. The web onboarding wizard reads this from the server\nand skips itself when true, preventing the \"Configure Base Domain\" wall\nfrom appearing on installs that were already configured via the CLI.","default":false}}},"AppSettingsResponse":{"type":"object","description":"Safe response for application settings that masks sensitive fields","required":["preview_domain","screenshots","letsencrypt","dns_provider","security_headers","rate_limiting","docker_registry","disk_space_alert","container_logs","agent_sandbox","ai_config","preview_gateway","multi_node","monitoring","observability_compression","observability_retention","effective_metrics_store","effective_observability_store","insecure_tls","setup_complete","require_mfa_for_admins","cluster_dns","build_limits","ai_chat_limits"],"properties":{"agent_sandbox":{"$ref":"#/components/schemas/AgentSandboxSettingsMasked"},"ai_chat_limits":{"$ref":"#/components/schemas/AiChatLimitsSettings","description":"Per-turn limits for the AI chat. No sensitive content."},"ai_config":{"$ref":"#/components/schemas/AiConfigSettings"},"build_limits":{"$ref":"#/components/schemas/BuildLimitsSettings","description":"Build-time resource limits (control-plane only). No sensitive content,\npassed through as-is."},"cluster_dns":{"$ref":"#/components/schemas/ClusterDnsSettings","description":"Cluster-DNS resolver settings (ADR-024, experimental beta). No masking\nneeded — `enabled` is a plain bool with no sensitive content. Passed\nthrough as-is so the settings UI can read and toggle the flag."},"container_logs":{"$ref":"#/components/schemas/ContainerLogSettings"},"disk_space_alert":{"$ref":"#/components/schemas/DiskSpaceAlertSettings"},"dns_provider":{"$ref":"#/components/schemas/DnsProviderSettingsMasked"},"docker_registry":{"$ref":"#/components/schemas/DockerRegistrySettingsMasked"},"edge_target":{"type":["string","null"],"description":"Public edge target that synced DNS records point at (IP → A/AAAA, else CNAME)."},"effective_metrics_store":{"$ref":"#/components/schemas/MetricsStoreKind","description":"The storage backend the runtime is **actually** using for metrics,\nafter reconciling the `monitoring.store` toggle with the server's\n`TEMPS_CLICKHOUSE_*` configuration. When `monitoring.store` is\n`click_house` but those env vars are not fully set, the runtime falls\nback to TimescaleDB — in that case this reports `timescale_db` even\nthough `monitoring.store` says `click_house`. The UI shows this as the\neffective backend and warns when it diverges from the configured store."},"effective_observability_store":{"$ref":"#/components/schemas/MetricsStoreKind","description":"Storage backend actually used for proxy logs, OTel spans, and OTel\nmetrics. OTel logs remain TimescaleDB-backed. Unlike resource metrics,\nthese domains switch to ClickHouse whenever the server-level ClickHouse\nconnection is configured; they do not use the monitoring store toggle."},"external_url":{"type":["string","null"]},"insecure_tls":{"type":"boolean"},"internal_url":{"type":["string","null"]},"letsencrypt":{"$ref":"#/components/schemas/LetsEncryptSettings"},"monitored_services_count":{"type":["integer","null"],"format":"int64","description":"Number of enabled, running services the MetricsScraper currently\nincludes. Used for the lightweight storage estimate in the UI.","minimum":0},"monitoring":{"$ref":"#/components/schemas/MonitoringSettingsMasked"},"multi_node":{"$ref":"#/components/schemas/MultiNodeSettingsMasked"},"observability_compression":{"$ref":"#/components/schemas/ObservabilityCompressionSettings","description":"TimescaleDB compression delays for immutable proxy logs and OTel spans."},"observability_retention":{"$ref":"#/components/schemas/ObservabilityRetentionSettings","description":"Retention windows for raw proxy logs and OpenTelemetry data."},"preview_domain":{"type":"string"},"preview_gateway":{"$ref":"#/components/schemas/PreviewGatewaySettingsMasked"},"rate_limiting":{"$ref":"#/components/schemas/RateLimitSettings"},"require_mfa_for_admins":{"type":"boolean","description":"When enabled, Admin-role accounts without MFA enrolled are rejected\nat password login (bherila/temps#32). SSO/OIDC logins are unaffected."},"screenshots":{"$ref":"#/components/schemas/ScreenshotSettings"},"security_headers":{"$ref":"#/components/schemas/SecurityHeadersSettings"},"setup_complete":{"type":"boolean","description":"Whether `temps setup` has been run at least once. The web onboarding\nwizard checks this field on load and skips itself when true."}}},"ApplyHostnameModeRequest":{"type":"object","description":"Request to apply a hostname mode (recompute + optional DNS sync).","required":["mode"],"properties":{"mode":{"type":"string","description":"Target mode to apply: `\"standard\"` or `\"flat\"`."},"sync_dns":{"type":"boolean","description":"Also reconcile the provider's DNS zone for the affected hostnames."}}},"ArchiveFlagResponse":{"type":"object","required":["key"],"properties":{"archived_at":{"type":["string","null"]},"key":{"type":"string"}}},"ArchiveMode":{"type":"string","enum":["off","on","always","unknown"]},"AssignRoleRequest":{"type":"object","required":["user_id","role_type"],"properties":{"role_type":{"type":"string"},"user_id":{"type":"integer","format":"int32"}}},"AttachScheduleServicesRequest":{"type":"object","description":"Body for `POST /api/backups/schedules/{id}/services` — attach external\nservices to a backup schedule. Idempotent.","required":["service_ids"],"properties":{"service_ids":{"type":"array","items":{"type":"integer","format":"int32"},"description":"External service ids to attach. Duplicates are de-duplicated server-side."}}},"AttachScheduleServicesResponse":{"type":"object","description":"Response for `POST /api/backups/schedules/{id}/services`.","required":["inserted","total_attached"],"properties":{"inserted":{"type":"integer","format":"int64","description":"Number of rows actually inserted (excludes rows skipped by\n`ON CONFLICT DO NOTHING`).","minimum":0},"total_attached":{"type":"integer","description":"Total number of services now attached to the schedule.","minimum":0}}},"AuditLogIpInfo":{"type":"object","description":"IP address information in audit log","required":["ip"],"properties":{"city":{"type":["string","null"],"description":"City name","example":"San Francisco"},"country":{"type":["string","null"],"description":"Country code","example":"US"},"ip":{"type":"string","description":"IP address","example":"192.168.1.1"},"latitude":{"type":["number","null"],"format":"double","description":"Latitude","example":37.7749},"longitude":{"type":["number","null"],"format":"double","description":"Longitude","example":122.4194}}},"AuditLogResponse":{"type":"object","description":"Response type for audit log entries","required":["id","operation_type","audit_date"],"properties":{"audit_date":{"type":"integer","format":"int64","description":"When the action occurred","example":11932193},"data":{"description":"Additional context about the action"},"id":{"type":"integer","format":"int32","description":"Unique identifier for the audit log entry"},"ip_address":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AuditLogIpInfo","description":"IP address details"}]},"operation_type":{"type":"string","description":"The type of action that was performed","example":"USER_LOGIN"},"user":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AuditLogUserInfo","description":"User details who performed the action"}]},"user_id":{"type":["integer","null"],"format":"int32","description":"The user who performed the action (`null` when that account has\nsince been deleted; `data` retains the original actor context)"}}},"AuditLogUserInfo":{"type":"object","description":"User information in audit log","required":["id","name","email"],"properties":{"email":{"type":"string","description":"User's email","example":"john.doe@example.com"},"id":{"type":"integer","format":"int32","description":"User ID"},"name":{"type":"string","description":"User's name","example":"John Doe"}}},"AuthFlavorDto":{"type":"object","description":"One auth flavor surfaced to the UI. Mirrors `AuthFlavor` in the catalog\nbut without the seed-path / env-var fields the frontend doesn't need\n(those are server-side only — exposing them just bloats the response).","required":["id","label","description","format"],"properties":{"description":{"type":"string"},"env_var":{"type":["string","null"],"description":"For `api_key` format: the env var name that will be set inside the\nsandbox. Useful for showing the user \"we'll set OPENAI_API_KEY\" so\nthey know what their key controls."},"format":{"type":"string","description":"`api_key`, `oauth_token`, or `config_file` — drives which input UI\nthe settings page renders (single-line vs. multi-line textarea)."},"id":{"type":"string"},"label":{"type":"string"}}},"AuthResponse":{"type":"object","required":["success","message","mfa_required"],"properties":{"message":{"type":"string"},"mfa_required":{"type":"boolean"},"success":{"type":"boolean"},"user_id":{"type":["integer","null"],"format":"int32"}}},"AuthStatusResponse":{"type":"object","required":["status"],"properties":{"cli_token":{"type":["string","null"]},"status":{"type":"string"}}},"AuthTokenResponse":{"type":"object","required":["access_token","refresh_token","expires_at"],"properties":{"access_token":{"type":"string"},"expires_at":{"type":"integer","format":"int64"},"refresh_token":{"type":"string"}}},"AutoWatchParams":{"type":"object","description":"Auto-watch (Watchdog-style) detector parameters (stub — not evaluated).","properties":{"direction":{"$ref":"#/components/schemas/Direction","description":"The engine self-tunes the band; the user supplies only the direction."}}},"AutofixRunConfig":{"type":"object","description":"User-chosen per-run options, persisted as JSON in `agent_runs.run_config`.\nEvery field is optional — unset fields fall back to the provider defaults\nin settings, then to built-in defaults.","properties":{"branch":{"type":["string","null"],"description":"Branch to clone instead of the project's main branch.","default":null},"max_turns":{"type":["integer","null"],"format":"int32","description":"Per-run turn cap applied to every phase of this run. Only enforced\nfor CLIs with a turn flag (Claude Code); Codex/OpenCode run to\ncompletion. `None` uses the provider's per-phase defaults.","default":null},"model":{"type":["string","null"],"description":"Model id for the chosen provider. `None` uses the provider's saved\ndefault model, or the CLI's own default.","default":null},"provider":{"type":["string","null"],"description":"AI provider id (\"claude_cli\", \"codex_cli\", \"opencode\"). `None` uses\nthe platform default provider from agent sandbox settings.","default":null}}},"AutofixerRunResponse":{"type":"object","required":["id","project_id","status","tokens_input","tokens_output","files_changed","created_at"],"properties":{"ai_model":{"type":["string","null"]},"ai_output":{"type":["string","null"]},"ai_provider":{"type":["string","null"],"description":"AI provider slug this run executes with (e.g. claude_cli, codex_cli)."},"analysis":{"type":["string","null"]},"branch_name":{"type":["string","null"]},"completed_at":{"type":["string","null"]},"created_at":{"type":"string"},"error_message":{"type":["string","null"]},"files_changed":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"phase":{"type":["string","null"]},"pr_number":{"type":["integer","null"],"format":"int32"},"pr_url":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"run_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AutofixRunConfig","description":"Per-run options the run was started with; used to prefill the\nretry / start-over dialog."}]},"started_at":{"type":["string","null"]},"status":{"type":"string"},"tokens_input":{"type":"integer","format":"int32"},"tokens_output":{"type":"integer","format":"int32"},"trigger_source_id":{"type":["integer","null"],"format":"int32"},"user_context":{"type":["string","null"]}}},"AutofixerRunWithLogsResponse":{"type":"object","required":["run","logs"],"properties":{"logs":{"type":"array","items":{"$ref":"#/components/schemas/AgentRunLogResponse"}},"run":{"$ref":"#/components/schemas/AutofixerRunResponse"}}},"AvailableContainerInfo":{"type":"object","description":"Available Docker container that can be imported as a service","required":["container_id","container_name","image","version","service_type","is_running"],"properties":{"container_id":{"type":"string","description":"Container ID or name","example":"abc123def456"},"container_name":{"type":"string","description":"Container display name","example":"my-postgres"},"exposed_ports":{"type":"array","items":{"type":"integer","format":"int32","minimum":0},"description":"Exposed ports (e.g., [5432] for PostgreSQL, [6379] for Redis)"},"image":{"type":"string","description":"Docker image name (e.g., \"gotempsh/postgres-walg:18-bookworm\")","example":"gotempsh/postgres-walg:18-bookworm"},"is_running":{"type":"boolean","description":"Whether the container is currently running","example":true},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute","description":"Service type this container represents"},"version":{"type":"string","description":"Extracted version from image","example":"18"}}},"AvailablePermissions":{"type":"object","description":"Response containing all available permissions for frontend validation","required":["permissions","roles"],"properties":{"permissions":{"type":"array","items":{"$ref":"#/components/schemas/PermissionInfo"},"description":"All available permissions in the system"},"roles":{"type":"array","items":{"$ref":"#/components/schemas/RoleInfo"},"description":"All available roles"}}},"BackupAlertListResponse":{"type":"object","description":"Response body for the list-backup-alerts endpoint.","required":["alerts"],"properties":{"alerts":{"type":"array","items":{"$ref":"#/components/schemas/BackupAlertResponse"},"description":"All currently open (unresolved) alerts, newest first."}}},"BackupAlertResponse":{"type":"object","description":"A single open backup alert surfaced in the UI banner.\n\nAlerts are auto-opened by the watcher and auto-resolved when the triggering\ncondition clears. No manual dismiss is required or supported.\n\nThe optional `schedule_s3_source_id` field is included so the UI can\ndeep-link an `overdue_schedule` alert to the S3 source detail page that\nhosts the schedule. `stalled_job` alerts no longer carry a deep-link\ntarget — the alert message text contains the backup id for display.","required":["id","kind","severity","message","opened_at"],"properties":{"id":{"type":"integer","format":"int64","description":"Database id of the alert row."},"kind":{"type":"string","description":"`\"overdue_schedule\"` or `\"stalled_job\"`."},"message":{"type":"string","description":"Human-readable description of the alert condition."},"opened_at":{"type":"string","description":"RFC 3339 timestamp when the alert was opened.","example":"2026-05-15T10:00:00Z"},"schedule_id":{"type":["integer","null"],"format":"int32","description":"FK to `backup_schedules.id`. Set for `overdue_schedule` alerts."},"schedule_name":{"type":["string","null"],"description":"Human-readable name of the linked schedule, if applicable."},"schedule_s3_source_id":{"type":["integer","null"],"format":"int32","description":"FK to `backup_schedules.s3_source_id`. The UI uses this to deep-link\nthe alert to the S3 source detail page that hosts the schedule.\nSet for `overdue_schedule` alerts."},"severity":{"type":"string","description":"`\"warning\"` or `\"critical\"`."}}},"BackupResponse":{"type":"object","description":"Response type for backup","required":["id","name","backup_id","backup_type","state","started_at","s3_source_id","s3_location","metadata","compression_type","created_by","tags"],"properties":{"attempts":{"type":["integer","null"],"format":"int32","description":"How many times this job has been claimed and run. `null` for legacy\nbackups with no `backup_jobs` row."},"backup_id":{"type":"string"},"backup_type":{"type":"string"},"checksum":{"type":["string","null"]},"completed_at":{"type":["integer","null"],"format":"int64"},"compression_type":{"type":"string"},"created_by":{"type":"integer","format":"int32"},"current_step":{"type":["string","null"],"description":"Name of the engine step currently executing (e.g., `\"walg_push\"`).\n`null` when no `backup_jobs` row exists for this backup (legacy rows\npre-dating ADR-014), or when the job has not yet completed its first step."},"error_message":{"type":["string","null"]},"expires_at":{"type":["integer","null"],"format":"int64"},"external_service":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ExternalServiceSummary","description":"External service that owns this backup (Redis, Postgres, etc.).\n`null` for control-plane backups (the Temps server's own database)."}]},"file_count":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"live_size_bytes":{"type":["integer","null"],"format":"int64","description":"Best-effort partial size while a backup is still running, computed\nby listing the S3 prefix. Null when the backup is finished\n(`size_bytes` is authoritative in that case)."},"max_attempts":{"type":["integer","null"],"format":"int32","description":"Maximum attempts before the job is permanently failed. `null` for\nlegacy backups."},"max_runtime_secs":{"type":["integer","null"],"format":"int64","description":"Resolved wall-clock timeout for this backup job (seconds). `null` for\nlegacy backups. Derived from the three-tier resolution order:\ncaller override → schedule override → engine default."},"metadata":{},"name":{"type":"string"},"s3_location":{"type":"string"},"s3_source_id":{"type":"integer","format":"int32"},"schedule_id":{"type":["integer","null"],"format":"int32"},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Final size of the backup once completed. Null while running."},"started_at":{"type":"integer","format":"int64"},"state":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}}}},"BackupScheduleResponse":{"type":"object","description":"Response type for backup schedule","required":["id","name","backup_type","retention_period","s3_source_id","schedule_expression","enabled","created_at","updated_at","tags","target_all_services","include_control_plane"],"properties":{"backup_type":{"type":"string"},"created_at":{"type":"integer","format":"int64"},"description":{"type":["string","null"]},"enabled":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"include_control_plane":{"type":"boolean","description":"When `true`, every run also produces a `control_plane` backup\n(Temps's own Postgres). When `false`, only the external service\nfan-out happens."},"last_run":{"type":["integer","null"],"format":"int64"},"max_runtime_secs":{"type":["integer","null"],"format":"int64","description":"Per-schedule wall-clock timeout override for backup jobs (seconds).\n`null` means the engine-family default is used. See\n`temps_backup_core::timeouts::default_max_runtime_secs`."},"name":{"type":"string"},"next_run":{"type":["integer","null"],"format":"int64"},"retention_period":{"type":"integer","format":"int32"},"s3_source_id":{"type":"integer","format":"int32"},"schedule_expression":{"type":"string","example":"0 0 * * *"},"tags":{"type":"array","items":{"type":"string"}},"target_all_services":{"type":"boolean","description":"When `true`, the schedule auto-includes every external service on\nthe host (and any future ones). When `false`, the schedule only\ntargets services attached via `backup_schedule_services`."},"updated_at":{"type":"integer","format":"int64"}}},"BitbucketAuthInput":{"oneOf":[{"type":"object","description":"Personal / Workspace / Repository Access Token.","required":["token","type"],"properties":{"token":{"type":"string","description":"The Bitbucket access token value."},"type":{"type":"string","enum":["access_token"]}}},{"type":"object","description":"HTTP Basic / App Password authentication.","required":["username","password","type"],"properties":{"password":{"type":"string","description":"App password generated in Bitbucket security settings."},"type":{"type":"string","enum":["app_password"]},"username":{"type":"string","description":"Bitbucket account username."}}}],"description":"Authentication input for a Bitbucket Cloud provider. Use `access_token` for\na Repository or Workspace Access Token (PAT), or `username` + `app_password`\nfor App Password (HTTP Basic) authentication."},"BlobResponse":{"type":"object","description":"Response after uploading a blob","required":["url","pathname","contentType","size","uploadedAt"],"properties":{"contentType":{"type":"string","description":"Content type of the blob","example":"image/png"},"pathname":{"type":"string","description":"Original pathname","example":"images/avatar-abc123.png"},"size":{"type":"integer","format":"int64","description":"Size in bytes","example":12345},"uploadedAt":{"type":"string","format":"date-time","description":"Upload timestamp","example":"2025-01-03T12:00:00Z"},"url":{"type":"string","description":"URL path to access the blob","example":"/api/blob/123/images/avatar-abc123.png"}}},"BlobStatusResponse":{"type":"object","description":"Response for Blob service status","required":["enabled","healthy"],"properties":{"docker_image":{"type":["string","null"],"description":"Docker image being used","example":"ghcr.io/rustfs/rustfs:0.5.0"},"enabled":{"type":"boolean","description":"Whether the Blob service is enabled","example":true},"healthy":{"type":"boolean","description":"Whether the service is healthy","example":true},"version":{"type":["string","null"],"description":"Current version (if running)","example":"0.5.0"}}},"BranchInfo":{"type":"object","required":["name","commit_sha","protected"],"properties":{"commit_sha":{"type":"string"},"name":{"type":"string"},"protected":{"type":"boolean"}}},"BranchListResponse":{"type":"object","required":["branches"],"properties":{"branches":{"type":"array","items":{"$ref":"#/components/schemas/BranchInfo"}}}},"BrowserCount":{"type":"object","required":["browser","count","percentage"],"properties":{"browser":{"type":"string"},"count":{"type":"integer","format":"int64"},"percentage":{"type":"number","format":"double"}}},"BrowsersQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"BuildConfiguration":{"type":"object","description":"Build configuration (for building images from source)","required":["context","args"],"properties":{"args":{"type":"object","description":"Build arguments","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"context":{"type":"string","description":"Build context (Dockerfile path or buildpack)"},"dockerfile":{"type":["string","null"],"description":"Dockerfile path (relative to context)"},"target":{"type":["string","null"],"description":"Target stage (for multi-stage builds)"}}},"BuildLimitsSettings":{"type":"object","description":"Control-plane build resource limits.\n\nCaps how many builds run concurrently AND how much CPU/memory each build\nis allowed to consume. A single global semaphore in the deployer crate\ngates every `DockerRuntime::build_image` call to `max_concurrent`. When\nthe semaphore is full, additional builds queue and wait — they do not\nfail. Per-build CPU/memory caps are forwarded to Docker via\n`BuildImageOptions { memory, cpuquota, cpuperiod }`.\n\n`cpu_limit_cores = 0.0` or `memory_limit_mb = 0` means \"no explicit cap\"\n— fall back to the legacy 50%-of-host heuristic for backwards\ncompatibility with operators who never visit the settings page.","properties":{"cpu_limit_cores":{"type":"number","format":"float","description":"CPU cores allowed per build (float, e.g. 2.0 = 2 cores, 0.5 = half\na core). 0 means \"use the legacy 50%-of-host default\".","default":0.0,"example":2.0,"minimum":0},"max_concurrent":{"type":"integer","format":"int32","description":"Maximum number of `docker build` operations allowed to run at the\nsame time on the control plane. Additional builds queue. Min 1.","default":2,"example":2,"minimum":1},"memory_limit_mb":{"type":"integer","format":"int32","description":"Memory allowed per build, in megabytes. 0 means \"use the legacy\n50%-of-host default\". Docker enforces this as a hard cap — builds\nthat exceed it OOM-kill.","default":0,"example":2048,"minimum":0}}},"CancelBackupResponse":{"type":"object","description":"Response body for cancel endpoints.","required":["cancelled"],"properties":{"cancelled":{"type":"integer","format":"int64","description":"Number of rows that were actually flipped to `failed`. `0` is a valid\nsuccess and means the backup was already terminal — the call is\nidempotent.","minimum":0}}},"CertStatusResponse":{"type":"object","description":"Current on-demand cert status for a single hostname (ADR-018 §5). Backs\n`GET /domains/by-host/{hostname}/cert-status`.","required":["hostname"],"properties":{"backoff_until":{"type":["integer","null"],"format":"int64","description":"On-demand negative-cache deadline (epoch millis), when in backoff."},"hostname":{"type":"string","description":"SNI hostname."},"last_attempt":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/OnDemandCertAttemptResponse","description":"The most recent on-demand issuance attempt for this hostname, if any."}]},"status":{"type":["string","null"],"description":"Current cert lifecycle status from the `domains` row, when one exists."}}},"ChallengeConfig":{"type":"object","description":"Challenge configuration (future feature)\nFor CAPTCHA, JS challenges, proof-of-work, etc.","required":["challengeType","difficulty"],"properties":{"challengeType":{"type":"string","description":"Challenge type: \"captcha\", \"js_challenge\", \"proof_of_work\""},"difficulty":{"type":"integer","format":"int32","description":"Challenge difficulty level (1-10)","minimum":0},"protectedPaths":{"type":"array","items":{"type":"string"},"description":"Paths that require challenges"}}},"ChallengeError":{"type":"object","required":["type","detail","status"],"properties":{"detail":{"type":"string","description":"Human-readable error description"},"status":{"type":"integer","format":"int32","description":"HTTP status code"},"type":{"type":"string","description":"Error type (e.g., \"urn:ietf:params:acme:error:unauthorized\")"}}},"ChallengeValidationStatus":{"type":"object","required":["type","url","status","token"],"properties":{"error":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ChallengeError","description":"Error details if validation failed"}]},"status":{"type":"string","description":"Challenge status (e.g., \"pending\", \"valid\", \"invalid\")"},"token":{"type":"string","description":"Challenge token"},"type":{"type":"string","description":"Challenge type (e.g., \"dns-01\", \"http-01\")"},"url":{"type":"string","description":"Challenge validation URL"},"validated":{"type":["string","null"],"description":"When the challenge was validated (if successful)"}}},"ChangePasswordRequest":{"type":"object","required":["current_password","new_password"],"properties":{"current_password":{"type":"string","example":"current_password_value"},"mfa_code":{"type":["string","null"],"description":"TOTP code (or recovery code). Required iff the user has MFA enabled.","example":"123456"},"new_password":{"type":"string","example":"new_password_value"},"revoke_other_sessions":{"type":"boolean","description":"When true, every session OTHER than the one making this request is\nrevoked. Defaults to false; the UI surfaces this as a checkbox."}}},"ChangeProjectSourceRequest":{"type":"object","description":"Change a project's source type to a Git-less type (docker_image /\nstatic_files / manual). Switching TO `git` is done via the Git settings\nendpoint (which also supplies the repository + provider connection).","required":["source_type"],"properties":{"source_type":{"$ref":"#/components/schemas/SourceType"}}},"ChatCompletionChoice":{"type":"object","required":["index","message"],"properties":{"finish_reason":{"type":["string","null"]},"index":{"type":"integer","format":"int32"},"message":{"$ref":"#/components/schemas/ChatMessage"}}},"ChatCompletionRequest":{"allOf":[{"type":["object","null"],"description":"Tolerates extra SDK fields (stream_options, logprobs, etc.)","additionalProperties":{},"propertyNames":{"type":"string"}},{"type":"object","required":["model","messages"],"properties":{"frequency_penalty":{"type":["number","null"],"format":"double"},"max_tokens":{"type":["integer","null"],"format":"int64"},"messages":{"type":"array","items":{"$ref":"#/components/schemas/ChatMessage"}},"model":{"type":"string"},"n":{"type":["integer","null"],"format":"int32"},"presence_penalty":{"type":["number","null"],"format":"double"},"response_format":{},"seed":{"type":["integer","null"],"format":"int64"},"stop":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/StopSequence"}]},"stream":{"type":"boolean"},"temperature":{"type":["number","null"],"format":"double"},"tool_choice":{},"tools":{"type":["array","null"],"items":{}},"top_p":{"type":["number","null"],"format":"double"},"user":{"type":["string","null"]}}}],"description":"OpenAI-compatible chat completion request.\nUses `deny_unknown_fields = false` (serde default) so that SDK-specific\nfields like `stream_options`, `logprobs`, `top_logprobs`, `logit_bias`,\n`parallel_tool_calls`, etc. are silently accepted without breaking."},"ChatCompletionResponse":{"type":"object","required":["id","object","created","model","choices"],"properties":{"choices":{"type":"array","items":{"$ref":"#/components/schemas/ChatCompletionChoice"}},"created":{"type":"integer","format":"int64"},"id":{"type":"string"},"model":{"type":"string"},"object":{"type":"string"},"usage":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/UsageInfo"}]}}},"ChatMessage":{"type":"object","required":["role"],"properties":{"content":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MessageContent"}]},"name":{"type":["string","null"]},"role":{"type":"string"},"tool_call_id":{"type":["string","null"]},"tool_calls":{"type":["array","null"],"items":{}}}},"ChatReadinessResponse":{"type":"object","description":"What still has to be true before an AI chat can run a turn in this project.\n\nThe three gates are independent and fail for different reasons with different\nfixes, so they are reported separately rather than collapsed into one boolean:\nan instance admin configures a provider (instance-wide), while the two toggles\nare per-project. Collapsing them would leave the user with \"AI unavailable\"\nand no idea which of three places to go.","required":["ai_configured","chat_enabled","write_actions_enabled"],"properties":{"ai_configured":{"type":"boolean","description":"An AI provider is configured on this instance. Fixed in\nSettings → AI Providers; instance-wide, not per project."},"chat_enabled":{"type":"boolean","description":"The per-project read-only chat toggle is on (the default)."},"write_actions_enabled":{"type":"boolean","description":"The per-project write-actions opt-in is on. Required for any flow where\nthe assistant *proposes* changes; irrelevant for read-only questions."}}},"ChildBackupEntryResponse":{"type":"object","description":"A single child backup entry in the `GET /backups/{id}/children` response.\n\nEach entry corresponds to one `external_service_backups` row joined with\n`external_services`, providing service metadata without a second request.","required":["id","service_id","service_name","service_type","state","backup_type","started_at","s3_location","compression_type"],"properties":{"backup_type":{"type":"string","description":"Backup variant (e.g. \"full\", \"incremental\")."},"compression_type":{"type":"string","description":"Compression algorithm used (e.g. \"gzip\", \"lz4\")."},"error_message":{"type":["string","null"],"description":"Engine-reported error message when `state = \"failed\"`."},"finished_at":{"type":["string","null"],"description":"When the child backup finished, if known.","example":"2025-01-15T14:35:00.456Z"},"id":{"type":"integer","format":"int32","description":"Row ID from `external_service_backups`."},"s3_location":{"type":"string","description":"Object key or `s3://` URL where the backup data lives."},"service_id":{"type":"integer","format":"int32","description":"FK to `external_services.id`."},"service_name":{"type":"string","description":"Human-readable name of the external service (e.g. \"redis-prod\")."},"service_type":{"type":"string","description":"Service type string (e.g. \"postgres\", \"redis\", \"mongodb\", \"s3\").","example":"postgres"},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size of the child backup in bytes, if available."},"started_at":{"type":"string","description":"When the child backup started (RFC 3339).","example":"2025-01-15T14:30:00.123Z"},"state":{"type":"string","description":"Current state: \"pending\" | \"running\" | \"completed\" | \"failed\"."}}},"ChildBackupListResponse":{"type":"object","description":"Response body for `GET /backups/{id}/children`.\n\nReturns an empty `children` list (not 404) when the parent backup has no\nchild records (e.g. control-plane backups).","required":["children"],"properties":{"children":{"type":"array","items":{"$ref":"#/components/schemas/ChildBackupEntryResponse"},"description":"Zero or more child backup entries ordered by `external_service_backups.id` ASC."}}},"CleanupExpiredBackupsRequest":{"type":"object","properties":{"expected_backup_ids":{"type":["array","null"],"items":{"type":"string"},"description":"Exact candidates returned by the dry run. Execution fails if the\nretention selection has changed since preview."}}},"CliDeviceApproveRequest":{"type":"object","required":["user_code"],"properties":{"user_code":{"type":"string"}}},"CliDeviceApproveResponse":{"type":"object","required":["user_code","status"],"properties":{"status":{"type":"string"},"user_code":{"type":"string"}}},"CliDeviceLookupResponse":{"type":"object","required":["user_code","status","expires_at"],"properties":{"client_name":{"type":["string","null"]},"expires_at":{"type":"string","format":"date-time"},"requested_ip":{"type":["string","null"]},"status":{"type":"string","description":"`pending` | `approved` | `denied` | `expired`."},"user_code":{"type":"string"}}},"CliDevicePollRequest":{"type":"object","required":["device_code"],"properties":{"device_code":{"type":"string"}}},"CliDevicePollResponse":{"oneOf":[{"type":"object","description":"Still waiting on the user to approve in the browser.","required":["status"],"properties":{"status":{"type":"string","enum":["authorization_pending"]}}},{"type":"object","description":"CLI is polling faster than the server-suggested interval.","required":["status"],"properties":{"status":{"type":"string","enum":["slow_down"]}}},{"type":"object","description":"User denied the request in the browser.","required":["status"],"properties":{"status":{"type":"string","enum":["access_denied"]}}},{"type":"object","description":"The session has expired without approval.","required":["status"],"properties":{"status":{"type":"string","enum":["expired_token"]}}},{"type":"object","description":"The session was approved; this is the only response that carries\nthe API key. The key is returned exactly once and then cleared\nfrom the session row.","required":["user_id","email","role","api_key","key_prefix","status"],"properties":{"api_key":{"type":"string"},"email":{"type":"string"},"expires_at":{"type":["string","null"],"format":"date-time"},"key_prefix":{"type":"string"},"role":{"type":"string"},"status":{"type":"string","enum":["approved"]},"user_id":{"type":"integer","format":"int32"}}}]},"CliDeviceStartRequest":{"type":"object","properties":{"client_name":{"type":["string","null"],"description":"Friendly hostname / client identifier shown in the browser approval\nscreen. Sanitized before display.","example":"dviejo-mac.local"}}},"CliDeviceStartResponse":{"type":"object","required":["device_code","user_code","verification_uri","verification_uri_complete","expires_in","interval"],"properties":{"device_code":{"type":"string","description":"Opaque secret the CLI polls with. Never display to a human."},"expires_in":{"type":"integer","format":"int64","description":"Seconds until the device_code expires."},"interval":{"type":"integer","format":"int64","description":"Suggested polling interval, in seconds."},"user_code":{"type":"string","description":"Short human-readable code the user types into the browser.","example":"ABCD-1234"},"verification_uri":{"type":"string","description":"Base verification URL — the CLI may display this when the\npre-filled URL is too long to be useful.","example":"https://temps.example.com/cli-login"},"verification_uri_complete":{"type":"string","description":"`verification_uri` with `user_code` pre-filled. Open this directly.","example":"https://temps.example.com/cli-login/ABCD-1234"}}},"CliLoginRequest":{"type":"object","required":["username","password"],"properties":{"password":{"type":"string"},"username":{"type":"string"}}},"CloudCapability":{"type":"object","required":["configured","setup_path"],"properties":{"configured":{"type":"boolean"},"reason":{"type":["string","null"]},"setup_path":{"type":"string"}}},"CloudProvider":{"type":"string","description":"Cloud provider detected from node metadata","enum":["aws","gcp","azure","hetzner","digitalocean","other"]},"CloudSettings":{"type":"object","description":"Non-secret managed control-plane settings stored with application settings.","properties":{"backend_url":{"type":"string","description":"HTTPS origin used for enrollment and telemetry mirroring.","default":"https://app.temps.sh"}}},"CloudStatus":{"type":"object","required":["status","status_message","health","health_message","spooled_spans","backend_url"],"properties":{"backend_url":{"type":"string"},"health":{"type":"string"},"health_message":{"type":"string"},"instance_id":{"type":["string","null"]},"spooled_spans":{"type":"integer","minimum":0},"status":{"type":"string"},"status_message":{"type":"string"}}},"CloudflareConfig":{"type":"object","description":"Configuration for a Cloudflare Email Sending notification provider.\n\nNotifications are delivered through Cloudflare's transactional Email Sending\nAPI. Only the account, token, sender and recipients are configured here —\nsubject and body are derived from each notification.","required":["account_id","api_token","from_address","to_addresses"],"properties":{"account_id":{"type":"string","description":"Cloudflare account id that owns the Email Sending configuration.","example":"023e105f4ecef8ad9ca31a8372d0c353"},"api_token":{"type":"string","description":"Cloudflare API token with the Email Sending permission. Encrypted at\nrest and masked in normal API responses."},"from_address":{"type":"string","description":"Verified sender address (must belong to a domain enabled for Cloudflare\nEmail Sending).","example":"welcome@infracf.example.com"},"from_name":{"type":["string","null"],"description":"Optional human-friendly sender name shown in the recipient's inbox."},"to_addresses":{"type":"array","items":{"type":"string"},"description":"Recipients that should receive the notification."}}},"ClusterCapacity":{"type":"object","description":"Total cluster capacity (sum of node allocatable resources)","required":["node_count","cpu_millis","memory_mb"],"properties":{"cpu_millis":{"type":"integer","format":"int64","description":"Total allocatable CPU in millicores"},"memory_mb":{"type":"integer","format":"int64","description":"Total allocatable memory in MB"},"node_count":{"type":"integer","description":"Number of nodes","minimum":0}}},"ClusterDnsSettings":{"type":"object","description":"Cluster-DNS resolver settings (ADR-024, experimental beta).\n\nWhen `enabled`, the Temps control plane starts a Hickory DNS resolver and\ninjects it as the first nameserver into every deployed container via\n`HostConfig.Dns` — giving containers the ability to resolve `*.temps.local`\nFQDNs for service-to-service communication. Worker nodes pick this flag up\nfrom the `/api/internal/nodes/{id}/network/peers` wire response and gate\ntheir own per-node resolver the same way.\n\n**Default: `false` (disabled).**\n\nWhy disabled by default: a production incident showed that when the injected\nHickory resolver was slow or transiently unresponsive for a non-`*.temps.local`\n(external) hostname, glibc's resolver cycled through all three nameservers\n(`172.20.0.1`, `1.1.1.1`, `8.8.8.8`) at ~5 s timeout × 2 attempts each,\ncausing 22–27 s delays for outbound TCP connections. Disabling the injection\nrestores Docker's embedded DNS as the sole resolver, eliminating that failure\nmode. Operators running single/multi-node installs that depend on\n`*.temps.local` resolution must explicitly opt in by setting `enabled: true`.\n\n`bool` defaults to `false` in Rust and JSON (`#[serde(default)]`), so the\nsafe-off behaviour is automatic for new installs and legacy settings rows.","properties":{"enabled":{"type":"boolean","description":"Master switch. When `false` (default), no custom DNS is injected into\ncontainers — they use Docker's embedded DNS which forwards to the host's\nown `resolv.conf`. When `true`, the control-plane Hickory resolver is\nstarted and its bridge IP is injected as the first nameserver so\n`*.temps.local` FQDNs resolve inside containers.","default":false,"example":false}}},"ClusterHealthReportResponse":{"type":"object","description":"Response body for `GET /external-services/{id}/cluster-health`.","required":["checked_at","monitor_response_ms","members"],"properties":{"checked_at":{"type":"string","description":"ISO-8601 wall-clock when the report was generated.","example":"2025-10-12T12:15:47.609192Z"},"members":{"type":"array","items":{"$ref":"#/components/schemas/ClusterMemberHealthResponse"}},"monitor_error":{"type":["string","null"],"description":"Set when the monitor itself was unreachable. UI shows a banner."},"monitor_response_ms":{"type":"integer","format":"int64","description":"Round-trip to query the monitor (ms)."}}},"ClusterMemberHealthResponse":{"type":"object","description":"One row in the cluster Members table — see `GET /external-services/{id}/cluster-health`.","required":["nodename","nodehost","nodeport","reported_state","goal_state","health","seconds_since_report","candidate_priority","replication_quorum"],"properties":{"candidate_priority":{"type":"integer","format":"int32"},"goal_state":{"type":"string","description":"What the monitor *wants* the node to be. Differs from\n`reported_state` mid-transition (failover, demotion, etc.)."},"health":{"type":"integer","format":"int32","description":"pg_auto_failover liveness signal: `1` healthy, `0` unknown\n(no recent report), `-1` unhealthy."},"nodehost":{"type":"string"},"nodename":{"type":"string"},"nodeport":{"type":"integer","format":"int32"},"replay_lag_ms":{"type":["integer","null"],"format":"int64","description":"`replay_lag` from `pg_stat_replication`, in milliseconds."},"replication_quorum":{"type":"boolean"},"reported_state":{"type":"string","description":"What the node *last told the monitor* it was. Stale during outages."},"seconds_since_report":{"type":"integer","format":"int64","description":"Wall-clock seconds since the node last reported in."},"sync_state":{"type":["string","null"],"description":"`sync` / `quorum` / `async` for secondaries; `null` for the primary."}}},"ClusterMemberRequest":{"type":"object","description":"Request spec for a single cluster member.","required":["role"],"properties":{"node_id":{"type":["integer","null"],"format":"int32","description":"Target worker node ID. Omit or null to run on the control plane."},"role":{"type":"string","description":"Service-type-specific role (e.g., \"monitor\", \"primary\", \"replica\")","example":"primary"}}},"CmdBody":{"type":"object","required":["command"],"properties":{"args":{"type":"array","items":{"type":"string"},"description":"Arguments to pass to the binary. Defaults to empty."},"command":{"type":"string","description":"Binary name (argv[0]) — e.g. `\"ls\"`, `\"node\"`. The SDK sends this\nseparately from `args`."},"cwd":{"type":["string","null"],"description":"Working directory override."},"env":{"type":"object","description":"Extra env vars.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"sudo":{"type":"boolean","description":"When true, the SDK runs the command privileged. We ignore it today\n— the underlying provider always runs as the sandbox's own user."},"wait":{"type":"boolean","description":"When true, the response is an `application/x-ndjson` stream where\nthe first line is the running-command envelope and the second line\nis the finished-command envelope with `exitCode`."}}},"CmdInner":{"type":"object","description":"Inner `command` object — matches the SDK's zod validator exactly.\n`exitCode` is `null` until the command terminates; `startedAt` is Unix\nepoch milliseconds.","required":["id","name","args","cwd","sandboxId","startedAt"],"properties":{"args":{"type":"array","items":{"type":"string"}},"cwd":{"type":"string"},"exitCode":{"type":["integer","null"],"format":"int32"},"id":{"type":"string"},"name":{"type":"string"},"sandboxId":{"type":"string"},"startedAt":{"type":"integer","format":"int64"}}},"CmdKillBody":{"type":"object","description":"SDK-shaped kill body. The SDK sends `{signal: AbortSignal}` but only\nuses the signal for HTTP request abortion client-side; there's no\nsignal name on the wire.","properties":{"force":{"type":"boolean","description":"Optional: when true, SIGKILL instead of SIGTERM."}}},"CmdResponse":{"type":"object","description":"`@vercel/sandbox` envelope: `{ command: {...} }`.","required":["command"],"properties":{"command":{"$ref":"#/components/schemas/CmdInner"}}},"CommitExistsResponse":{"type":"object","required":["exists"],"properties":{"commit":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/CommitInfo","description":"Commit metadata when the requested SHA exists."}]},"commit_sha":{"type":["string","null"]},"exists":{"type":"boolean"}}},"CommitInfo":{"type":"object","required":["sha","message","author","author_email","date"],"properties":{"author":{"type":"string","description":"Author name"},"author_email":{"type":"string","description":"Author email"},"date":{"type":"string","format":"date-time","description":"Commit date in ISO 8601 format","example":"2025-10-12T12:15:47.609192Z"},"message":{"type":"string","description":"Commit message"},"sha":{"type":"string","description":"Commit SHA hash"}}},"CommitListResponse":{"type":"object","required":["commits"],"properties":{"commits":{"type":"array","items":{"$ref":"#/components/schemas/CommitInfo"}}}},"Comparator":{"type":"string","description":"Comparator for static/forecast threshold detectors. Serializes to the\nkeyword forms `gt|gte|lt|lte` (NOT the SQL operators used by\n`temps-monitoring::compare`).","enum":["gt","gte","lt","lte"]},"ComposePublicPort":{"type":"object","description":"A port that should be exposed publicly through the proxy for a compose service.","required":["service","port"],"properties":{"port":{"type":"integer","format":"int32","description":"Container port to expose (e.g. 8123)","minimum":0},"service":{"type":"string","description":"Compose service name (e.g. \"web\", \"clickhouse\")"}}},"ConnectionListQuery":{"type":"object","properties":{"direction":{"type":["string","null"]},"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0},"sort":{"type":["string","null"]}}},"ConnectionListResponse":{"type":"object","required":["connections","total_count","page","per_page"],"properties":{"connections":{"type":"array","items":{"$ref":"#/components/schemas/ConnectionResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"per_page":{"type":"integer","format":"int64","minimum":0},"total_count":{"type":"integer","minimum":0}}},"ConnectionResponse":{"type":"object","required":["id","provider_id","account_name","account_type","is_active","is_expired","syncing","synced_repository_count","health_status","consecutive_health_failures","created_at","updated_at"],"properties":{"account_name":{"type":"string"},"account_type":{"type":"string"},"consecutive_health_failures":{"type":"integer","format":"int32"},"created_at":{"type":"string","format":"date-time"},"health_message":{"type":["string","null"],"description":"Human-readable reason when health_status is \"unhealthy\"; null otherwise."},"health_status":{"type":"string","description":"Current health status: \"healthy\", \"unhealthy\", or \"unknown\"."},"id":{"type":"integer","format":"int32"},"installation_id":{"type":["string","null"]},"is_active":{"type":"boolean"},"is_expired":{"type":"boolean"},"last_health_check_at":{"type":["string","null"],"format":"date-time"},"last_synced_at":{"type":["string","null"],"format":"date-time"},"provider_id":{"type":"integer","format":"int32"},"synced_repository_count":{"type":"integer","format":"int32","description":"Running count of repositories persisted by the current (or most\nrecent) sync. Resets to 0 when a new sync begins; useful for showing\nlive progress on large syncs."},"syncing":{"type":"boolean"},"updated_at":{"type":"string","format":"date-time"},"user_id":{"type":["integer","null"],"format":"int32"}}},"ConnectionTestResult":{"type":"object","description":"Connection test result","required":["success","message"],"properties":{"message":{"type":"string"},"success":{"type":"boolean"}}},"ConsoleEventPayload":{"type":"object","description":"Payload for server-side event ingestion via the console API.\n\nThe app backend reads the encrypted `_temps_visitor_id` and `_temps_sid`\ncookie values from the user's request and forwards them here.\nTemps decrypts them server-side to resolve visitor/session identity.","required":["event_name","environment_id","deployment_id"],"properties":{"deployment_id":{"type":"integer","format":"int32","description":"Deployment ID to attribute the event to"},"environment_id":{"type":"integer","format":"int32","description":"Environment ID to attribute the event to"},"event_data":{"description":"Arbitrary JSON event data"},"event_name":{"type":"string","description":"Event name (e.g. \"purchase\", \"signup\", custom event names)"},"request_path":{"type":"string","description":"Page path context (defaults to \"/\")"},"request_query":{"type":"string","description":"Query string context"},"session_id":{"type":["string","null"],"description":"Encrypted `_temps_sid` cookie value from the user's browser"},"visitor_id":{"type":["string","null"],"description":"Encrypted `_temps_visitor_id` cookie value from the user's browser"}}},"ContainerActionResponse":{"type":"object","description":"Response indicating success of container state change","required":["container_id","container_name","action","status","message"],"properties":{"action":{"type":"string"},"container_id":{"type":"string"},"container_name":{"type":"string"},"message":{"type":"string"},"status":{"type":"string"}}},"ContainerDetailResponse":{"type":"object","description":"Detailed container information with environment variables and metrics","required":["id","container_id","container_name","image_name","status","deployment_id","created_at","deployed_at","container_port","environment_variables"],"properties":{"container_id":{"type":"string"},"container_name":{"type":"string"},"container_port":{"type":"integer","format":"int32","description":"Port inside the container"},"cpu_limit_cores":{"type":["number","null"],"format":"double","description":"CPU limit in whole cores (e.g. 1.0). None when no limit is configured."},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"deployed_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"deployment_id":{"type":"integer","format":"int32"},"environment_variables":{"type":"array","items":{"$ref":"#/components/schemas/EnvVarResponse"},"description":"Environment variables (sensitive values masked)"},"error_message":{"type":["string","null"],"description":"Free-form error string from Docker's container state on exit."},"exit_code":{"type":["integer","null"],"format":"int32","description":"Process exit code reported by Docker. None while still running."},"exit_reason":{"type":["string","null"],"description":"Human-readable reason the container exited."},"finished_at":{"type":["string","null"],"description":"When the container exited (Docker's FinishedAt). None while running.","example":"2025-10-12T12:16:47.609192Z"},"host_port":{"type":["integer","null"],"format":"int32","description":"Port on the host machine"},"id":{"type":"integer","format":"int32"},"image_name":{"type":"string"},"oom_killed":{"type":["boolean","null"],"description":"True when Docker's OOM killer terminated the container."},"ready_at":{"type":["string","null"],"example":"2025-10-12T12:16:47.609192Z"},"resource_limits":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ResourceLimitsResponse","description":"Resource limits"}]},"restart_count":{"type":["integer","null"],"format":"int64","description":"Container restart count from Docker"},"service_name":{"type":["string","null"],"description":"Compose service name (e.g. \"web\", \"redis\"). None for single-container deployments."},"service_url":{"type":["string","null"],"description":"Per-service URL for compose deployments"},"started_at":{"type":["string","null"],"description":"When the container's main process most recently started.","example":"2025-10-12T12:15:50.000000Z"},"status":{"type":"string"}}},"ContainerEnvironmentVariableValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"ContainerInfoResponse":{"type":"object","required":["container_id","container_name","image_name","status","created_at"],"properties":{"container_id":{"type":"string"},"container_name":{"type":"string"},"cpu_limit_cores":{"type":["number","null"],"format":"double","description":"CPU limit in whole cores (e.g. 1.0). None when no limit is configured."},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"error_message":{"type":["string","null"],"description":"Free-form error string from Docker's container state on exit."},"exit_code":{"type":["integer","null"],"format":"int32","description":"Process exit code reported by Docker. None while still running."},"exit_reason":{"type":["string","null"],"description":"Human-readable reason the container exited (e.g. \"OOMKilled\",\n\"Killed by SIGKILL (exit code 137)\", \"Exit code 1\"). None while running."},"finished_at":{"type":["string","null"],"description":"When the container exited (Docker's FinishedAt). None while running.","example":"2025-10-12T12:16:47.609192Z"},"image_name":{"type":"string"},"node_name":{"type":["string","null"],"description":"Node name where this container is running. None for local (single-node) deployments."},"oom_killed":{"type":["boolean","null"],"description":"True when Docker's OOM killer terminated the container."},"restart_count":{"type":["integer","null"],"format":"int64","description":"Container restart count from Docker. The UI shows a chip when this is\n> 0 so a crash loop is visible without opening detail."},"service_name":{"type":["string","null"],"description":"Compose service name (e.g. \"web\", \"redis\"). None for single-container deployments."},"service_url":{"type":["string","null"],"description":"Per-service URL for compose deployments (e.g. \"https://web-myapp.localho.st\")"},"started_at":{"type":["string","null"],"description":"When the container's main process most recently started. The UI uses\nthis for the uptime label so the count resets when a container is\nrestarted in place. None for containers that never started.","example":"2025-10-12T12:15:50.000000Z"},"status":{"type":"string"}}},"ContainerInventoryItem":{"type":"object","description":"A container reported by the agent during heartbeat reconciliation.","required":["container_id","container_name"],"properties":{"container_id":{"type":"string","description":"Docker container ID"},"container_name":{"type":"string","description":"Docker container name"}}},"ContainerListResponse":{"type":"object","required":["containers","total"],"properties":{"containers":{"type":"array","items":{"$ref":"#/components/schemas/ContainerInfoResponse"}},"total":{"type":"integer","minimum":0}}},"ContainerLogSettings":{"type":"object","description":"Docker container log rotation settings\nControls the `--log-opt max-size` and `--log-opt max-file` for containers","properties":{"max_file":{"type":"integer","format":"int32","description":"Maximum number of rotated log files to keep (e.g., 3 means up to 3 x max_size total)","default":3,"example":3,"minimum":0},"max_size":{"type":"string","description":"Maximum size of each log file (e.g., \"50m\", \"100m\", \"1g\")\nDocker default is unlimited; we default to \"50m\" to prevent disk exhaustion","default":"50m","example":"50m"},"service_max_file":{"type":"integer","format":"int32","description":"Maximum rotated log files for external service containers","default":3,"example":3,"minimum":0},"service_max_size":{"type":"string","description":"Maximum size for external service container logs (postgres, redis, etc.)\nDefaults to \"20m\" since services are typically less verbose than app containers","default":"20m","example":"20m"}}},"ContainerLogsQuery":{"type":"object","properties":{"container_name":{"type":["string","null"],"description":"Optional container name to get logs from (if deployment has multiple containers)"},"end_date":{"type":["integer","null"],"format":"int64"},"follow":{"type":"boolean","description":"Follow log output in real-time (default: true for backward compatibility)"},"start_date":{"type":["integer","null"],"format":"int64"},"tail":{"type":["string","null"]},"timestamps":{"type":"boolean","description":"Include timestamps in log output (default: false)"}}},"ContainerMetricHistoryPoint":{"type":"object","description":"One bucketed data point of a container resource metric time series.","required":["time","value"],"properties":{"time":{"type":"string","description":"Bucket timestamp (ISO 8601 with `Z` suffix).","example":"2025-10-12T12:15:00+00:00"},"value":{"type":"number","format":"double","description":"Averaged metric value for the bucket."}}},"ContainerMetricsHistoryQuery":{"type":"object","description":"Query parameters for the container metrics history endpoint.","required":["metric"],"properties":{"metric":{"type":"string","description":"Dotted metric name, e.g. `container.cpu_percent` or\n`container.memory_used_bytes`."},"range":{"type":"string","description":"Time window: `1h`, `6h`, `24h`, or `7d` (defaults to `1h`)."}}},"ContainerMetricsResponse":{"type":"object","description":"Container resource metrics (CPU, memory usage)","required":["container_id","container_name","cpu_percent","memory_bytes","network_rx_bytes","network_tx_bytes","timestamp"],"properties":{"container_id":{"type":"string"},"container_name":{"type":"string"},"cpu_limit_cores":{"type":["number","null"],"format":"double","description":"CPU limit in whole cores (e.g. 1.0). None = no limit."},"cpu_percent":{"type":"number","format":"double","description":"CPU usage as a multi-core percentage (Docker convention: 200 = 2 cores\nfully pinned). Divide by 100 to get cores used."},"memory_bytes":{"type":"integer","format":"int64","description":"Memory usage in bytes","minimum":0},"memory_limit_bytes":{"type":["integer","null"],"format":"int64","description":"Memory limit in bytes (if set)","minimum":0},"memory_percent":{"type":["number","null"],"format":"double","description":"Memory usage percentage (0-100) if limit is set"},"network_rx_bytes":{"type":"integer","format":"int64","description":"Network bytes received","minimum":0},"network_tx_bytes":{"type":"integer","format":"int64","description":"Network bytes transmitted","minimum":0},"timestamp":{"type":"string","description":"Timestamp of metrics collection","example":"2025-10-12T12:15:47.609192Z"}}},"ContainerResponse":{"type":"object","required":["name","container_type","can_contain_containers","can_contain_entities","metadata"],"properties":{"can_contain_containers":{"type":"boolean","description":"Can this container hold other containers?","example":true},"can_contain_entities":{"type":"boolean","description":"Can this container hold entities (tables, collections, etc.)?","example":false},"child_container_type":{"type":["string","null"],"description":"Type of child containers (if can_contain_containers is true)","example":"schema"},"container_type":{"type":"string","description":"Container type (database, schema, keyspace, bucket, etc.)","example":"database"},"entity_count_hint":{"type":["string","null"],"description":"Hint for UI on expected entity count (small = sidebar, large = pagination)","example":"large"},"entity_type_label":{"type":["string","null"],"description":"Label for entity type (if can_contain_entities is true)","example":"table"},"metadata":{"description":"Additional metadata"},"name":{"type":"string","description":"Container name","example":"mydb"}}},"ContainerRuntimeInfo":{"type":"object","description":"Snapshot of a container's lifecycle state from `docker inspect`.\n`restart_count` and `oom_killed` are the load-bearing fields when\ndiagnosing crash loops — the kernel OOM killer never reaches the\napplication's logs, so seeing `oom_killed=true` is the only signal\nthat a memory limit was the cause.","required":["role","container_name","resource_limits"],"properties":{"container_id":{"type":["string","null"],"description":"Container Docker id, when present. None = container does not exist\n(was never created or was removed externally)."},"container_name":{"type":"string","description":"Stable name of the Docker container (e.g. `postgres-mydb`)."},"exit_code":{"type":["integer","null"],"format":"int64","description":"Last container exit code, when known. Non-zero = unclean stop."},"finished_at":{"type":["string","null"],"description":"ISO-8601 timestamp of the most recent termination, when known."},"image":{"type":["string","null"],"description":"Currently-effective Docker image (e.g. `gotempsh/postgres-walg:18-bookworm`)."},"oom_killed":{"type":["boolean","null"],"description":"True when the container's last termination was caused by the\nkernel OOM killer. Set if the user enabled hard memory limits\nand the working set exceeded them."},"resource_limits":{"$ref":"#/components/schemas/ServiceResourceLimits","description":"Currently-applied resource limits read off the container's\n`HostConfig`. Compare this against the user-configured limits to\ndetect drift (an old container that never picked up new caps)."},"restart_count":{"type":["integer","null"],"format":"int64","description":"Total restarts since the container was created. Useful for\ndetecting crash loops — a steady stream means something is killing\nthe container repeatedly (frequently OOM)."},"role":{"type":"string","description":"`service_members.role` for cluster members; \"standalone\" otherwise."},"started_at":{"type":["string","null"],"description":"ISO-8601 timestamp of when the container last started. None when\nit has never started (i.e. created but never run)."},"status":{"type":["string","null"],"description":"Bollard container state (\"running\", \"exited\", \"dead\", etc.). None\nwhen the container does not exist."}}},"ContainerStatsSample":{"type":"object","description":"Live resource usage sample for a single container.\n\n`cpu_percent` is computed by Docker's standard formula:\n ((cpu_delta / system_delta) * online_cpus) * 100\n`memory_percent` is `(memory_usage / memory_limit) * 100` — when no\nmemory limit is set the limit reported by Docker is the host's total\nRAM, so a 5% reading means \"5% of host RAM\", not \"5% of allocated\".","required":["role","container_name"],"properties":{"container_name":{"type":"string"},"cpu_percent":{"type":["number","null"],"format":"double","description":"CPU usage as a percentage. `None` when the container is not running\n(Docker returns no usable counters)."},"memory_limit_bytes":{"type":["integer","null"],"format":"int64","description":"Memory limit in bytes (host RAM if no limit set).","minimum":0},"memory_percent":{"type":["number","null"],"format":"double","description":"Memory usage as a percentage of `memory_limit_bytes`."},"memory_usage_bytes":{"type":["integer","null"],"format":"int64","description":"Resident memory usage in bytes.","minimum":0},"online_cpus":{"type":["integer","null"],"format":"int32","description":"Number of cores Docker observed at sample time. Used by the UI\nto label \"x/y cores\" instead of just a percent.","minimum":0},"role":{"type":"string"}}},"ContentPart":{"type":"object","required":["type"],"properties":{"image_url":{},"text":{"type":["string","null"]},"type":{"type":"string"}}},"ContextLine":{"type":"object","description":"A line in context response","required":["timestamp","level","message","line_offset","is_match"],"properties":{"fields":{},"is_match":{"type":"boolean","description":"Whether this line matched the original search"},"level":{"$ref":"#/components/schemas/LogLevel"},"line_offset":{"type":"integer","format":"int32"},"message":{"type":"string"},"timestamp":{"type":"string"}}},"ContextLogsRequest":{"type":"object","required":["chunk_id","line_offset"],"properties":{"chunk_id":{"type":"string"},"line_offset":{"type":"integer","format":"int32"},"lines":{"type":["integer","null"],"format":"int32","description":"Number of context lines before and after (default: 25)","minimum":0}}},"ContextLogsResponse":{"type":"object","required":["lines","target_index"],"properties":{"lines":{"type":"array","items":{"$ref":"#/components/schemas/ContextLine"}},"target_index":{"type":"integer","minimum":0}}},"ConversationDetailResponse":{"allOf":[{"$ref":"#/components/schemas/ConversationResponse"},{"type":"object","required":["messages"],"properties":{"messages":{"type":"array","items":{"$ref":"#/components/schemas/MessageResponse"},"description":"Turns oldest-first. The `system` seed message is omitted (internal)."}}}]},"ConversationResponse":{"type":"object","required":["public_id","context_type","context_id","status","created_at","last_activity_at"],"properties":{"context_id":{"type":"string"},"context_type":{"type":"string"},"created_at":{"type":"string"},"last_activity_at":{"type":"string"},"public_id":{"type":"string"},"status":{"type":"string"},"title":{"type":["string","null"]}}},"ConversationSummary":{"type":"object","description":"A conversation summary grouping related AI invocations.","required":["conversation_id","message_count","total_input_tokens","total_output_tokens","total_tokens","total_cost_microcents","avg_latency_ms","models_used","first_at","last_at"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"conversation_id":{"type":"string"},"first_at":{"type":"string"},"last_at":{"type":"string"},"message_count":{"type":"integer","format":"int64"},"models_used":{"type":"array","items":{"type":"string"}},"total_cost_microcents":{"type":"integer","format":"int64"},"total_input_tokens":{"type":"integer","format":"int64"},"total_output_tokens":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"ConversationsQueryParams":{"type":"object","properties":{"from":{"type":["string","null"],"description":"ISO 8601 start time (defaults to 24h ago)"},"limit":{"type":["integer","null"],"format":"int64","description":"Max results (defaults to 50, max 100)","minimum":0},"model":{"type":["string","null"],"description":"Filter by model name"},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"to":{"type":["string","null"],"description":"ISO 8601 end time (defaults to now)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"CopyBlobRequest":{"type":"object","description":"Request to copy a blob","required":["fromUrl","toPathname"],"properties":{"fromUrl":{"type":"string","description":"Source blob URL or pathname","example":"/api/blob/10/images/avatar.png"},"projectId":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1},"toPathname":{"type":"string","description":"Destination pathname","example":"images/avatar-copy.png"}}},"CostAnalysis":{"type":"object","description":"Full cluster cost + rightsizing analysis attached to an import plan.","required":["nodes","capacity","requested","usage_source","overprovisioning","recommendation","notes"],"properties":{"actual_usage":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ResourceFootprint","description":"Measured usage from the metrics API (`metrics.k8s.io`).\n`None` when metrics-server is not installed."}]},"capacity":{"$ref":"#/components/schemas/ClusterCapacity","description":"Total cluster capacity (sum of node allocatable resources)"},"control_plane_monthly_usd":{"type":["number","null"],"format":"double","description":"Managed control-plane fee included in `current_monthly_usd` (EKS/GKE\ncharge ~$73/mo per cluster). `None` when not applicable/unknown."},"current_monthly_usd":{"type":["number","null"],"format":"double","description":"Estimated total infrastructure cost per month in USD (compute nodes +\ncontrol-plane fee). `None` when no node could be priced."},"nodes":{"type":"array","items":{"$ref":"#/components/schemas/NodeCostInfo"},"description":"Per-node inventory with price estimates where the instance type is known"},"notes":{"type":"array","items":{"type":"string"},"description":"Honesty notes: what could not be measured, which numbers are\nestimates, and any assumptions made. Always shown to the user."},"overprovisioning":{"$ref":"#/components/schemas/OverprovisioningAssessment","description":"Requests-vs-capacity-vs-usage assessment"},"provider":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/CloudProvider","description":"Detected cloud provider (from node `providerID` prefixes)"}]},"recommendation":{"$ref":"#/components/schemas/TargetRecommendation","description":"The temps/Hetzner target sizing and savings estimate"},"requested":{"$ref":"#/components/schemas/ResourceFootprint","description":"Sum of pod resource *requests* across running pods — what the\nscheduler has reserved, i.e. what the cluster is sized for."},"usage_source":{"$ref":"#/components/schemas/UsageSource","description":"How the usage numbers were obtained (drives UI wording)"}}},"CreateAlertRuleRequest":{"type":"object","required":["name","trigger_type"],"properties":{"cooldown_minutes":{"type":"integer","format":"int32","description":"Minimum minutes between notifications for same rule+group"},"enabled":{"type":"boolean"},"environment_filter":{"type":["integer","null"],"format":"int32","description":"Optional environment ID to filter alerts"},"error_level_filter":{"type":["string","null"],"description":"Optional error type/level filter"},"name":{"type":"string"},"notification_priority":{"type":"string","description":"Notification priority: Low, Normal, High, Critical"},"trigger_config":{"description":"Trigger-specific configuration (e.g., {\"count\": 100, \"window_minutes\": 60} for frequency)"},"trigger_type":{"type":"string","description":"Trigger type: new_issue, regression, frequency, new_user, user_count, status_change"}}},"CreateApiKeyRequest":{"type":"object","required":["name","role_type"],"properties":{"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"},"example":["projects:read","deployments:read"]},"role_type":{"type":"string","example":"admin"}}},"CreateApiKeyResponse":{"type":"object","required":["id","name","key_prefix","role_type","api_key","created_at"],"properties":{"api_key":{"type":"string"},"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00Z"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"id":{"type":"integer","format":"int32"},"key_prefix":{"type":"string"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"}},"role_type":{"type":"string"}}},"CreateBackupScheduleRequest":{"type":"object","required":["name","backup_type","retention_period","schedule_expression","enabled","tags"],"properties":{"backup_type":{"type":"string"},"description":{"type":["string","null"]},"enabled":{"type":"boolean"},"include_control_plane":{"type":["boolean","null"],"description":"When `true` (default), every run also produces a `control_plane`\nbackup of Temps's own database. Operators who use Temps purely as\na backup orchestrator for external DBs can set this to `false` to\nkeep the run history focused on those services."},"max_runtime_secs":{"type":["integer","null"],"format":"int64","description":"Optional wall-clock timeout override for jobs created by this schedule\n(seconds). When set, overrides the engine-family default. `null` means\n\"use engine default.\" The per-job `max_runtime_secs` in\n`EnqueueJobParams` can still override this for ad-hoc triggers."},"name":{"type":"string"},"retention_period":{"type":"integer","format":"int32"},"s3_source_id":{"type":["integer","null"],"format":"int32","description":"Optional S3 source. If omitted, the current default S3 source is used."},"schedule_expression":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"target_all_services":{"type":["boolean","null"],"description":"When `true` (default), the schedule backs up every external service\non the host — including databases created in the future. When\n`false`, the schedule backs up only the services explicitly attached\nvia `POST /backups/schedules/{id}/services`. Omit to use the default."}}},"CreateBitbucketRequest":{"type":"object","required":["name","auth"],"properties":{"auth":{"$ref":"#/components/schemas/BitbucketAuthInput","description":"Authentication credentials — either an access token or an app password."},"name":{"type":"string","description":"Display name for this provider."}}},"CreateCloudflareProviderRequest":{"type":"object","required":["name","config"],"properties":{"config":{"$ref":"#/components/schemas/CloudflareConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":"string"}}},"CreateConversationRequest":{"type":"object","required":["context_type","context_id"],"properties":{"context_id":{"type":"string","description":"The entity id (ints stringified)."},"context_type":{"type":"string","description":"e.g. `\"deployment\"`."}}},"CreateDSNRequest":{"type":"object","properties":{"base_url":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"name":{"type":["string","null"]}}},"CreateDashboardRequest":{"type":"object","required":["project_id","name","layout"],"properties":{"layout":{"$ref":"#/components/schemas/DashboardLayout"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"}}},"CreateDeploymentTokenRequest":{"type":"object","required":["name"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment ID - if set, token is scoped to a specific deployment"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment ID - if not set, token applies to all environments"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"},"description":"List of permissions (e.g., [\"visitors:enrich\", \"emails:send\"])\nIf not provided, defaults to full access","example":["visitors:enrich","emails:send"]}}},"CreateDeploymentTokenResponse":{"type":"object","required":["id","project_id","name","token_prefix","token","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00Z"},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"}},"project_id":{"type":"integer","format":"int32"},"token":{"type":"string","description":"The full token value - only returned on creation"},"token_prefix":{"type":"string"}}},"CreateDnsProviderRequest":{"type":"object","description":"Request to create a new DNS provider","required":["name","provider_type","credentials"],"properties":{"credentials":{"$ref":"#/components/schemas/DnsProviderCredentials","description":"Provider credentials"},"description":{"type":["string","null"],"description":"Optional description"},"name":{"type":"string","description":"User-friendly name","example":"My Cloudflare"},"provider_type":{"$ref":"#/components/schemas/DnsProviderType","description":"Provider type"}}},"CreateDomainRequest":{"type":"object","required":["domain"],"properties":{"challenge_type":{"type":"string","description":"Challenge type for Let's Encrypt validation. Options: \"http-01\" (default) or \"dns-01\""},"domain":{"type":"string"}}},"CreateEmailDomainRequest":{"type":"object","required":["provider_id","domain"],"properties":{"domain":{"type":"string","description":"Domain name (e.g., \"updates.example.com\")","example":"updates.example.com"},"provider_id":{"type":"integer","format":"int32","description":"Provider ID to use for this domain"}}},"CreateEmailProviderRequest":{"type":"object","required":["name","provider_type","region"],"properties":{"name":{"type":"string","description":"User-friendly name for the provider","example":"My AWS SES"},"provider_type":{"$ref":"#/components/schemas/EmailProviderTypeRoute","description":"Provider type"},"region":{"type":"string","description":"Cloud region. For SMTP this is informational only — the host/port carry the real routing.","example":"us-east-1"},"scaleway_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ScalewayCredentialsRequest","description":"Scaleway credentials (required if provider_type is scaleway)"}]},"ses_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SesCredentialsRequest","description":"AWS SES credentials (required if provider_type is ses)"}]},"smtp_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SmtpCredentialsRequest","description":"Generic SMTP credentials (required if provider_type is smtp). Use when\nyou only have SMTP creds and want to import an already-set-up domain."}]},"sns_topic_arn":{"type":["string","null"],"description":"Exact SNS topic allowed to deliver SES events for this provider."}}},"CreateEnvironmentRequest":{"type":"object","required":["name","branch"],"properties":{"branch":{"type":"string"},"name":{"type":"string"},"set_as_preview":{"type":"boolean","description":"If true, set this environment as the preview environment for the project"}}},"CreateEnvironmentVariableRequest":{"type":"object","required":["key","value","environment_ids"],"properties":{"environment_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"include_in_preview":{"type":"boolean","description":"Include this environment variable in preview environments (default: true)"},"is_secret":{"type":"boolean","description":"When true the variable is treated as write-only: never returned in\nplaintext from the API, masked in the UI, and updates that omit the\nvalue preserve the existing ciphertext. The flag is one-way — secret\nvars cannot be demoted back to regular vars."},"key":{"type":"string"},"value":{"type":"string"}}},"CreateExternalServiceRequest":{"type":"object","required":["name","service_type","parameters"],"properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/ClusterMemberRequest"},"description":"Cluster member specifications. Required when topology is \"cluster\"."},"name":{"type":"string"},"node_id":{"type":["integer","null"],"format":"int32","description":"Target node ID for the service. Omit or null to run on the control plane."},"parameters":{"type":"object","additionalProperties":{},"propertyNames":{"type":"string"}},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute"},"topology":{"type":"string","description":"Service topology: \"standalone\" (default) or \"cluster\" (HA multi-member).","example":"standalone"},"version":{"type":["string","null"]}}},"CreateFlagRequest":{"type":"object","required":["key","value_type","default_value"],"properties":{"client_visible":{"type":"boolean","description":"Whether the flag may be exposed on the unauthenticated same-origin\nevaluation endpoint. Defaults to `false`: flags are server-only unless\nexplicitly opted in, because targeting rules can encode business logic."},"default_value":{"description":"Served whenever evaluation cannot do better. Must match `value_type`.\n\nLeft unannotated so utoipa emits a free-form schema: a bool flag's\ndefault is `false`, not an object, and `value_type = Object` would tell\nevery generated client otherwise."},"description":{"type":["string","null"]},"key":{"type":"string","description":"Stable key used in application code. Immutable after create.","example":"checkout.v2"},"value_type":{"$ref":"#/components/schemas/FlagValueType","description":"Fixed at create: retyping would invalidate every stored value and every\ncall site."}}},"CreateFunnelRequest":{"type":"object","required":["name","steps"],"properties":{"description":{"type":["string","null"]},"name":{"type":"string"},"steps":{"type":"array","items":{"$ref":"#/components/schemas/CreateFunnelStep"}}}},"CreateFunnelResponse":{"type":"object","required":["funnel_id","message"],"properties":{"funnel_id":{"type":"integer","format":"int32"},"message":{"type":"string"}}},"CreateFunnelStep":{"type":"object","required":["event_name"],"properties":{"event_filter":{"type":"array","items":{"$ref":"#/components/schemas/SmartFilter"}},"event_name":{"type":"string"}}},"CreateGenericRequest":{"type":"object","required":["name","clone_url"],"properties":{"base_url":{"type":["string","null"],"description":"Optional base URL of the git host for display purposes (no API is called)."},"clone_url":{"type":"string","description":"HTTPS clone URL for the repository, e.g. `https://git.example.com/org/repo.git`."},"name":{"type":"string","description":"Display name for this provider."},"token":{"type":["string","null"],"description":"Access token or password. Omit (or set to `null`) for public repositories."},"token_username":{"type":["string","null"],"description":"HTTP Basic username used with the token. Defaults to `x-access-token` when\nabsent or empty. Ignored for public (unauthenticated) repositories."}}},"CreateGitHubPATRequest":{"type":"object","required":["name","token"],"properties":{"name":{"type":"string"},"token":{"type":"string"}}},"CreateGitLabOAuthRequest":{"type":"object","required":["name","client_id","client_secret","redirect_uri"],"properties":{"base_url":{"type":["string","null"]},"client_id":{"type":"string"},"client_secret":{"type":"string"},"name":{"type":"string"},"redirect_uri":{"type":"string"}}},"CreateGitLabPATRequest":{"type":"object","required":["name","token"],"properties":{"base_url":{"type":["string","null"]},"name":{"type":"string"},"token":{"type":"string"}}},"CreateGiteaPATRequest":{"type":"object","required":["name","token","base_url"],"properties":{"base_url":{"type":"string","description":"HTTPS base URL of the Gitea instance, e.g. `https://git.example.com`."},"name":{"type":"string","description":"Display name for this provider."},"token":{"type":"string","description":"Personal access token issued by the Gitea instance."}}},"CreateIncidentRequest":{"type":"object","required":["title","severity"],"properties":{"description":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"monitor_id":{"type":["integer","null"],"format":"int32"},"severity":{"type":"string"},"title":{"type":"string"}}},"CreateIntegrationBody":{"type":"object","required":["provider","signing_secret"],"properties":{"provider":{"type":"string","description":"Registered provider name, e.g. \"stripe\"."},"signing_secret":{"type":"string","description":"Signing secret from the provider's dashboard."}}},"CreateIpAccessControlRequest":{"type":"object","description":"Request to create an IP access control rule","required":["ip_address","action"],"properties":{"action":{"type":"string","description":"Action to take: \"block\" or \"allow\"","example":"block"},"ip_address":{"type":"string","description":"IP address in CIDR notation (e.g., \"192.168.1.1\" or \"10.0.0.0/24\")","example":"192.168.1.100"},"reason":{"type":["string","null"],"description":"Optional reason for the action","example":"Malicious activity detected"}}},"CreateMcpRequest":{"type":"object","required":["slug","name","config"],"properties":{"config":{"type":"object"},"description":{"type":["string","null"]},"name":{"type":"string"},"slug":{"type":"string"}}},"CreateMetricAlertRequest":{"type":"object","required":["project_id","name","metric_name","aggregation","detection_config","window_secs","for_duration_secs","severity","enabled"],"properties":{"aggregation":{"type":"string","description":"One of `avg|sum|min|max|count|rate|p50|p90|p95|p99`."},"detection_config":{"$ref":"#/components/schemas/DetectionConfig","description":"The detector: a discriminated union keyed by `kind`. Today only\n`{ \"kind\": \"static\", \"comparator\": \"gt\", \"threshold\": 500 }` is evaluable."},"dynamic_alerts":{"type":"boolean","description":"When true (and `group_by` is set) fire one independent alarm per breaching\nseries. Static detectors only. Default false."},"enabled":{"type":"boolean"},"for_duration_secs":{"type":"integer","format":"int32"},"group_by":{"type":"array","items":{"type":"string"},"description":"Label keys to break the metric down by, e.g. `[\"endpoint\",\"region\"]`. Empty\n(the default) = one aggregate stream. Max 2 keys; keys must match\n`[a-zA-Z0-9_.:-]`."},"grouped_notification_threshold":{"type":"integer","format":"int32","description":"When more than this many series transition to firing in the same tick, only\nthe first gets the expensive chart/AI enrichment. Range 1–1000, default 5."},"label_filters":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"AND-combined label equality filters: `[[\"key\",\"value\"],…]`. Empty = no\nfiltering (the default). Max 10 pairs; keys must match `[a-zA-Z0-9_.:-]`;\nvalues capped at 500 characters."},"max_series":{"type":"integer","format":"int32","description":"Cardinality cap for dynamic alerting: at most this many series (top by\n`|value|`). Range 1–100, default 20."},"metric_name":{"type":"string"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"severity":{"type":"string","description":"One of `info|warning|critical`."},"window_secs":{"type":"integer","format":"int32"}}},"CreateMonitorRequest":{"type":"object","required":["name","monitor_type","environment_id"],"properties":{"check_interval_seconds":{"type":["integer","null"],"format":"int32"},"check_path":{"type":["string","null"]},"environment_id":{"type":"integer","format":"int32"},"monitor_type":{"type":"string"},"name":{"type":"string"}}},"CreateNotificationEmailProviderRequest":{"type":"object","required":["name","config"],"properties":{"config":{"$ref":"#/components/schemas/EmailConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":"string"}}},"CreateOidcProviderRequest":{"type":"object","required":["name","issuer_url","client_id","client_secret"],"properties":{"client_id":{"type":"string"},"client_secret":{"type":"string"},"default_role":{"type":"string"},"enabled":{"type":"boolean"},"group_claim":{"type":"string"},"issuer_url":{"type":"string"},"jit_provisioning":{"type":"boolean"},"name":{"type":"string"},"role_claim":{"type":"string"},"scopes":{"type":"string"},"template":{"type":"string"},"trust_idp_email":{"type":"boolean","description":"Defaults false. Set to true only for IdPs where an admin\ncontrols user provisioning (corporate Okta, Azure AD) and\nself-signup of arbitrary emails is not possible — see the\n`trust_idp_email` field on `oidc_providers::Model` for the\nsecurity tradeoff this enables."}}},"CreateOidcRoleMappingRequest":{"type":"object","required":["priority","idp_group","role"],"properties":{"idp_group":{"type":"string"},"priority":{"type":"integer","format":"int32"},"role":{"type":"string"}}},"CreatePlanRequest":{"type":"object","description":"Request to create an import plan","required":["source","workload_id"],"properties":{"credentials":{"$ref":"#/components/schemas/ImportCredentials","description":"Platform credentials (required for cloud platforms like Vercel, Railway)"},"repository_id":{"type":["integer","null"],"format":"int32","description":"Optional repository ID to associate with the import\nIf provided, preset will be detected from the repository"},"source":{"$ref":"#/components/schemas/ImportSource","description":"Source to import from"},"workload_id":{"$ref":"#/components/schemas/WorkloadId","description":"Workload ID to import"}}},"CreatePlanResponse":{"type":"object","description":"Response with created plan","required":["session_id","plan","validation","can_execute"],"properties":{"can_execute":{"type":"boolean","description":"Whether the plan can be executed"},"plan":{"$ref":"#/components/schemas/ImportPlan","description":"Generated import plan"},"session_id":{"type":"string","description":"Session ID for tracking"},"validation":{"$ref":"#/components/schemas/ValidationReport","description":"Validation report"}}},"CreatePrResponse":{"type":"object","required":["run","pr_url","pr_number","branch_name"],"properties":{"branch_name":{"type":"string"},"pr_number":{"type":"integer","format":"int32"},"pr_url":{"type":"string"},"run":{"$ref":"#/components/schemas/AutofixerRunResponse"}}},"CreateProjectAccessRequest":{"type":"object","required":["team_id","role"],"properties":{"role":{"$ref":"#/components/schemas/TeamRole"},"team_id":{"type":"integer","format":"int32"}}},"CreateProjectFromTemplateRequest":{"type":"object","description":"Request to create a project from a template\n\nSupports two deploy modes:\n * **Fork mode** — when `git_provider_connection_id` is set, the template\n repo is cloned into a new repository under the user's Git account and the\n project tracks that fork (git-push deploys, automatic deploy on push).\n * **One-click public-repo mode** — when `git_provider_connection_id` is\n omitted, the project deploys directly from the template's public source\n repository (no fork, no Git account required). This is the activation\n path: a brand-new user with no Git provider connected can still deploy a\n demo in one click. `repository_name` / `repository_owner` are ignored in\n this mode, and automatic-deploy-on-push is unavailable (there is no fork\n to receive webhooks).","required":["template_slug","project_name"],"properties":{"automatic_deploy":{"type":"boolean","description":"Enable automatic deployment on push (defaults to true). Only honoured in\nfork mode; public-repo deploys cannot receive push webhooks."},"environment_variables":{"type":"array","items":{"$ref":"#/components/schemas/EnvVarInput"},"description":"Environment variables to set (key-value pairs)"},"git_provider_connection_id":{"type":["integer","null"],"format":"int32","description":"Git provider connection ID. When omitted, the project deploys directly\nfrom the template's public source repository instead of forking it."},"private":{"type":"boolean","description":"Whether to make the repository private (defaults to true)"},"project_name":{"type":"string","description":"Name for the new project"},"repository_name":{"type":["string","null"],"description":"Name for the new repository to create. Required in fork mode; ignored in\none-click public-repo mode."},"repository_owner":{"type":["string","null"],"description":"Owner/organization for the new repository (defaults to authenticated user)"},"storage_service_ids":{"type":"array","items":{"type":"integer","format":"int32"},"description":"External storage service IDs to attach to the project"},"template_slug":{"type":"string","description":"Template slug to use as the base"}}},"CreateProjectFromTemplateResponse":{"type":"object","description":"Response after creating a project from template","required":["project_id","project_slug","project_name","repository_url","template_slug","message"],"properties":{"message":{"type":"string","description":"Message with additional info"},"project_id":{"type":"integer","format":"int32","description":"ID of the created project"},"project_name":{"type":"string","description":"Name of the created project"},"project_slug":{"type":"string","description":"Slug of the created project"},"repository_url":{"type":"string","description":"URL of the created repository"},"template_slug":{"type":"string","description":"Template that was used"}}},"CreateProjectRequest":{"type":"object","required":["name","directory","main_branch","preset","storage_service_ids"],"properties":{"automatic_deploy":{"type":["boolean","null"]},"build_command":{"type":["string","null"]},"custom_domain":{"type":["string","null"]},"directory":{"type":"string"},"environment_variables":{"type":["array","null"],"items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]}},"exposed_port":{"type":["integer","null"],"format":"int32","description":"Port exposed by the container (fallback when image has no EXPOSE directive)\n\nPriority order for port resolution:\n1. Image EXPOSE directive (auto-detected from built image)\n2. Environment-level exposed_port (overrides this value per environment)\n3. This project-level exposed_port (fallback)\n4. Default: 3000\n\nOnly set this if your image doesn't use EXPOSE directive.","example":8080},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"git_url":{"type":["string","null"]},"install_command":{"type":["string","null"]},"is_on_demand":{"type":["boolean","null"]},"is_public_repo":{"type":["boolean","null"]},"is_web_app":{"type":["boolean","null"]},"main_branch":{"type":"string"},"name":{"type":"string"},"output_dir":{"type":["string","null"]},"performance_metrics_enabled":{"type":"boolean"},"preset":{"type":"string"},"preset_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PresetConfigSchema","description":"Preset-specific configuration\n\nDifferent presets accept different configuration options:\n- **Dockerfile preset**: Accepts `DockerfilePresetConfig` with `dockerfile_path` and `build_context`\n- **Nixpacks preset**: Accepts ordered `providers` (for example `[\"...\", \"python\"]`)\n and optional inline `nixpacksConfig` TOML\n- **Static presets** (Vite, Next.js, etc.): Accept `StaticPresetConfig` with build commands and output dir\n\nExample for Dockerfile preset:\n```json\n{\n \"dockerfilePath\": \"docker/Dockerfile\",\n \"buildContext\": \"./api\"\n}\n```"}]},"project_type":{"type":["string","null"]},"repo_name":{"type":["string","null"]},"repo_owner":{"type":["string","null"]},"source_type":{"$ref":"#/components/schemas/SourceType","description":"Source type for deployments\n\nDetermines how the project is deployed:\n- **git** (default): Traditional Git-based deployments - source code is pulled, built, and deployed\n- **docker_image**: Deploy pre-built Docker images from external registries (DockerHub, GHCR, etc.)\n- **static_files**: Deploy pre-built static files uploaded as tar.gz or zip bundles\n\nFor `docker_image` and `static_files` source types, `repo_name` and `repo_owner` are optional."},"storage_service_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"use_default_wildcard":{"type":["boolean","null"]}}},"CreateProjectSecretRequest":{"type":"object","description":"Request to create a new project secret.\n\nProject secrets are mounted into the container as files under\n`/run/secrets/` (mode 0400, tmpfs) instead of as environment variables.\nValues are always encrypted at rest and never returned in plaintext from\nthe API after create. Distinct from agent secrets (global `/settings/secrets`).","required":["key","value"],"properties":{"environment_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"include_in_preview":{"type":"boolean","description":"Include this secret in preview environments."},"key":{"type":"string","description":"Identifier for the secret. Becomes the filename at `/run/secrets/`.\nMust start with a letter or underscore and contain only A-Z, a-z, 0-9, _."},"value":{"type":"string","description":"Plaintext value, <= 1 MiB."}}},"CreateProviderKeyRequest":{"type":"object","required":["provider","display_name","api_key"],"properties":{"api_key":{"type":"string"},"base_url":{"type":["string","null"]},"default_model":{"type":["string","null"],"description":"Optional model id to pin for this provider (e.g. \"gpt-4o-mini\")."},"display_name":{"type":"string"},"provider":{"type":"string"}}},"CreateProviderRequest":{"type":"object","required":["name","provider_type","config"],"properties":{"config":{},"enabled":{"type":["boolean","null"]},"name":{"type":"string"},"provider_type":{"type":"string"}}},"CreateRouteRequest":{"type":"object","required":["domain","host","port"],"properties":{"domain":{"type":"string"},"host":{"type":"string"},"port":{"type":"integer","format":"int32"},"route_type":{"type":["string","null"],"description":"Route type: \"http\" (default) matches on HTTP Host header,\n\"tls\" matches on TLS SNI hostname for TCP passthrough"}}},"CreateS3SourceRequest":{"type":"object","required":["name","bucket_name","bucket_path","access_key_id","secret_key","region"],"properties":{"access_key_id":{"type":"string"},"bucket_name":{"type":"string"},"bucket_path":{"type":"string"},"endpoint":{"type":["string","null"],"description":"Optional endpoint URL for S3-compatible services like MinIO","example":"http://minio.example.com:9000"},"force_path_style":{"type":["boolean","null"],"description":"Whether to use path-style addressing (default: true)","example":true},"is_default":{"type":["boolean","null"],"description":"When true, make this the default source (will swap out any existing default).\nThe very first S3 source is always created as default regardless of this flag.","example":false},"name":{"type":"string"},"region":{"type":"string"},"secret_key":{"type":"string"}}},"CreateSandboxBody":{"type":"object","properties":{"_runtime":{"type":["string","null"]},"backend":{"type":["string","null"],"description":"Isolation backend: `\"docker\"` (default) or `\"firecracker\"` (ADR-029,\nhardware-virtualized microVM — requires a host provisioned with\n`temps firecracker setup`). Omit for the platform default; existing\nclients are unaffected. Requesting an unavailable backend fails with\n400 rather than silently downgrading isolation."},"cpu_limit":{"type":["number","null"],"format":"double"},"disk_size_mb":{"type":["integer","null"],"format":"int64","description":"Root disk size in MB (Firecracker only; Docker ignores it). Omit for\nthe platform default (1 GiB).","minimum":0},"env":{"type":"object","description":"Extra env vars baked into the container on create.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"image":{"type":["string","null"],"description":"Docker image override. `null` uses the platform default."},"memory_limit_mb":{"type":["integer","null"],"format":"int64","minimum":0},"name":{"type":["string","null"]},"networkPolicy":{},"pids_limit":{"type":["integer","null"],"format":"int64"},"ports":{"type":"array","items":{"type":"integer","format":"int32","minimum":0},"description":"Ports the sandbox will listen on. Each port becomes a `routes[]`\nentry in the create/get response so `@vercel/sandbox`'s\n`sandbox.domain(port)` can resolve it client-side without an\nextra round-trip."},"preview_password":{"type":["string","null"],"description":"Optional preview-URL password. When set, every preview URL served\nfor this sandbox is gated behind a login form. 8–256 characters.\nOmit to leave preview URLs open (the sandbox ID remains the only\ngate). The plaintext is never returned; only the last-4 hint is\nsurfaced in `SandboxResponse.preview_password_hint`."},"projectId":{"type":["string","null"]},"resources":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ResourcesBody","description":"`@vercel/sandbox`'s nested resources object. When present, its\n`memory` / `vcpus` populate `memory_limit_mb` / `cpu_limit` if those\nweren't sent directly."}]},"source":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SourceBody","description":"Optional initial content to seed into the work dir. Clones a\nrepo or extracts a tarball after the sandbox is created."}]},"timeout":{"type":["integer","null"],"format":"int64","description":"Idle timeout as sent by `@vercel/sandbox` (milliseconds). Converted\nto seconds when `timeout_secs` is absent.","minimum":0},"timeout_secs":{"type":["integer","null"],"format":"int64","description":"Idle timeout in seconds (temps-native). Clamped to `[60, 86400]`.","minimum":0}}},"CreateSkillRequest":{"type":"object","required":["slug","name","content"],"properties":{"content":{"type":"string"},"description":{"type":["string","null"]},"name":{"type":"string"},"slug":{"type":"string"}}},"CreateSlackProviderRequest":{"type":"object","required":["name","config"],"properties":{"config":{"$ref":"#/components/schemas/SlackConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":"string"}}},"CreateTeamMemberRequest":{"type":"object","required":["user_id","role"],"properties":{"role":{"$ref":"#/components/schemas/TeamRole"},"user_id":{"type":"integer","format":"int32"}}},"CreateTeamRequest":{"type":"object","required":["name","slug"],"properties":{"description":{"type":["string","null"]},"name":{"type":"string"},"slug":{"type":"string"}}},"CreateUserRequest":{"type":"object","required":["username","roles"],"properties":{"email":{"type":["string","null"]},"password":{"type":["string","null"]},"roles":{"type":"array","items":{"type":"string"}},"username":{"type":"string"}}},"CreateWebhookProviderRequest":{"type":"object","required":["name","config"],"properties":{"config":{"$ref":"#/components/schemas/WebhookConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":"string"}}},"CreateWebhookRequestBody":{"type":"object","required":["url","events"],"properties":{"enabled":{"type":["boolean","null"],"description":"Whether the webhook is enabled","default":true},"events":{"type":"array","items":{"type":"string"},"description":"Event types to subscribe to","example":["deployment.created","deployment.succeeded"]},"secret":{"type":["string","null"],"description":"Secret for HMAC signature verification (optional)"},"url":{"type":"string","description":"Target URL for webhook delivery","example":"https://example.com/webhook"}}},"CreatedResource":{"type":"object","description":"Resource created during import (for rollback / audit)","required":["resource_type","resource_id","resource_name"],"properties":{"resource_id":{"type":"integer","format":"int32","description":"Resource ID"},"resource_name":{"type":"string","description":"Resource name"},"resource_type":{"type":"string","description":"Resource type (project, environment, deployment, service, domain, etc.)"}}},"CronExecutionInfo":{"type":"object","required":["id","cron_id","executed_at","url","status_code","headers","response_time_ms"],"properties":{"cron_id":{"type":"integer","format":"int32"},"error_message":{"type":["string","null"]},"executed_at":{"type":"string"},"headers":{"type":"string"},"id":{"type":"integer","format":"int32"},"response_time_ms":{"type":"integer","format":"int32"},"status_code":{"type":"integer","format":"int32"},"url":{"type":"string"}}},"CronInfo":{"type":"object","required":["id","project_id","environment_id","path","schedule","created_at","updated_at"],"properties":{"created_at":{"type":"string"},"deleted_at":{"type":["string","null"]},"environment_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"next_run":{"type":["string","null"]},"path":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"schedule":{"type":"string"},"updated_at":{"type":"string"}}},"CrossProjectSiblingRef":{"type":"object","description":"A sibling project that shares the same `trace_id`, returned by the\nPhase 1 cross-project banner endpoint.","required":["project_id","project_name","project_slug","first_seen"],"properties":{"first_seen":{"type":"string","format":"date-time","description":"ISO 8601 timestamp (UTC, `Z` suffix) of first span ingest for this\n`(trace_id, project_id)` pair."},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"project_slug":{"type":"string","description":"URL slug used to link into the sibling project's single-project trace view."}}},"CrossProjectTraceResponse":{"type":"object","description":"Response body for `GET /otel/traces/cross-project/{trace_id}`.\n\nAn empty `siblings` vec is the normal single-project case — never 404.","required":["trace_id","siblings"],"properties":{"siblings":{"type":"array","items":{"$ref":"#/components/schemas/CrossProjectSiblingRef"},"description":"Projects other than the caller's that hold spans for this trace,\nordered by `first_seen ASC`."},"trace_id":{"type":"string","description":"The trace_id that was queried (echoed back for client convenience)."}}},"CurrentStatusResponse":{"type":"object","required":["monitor_id","current_status","uptime_percentage"],"properties":{"avg_response_time_ms":{"type":["number","null"],"format":"double"},"current_status":{"type":"string"},"last_check_at":{"type":["string","null"],"format":"date-time"},"monitor_id":{"type":"integer","format":"int32"},"uptime_percentage":{"type":"number","format":"double"}}},"CustomDomainRequest":{"type":"object","required":["domain","environment_id"],"properties":{"branch":{"type":["string","null"]},"domain":{"type":"string"},"environment_id":{"type":"integer","format":"int32"},"redirect_to":{"type":["string","null"]},"service_name":{"type":["string","null"],"description":"Docker Compose service name this domain routes to (only for docker-compose projects)"},"status_code":{"type":["integer","null"],"format":"int32"}}},"CustomDomainResponse":{"type":"object","required":["id","project_id","domain","status","created_at","updated_at"],"properties":{"branch":{"type":["string","null"]},"created_at":{"type":"integer","format":"int64"},"domain":{"type":"string"},"domain_id":{"type":["integer","null"],"format":"int32"},"environment":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DomainEnvironmentResponse"}]},"expiration_time":{"type":["integer","null"],"format":"int64"},"id":{"type":"integer","format":"int32"},"last_renewed":{"type":["integer","null"],"format":"int64"},"message":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"redirect_to":{"type":["string","null"]},"service_name":{"type":["string","null"],"description":"Docker Compose service name this domain routes to"},"status":{"type":"string"},"status_code":{"type":["integer","null"],"format":"int32"},"updated_at":{"type":"integer","format":"int64"}}},"CustomerMovementResponse":{"type":"object","required":["bucket","new_customers","churned_customers"],"properties":{"bucket":{"type":"string","format":"date-time"},"churned_customers":{"type":"integer","format":"int64"},"new_customers":{"type":"integer","format":"int64"}}},"DashboardLayout":{"type":"object","description":"The typed layout persisted (as JSONB) in `metric_dashboards.layout`.","required":["sections"],"properties":{"sections":{"type":"array","items":{"$ref":"#/components/schemas/DashboardSection"},"description":"Ordered sections that make up the dashboard."}}},"DashboardProjectsAnalyticsQuery":{"type":"object","description":"Query parameters for batch dashboard analytics","required":["project_ids","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"project_ids":{"type":"string","description":"Comma-separated list of project IDs"},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"DashboardProjectsAnalyticsResponse":{"type":"object","description":"Batch response for dashboard project analytics","required":["projects"],"properties":{"projects":{"type":"object","description":"Map of project_id -> analytics data","additionalProperties":{"$ref":"#/components/schemas/ProjectDashboardAnalytics"},"propertyNames":{"type":"string"}}}},"DashboardSection":{"type":"object","description":"A titled group of tiles within a dashboard.","required":["id","title","tiles"],"properties":{"id":{"type":"string","description":"Stable client-generated section id."},"tiles":{"type":"array","items":{"$ref":"#/components/schemas/DashboardTile"},"description":"Tiles rendered within this section."},"title":{"type":"string","description":"Section heading."}}},"DashboardTile":{"type":"object","description":"A single metric tile within a dashboard section.","required":["id","metric_name","aggregation"],"properties":{"aggregation":{"type":"string","description":"Aggregation applied per bucket: one of\n`avg|sum|min|max|count|rate|p50|p90|p95|p99`."},"group_by":{"type":"array","items":{"type":"string"},"description":"Label keys to break the metric down by (group-by / multi-series view).\nEmpty = single aggregated series (current behavior). Max 2 keys — more\ndimensions are unreadable in a chart (ADR-026 Phase 2). Each key must\nmatch `[a-zA-Z0-9_.:-]`. Wired directly to `MetricQuery.group_by` by\nthe tile query path (separate frontend task)."},"id":{"type":"string","description":"Stable client-generated tile id (used as a React key / for reordering)."},"label_filters":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"AND-combined label equality filters: `[[\"key\",\"value\"],…]`. Empty = no\nfiltering. Max 10 pairs; keys must match `[a-zA-Z0-9_.:-]`; values\ncapped at 500 characters. Not yet wired into the tile query path\n(Phase 1 ADR-026 — field round-trips and validates; query wiring is\na separate frontend task)."},"metric_name":{"type":"string","description":"The metric name to chart (e.g. `http.server.duration`)."},"title":{"type":["string","null"],"description":"Optional display title; falls back to the metric name in the UI."}}},"DataImplication":{"type":"object","description":"A specific data implication the user needs to understand","required":["severity","message"],"properties":{"message":{"type":"string","description":"Human-readable description of what could happen"},"recommended_action":{"type":["string","null"],"description":"What the user should do about it (if anything)"},"severity":{"$ref":"#/components/schemas/DataImplicationSeverity","description":"Severity of this implication"}}},"DataImplicationSeverity":{"type":"string","description":"Severity of a data implication","enum":["info","warning","data-not-migrated","potential-data-loss"]},"DatabaseMetricsResponse":{"type":"object","description":"Response for the per-database metrics breakdown.","required":["databases"],"properties":{"databases":{"type":"array","items":{"$ref":"#/components/schemas/DatabaseMetricsRow"},"description":"One entry per database, sorted by the first metric descending\n(largest first) so the biggest database leads the table."}}},"DatabaseMetricsRow":{"type":"object","description":"Per-database metric values for a Postgres service.\n\nA Postgres instance can host many databases (some unrelated to this\nservice). The collector records per-`datname` series; this groups the\nlatest value of each requested metric by database so the UI can render a\n\"Databases\" breakdown table instead of one collapsed number.","required":["database","metrics"],"properties":{"database":{"type":"string","description":"Database name (`datname`)."},"metrics":{"type":"object","description":"Latest value of each requested metric for this database\n(e.g. `{\"pg.database_size_bytes\": 7943871, \"pg.cache_hit_ratio\": 0.99}`).","additionalProperties":{"type":"number","format":"double"},"propertyNames":{"type":"string"}}}},"DelRequest":{"type":"object","description":"Request to delete keys","required":["keys"],"properties":{"keys":{"type":"array","items":{"type":"string"},"description":"The key(s) to delete","example":["user:123","user:456"]},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"DelResponse":{"type":"object","description":"Response for delete operation","required":["deleted"],"properties":{"deleted":{"type":"integer","format":"int64","description":"Number of keys deleted","example":2}}},"DeleteBlobRequest":{"type":"object","description":"Request to delete blobs","required":["pathnames"],"properties":{"pathnames":{"type":"array","items":{"type":"string"},"description":"Pathnames to delete (relative to project)","example":["images/avatar.png","documents/file.pdf"]},"projectId":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"DeleteBlobResponse":{"type":"object","description":"Response after deleting blobs","required":["deleted"],"properties":{"deleted":{"type":"integer","format":"int64","description":"Number of blobs deleted","example":2}}},"DeleteResponse":{"type":"object","required":["deleted"],"properties":{"deleted":{"type":"integer","format":"int64","minimum":0}}},"DeployFromImageRequest":{"type":"object","properties":{"external_image_id":{"type":["integer","null"],"format":"int32","description":"External image ID (if already registered). If provided without image_ref,\nthe image reference will be fetched from the registered external image."},"health_check_path":{"type":["string","null"],"description":"Optional HTTP health-check path override (e.g. \"/api/healthz\").\nImage deploys can't read `.temps.yaml`, so this sets the path the deployer\nprobes after the container starts and the path the environment's uptime\nmonitor checks. Must start with '/'. When omitted, defaults to \"/\".","example":"/api/healthz"},"image_ref":{"type":["string","null"],"description":"Docker image reference (e.g., \"ghcr.io/org/app:v1.0\")\nRequired if external_image_id is not provided","example":"ghcr.io/myorg/myapp:v1.0"},"metadata":{"description":"Optional deployment metadata"}}},"DeployFromImageUploadQuery":{"type":"object","description":"Query parameters for deploying from an uploaded image tarball","properties":{"health_check_path":{"type":["string","null"],"description":"Optional HTTP health-check path override (e.g. \"/api/healthz\").\nMust start with '/'. When omitted, defaults to \"/\".","example":"/api/healthz"},"tag":{"type":["string","null"],"description":"Tag to apply to the imported image (e.g., \"myapp:v1.0\")\nIf not provided, a unique tag will be generated","example":"myapp:v1.0"}}},"DeployFromStaticRequest":{"type":"object","required":["static_bundle_id"],"properties":{"health_check_path":{"type":["string","null"],"description":"Optional HTTP health-check path override (e.g. \"/api/healthz\").\nStatic deploys can't read `.temps.yaml`, so this sets the path the deployer\nprobes after the container starts and the path the environment's uptime\nmonitor checks. Must start with '/'. When omitted, defaults to \"/\".","example":"/api/healthz"},"metadata":{"description":"Optional deployment metadata"},"static_bundle_id":{"type":"integer","format":"int32","description":"Static bundle ID (required)"}}},"DeploymentConfig":{"type":"object","description":"Deployment configuration shared between projects and environments\n\nThis configuration can be set at the project level (as defaults) and\noverridden at the environment level for specific deployments.\n\nNote: Environment variables are managed separately and are not part of this config.","properties":{"antiAffinity":{"type":"boolean","description":"Anti-affinity: spread replicas across different nodes.\n\nWhen enabled, the scheduler avoids placing two replicas of the same\nenvironment on the same node. If there are fewer eligible nodes than\nreplicas, remaining replicas wrap around (best-effort spreading).\n\nDefaults to `true` — replicas spread by default."},"automaticDeploy":{"type":["boolean","null"],"description":"Enable automatic deployments on git push.\n`None` = inherit from project config; `Some(true/false)` = explicit override.\nStored as JSONB so absent key → `None` (inherit), never silently defaults to false."},"containerExecEnabled":{"type":"boolean","description":"Enable container exec/shell access (disabled by default for security)"},"cpuLimit":{"type":["integer","null"],"format":"int32","description":"CPU limit in microcores, where 1_000_000 = 1 full CPU core\n(e.g., 2_000_000 = 2 CPUs). NOT millicores. `None` = uncapped."},"cpuRequest":{"type":["integer","null"],"format":"int32","description":"CPU request in microcores, where 1_000_000 = 1 full CPU core\n(e.g., 100_000 = 0.1 CPU, 500_000 = 0.5 CPU, 2_000_000 = 2 CPUs).\nNOT millicores — the deployer formats this as `{n}u` and converts\n`n / 1_000_000` cores into Docker nano_cpus."},"crossArchitectureBuilds":{"type":["boolean","null"],"description":"Build one image per architecture the eligible nodes run.\n\n`None`/`false` (the default) builds exactly once, on the control\nplane's native platform — byte-for-byte the behaviour of a\nsingle-architecture cluster. When enabled and the nodes this\ndeployment could land on span more than one architecture, the build\njob produces one image per architecture; the non-native ones go\nthrough the daemon's `platform` option, which requires QEMU binfmt\nhandlers registered on the control plane.\n\n**Opt-in on purpose.** Cross-architecture builds are emulated and\nsubstantially slower, and deriving them from cluster topology would\nmean a single node joining silently changes build behaviour for every\ndeployment in the cluster. It also keeps the decision on operator\nconfig rather than on a value each node reports about itself.\n\n`Option` so an environment inherits the project's setting\n(`None`) or overrides it, matching `automatic_deploy`."},"exposedPort":{"type":["integer","null"],"format":"int32","description":"Port exposed by the container\nIf not specified, will be auto-detected from Docker image or default to 3000"},"idleTimeoutSeconds":{"type":"integer","format":"int32","description":"Seconds of inactivity before containers are stopped in on-demand mode.\nOnly used when `on_demand` is true. Min: 60, Max: 86400 (24h).\nDefault: 300 (5 minutes)."},"memoryLimit":{"type":["integer","null"],"format":"int32","description":"Memory limit in megabytes. Three-state semantics:\n- `None` → inherit the parent layer (env inherits project, project\n inherits the seeded default); used by the settings UI's \"Use default\".\n- `Some(0)` → explicit **uncapped**: stop inheriting and run with no\n memory limit. This is the deliberate escape hatch for dedicated\n workloads, distinct from `None`.\n- `Some(n)` → hard cap of `n` MB.\n\n`merge`/resolution keep `Some(0)` as a present value (it wins precedence\nover a parent cap), and the deployer collapses it to \"no limit\" before\ntalking to Docker."},"memoryRequest":{"type":["integer","null"],"format":"int32","description":"Memory request in megabytes (e.g., 128 = 128MB)"},"onDemand":{"type":"boolean","description":"Enable on-demand mode (scale-to-zero).\nWhen enabled, containers are stopped after `idle_timeout_seconds` of no traffic\nand automatically started when a new request arrives."},"performanceMetricsEnabled":{"type":"boolean","description":"Enable performance metrics collection (speed insights)"},"replicas":{"type":"integer","format":"int32","description":"Number of replicas/instances to run\nDefaults to 1 replica"},"security":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SecurityConfig","description":"Security configuration (headers, rate limiting, attack mode, etc.)\nThese settings inherit and override from parent level (Environment > Project > Global)"}]},"sessionRecordingEnabled":{"type":"boolean","description":"Enable session recording for analytics"},"targetLabels":{"description":"Label selector for node-based scheduling. Replicas are only deployed to\nnodes whose labels match the selector.\n\nMatching rules:\n- **Same key, array value** → OR: node must match any value\n- **Different keys** → AND: node must satisfy all keys\n\nExample: `{\"region\": [\"us\", \"asia\"], \"gpu\": \"true\"}`\n→ (region=us OR region=asia) AND gpu=true\n\nApplied after `target_nodes` filtering (they stack)."},"targetNodes":{"type":["array","null"],"items":{"type":"integer","format":"int32"},"description":"Optional list of node IDs to deploy to. When set, replicas are distributed\nonly across these nodes (round-robin). When None, the scheduler distributes\nacross all active nodes (or deploys locally if no nodes exist)."},"wakeTimeoutSeconds":{"type":"integer","format":"int32","description":"Max seconds to wait for containers to start when waking from on-demand sleep.\nRequests return 503 if exceeded. Default: 30."}}},"DeploymentConfigSnapshot":{"type":"object","description":"Deployment configuration snapshot for deployments\n\nThis extends DeploymentConfig with environment variables to capture\nthe complete state of a deployment at the time it was created.","properties":{"automaticDeploy":{"type":"boolean","description":"Enable automatic deployments on git push"},"containerExecEnabled":{"type":"boolean","description":"Enable container exec/shell access"},"cpuLimit":{"type":["integer","null"],"format":"int32","description":"CPU limit in millicores"},"cpuRequest":{"type":["integer","null"],"format":"int32","description":"CPU request in millicores"},"environmentVariables":{"type":"object","description":"Environment variables used for this deployment","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"exposedPort":{"type":["integer","null"],"format":"int32","description":"Port exposed by the container"},"memoryLimit":{"type":["integer","null"],"format":"int32","description":"Memory limit in megabytes"},"memoryRequest":{"type":["integer","null"],"format":"int32","description":"Memory request in megabytes"},"performanceMetricsEnabled":{"type":"boolean","description":"Enable performance metrics collection"},"replicas":{"type":"integer","format":"int32","description":"Number of replicas"},"sessionRecordingEnabled":{"type":"boolean","description":"Enable session recording"}}},"DeploymentConfiguration":{"type":"object","description":"Deployment-level configuration","required":["image","strategy","env_vars","ports","volumes","network","resources"],"properties":{"build":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/BuildConfiguration","description":"Build configuration (if building from source)"}]},"command":{"type":["array","null"],"items":{"type":"string"},"description":"Command override"},"entrypoint":{"type":["array","null"],"items":{"type":"string"},"description":"Entrypoint override"},"env_vars":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentVariable"},"description":"Environment variables"},"git":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/GitSourcePlan","description":"Where the application's source code lives, when the source platform\nbuilds from a git repository. Execution uses this to link the temps\nproject to the same repository so the real deployment pipeline can\nclone and build it."}]},"health_check":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/HealthCheckConfiguration","description":"Health check configuration"}]},"image":{"type":"string","description":"Image to deploy"},"network":{"$ref":"#/components/schemas/NetworkConfiguration","description":"Network configuration"},"ports":{"type":"array","items":{"$ref":"#/components/schemas/PortMapping"},"description":"Port mappings"},"resources":{"$ref":"#/components/schemas/ResourceLimits","description":"Resource limits"},"strategy":{"$ref":"#/components/schemas/DeploymentStrategy","description":"Deployment strategy"},"volumes":{"type":"array","items":{"$ref":"#/components/schemas/VolumeMount"},"description":"Volume mounts"},"working_dir":{"type":["string","null"],"description":"Working directory"}}},"DeploymentContainerLogContentResponse":{"type":"object","description":"A single captured container-log dump, including its full text content.","required":["id","container_name","size_bytes","truncated","captured_at","content"],"properties":{"captured_at":{"type":"integer","format":"int64"},"container_name":{"type":"string"},"content":{"type":"string","description":"The captured plain-text log content."},"id":{"type":"integer","format":"int32"},"service_name":{"type":["string","null"]},"size_bytes":{"type":"integer","format":"int64"},"truncated":{"type":"boolean"}}},"DeploymentContainerLogResponse":{"type":"object","description":"Metadata for one captured (historical) container-log dump. Listed on the\ndeployment detail page so a user can pick which past container's logs to read.","required":["id","deployment_id","container_id","container_name","size_bytes","truncated","captured_at"],"properties":{"captured_at":{"type":"integer","format":"int64","description":"Unix epoch milliseconds of when the logs were captured (just before\nteardown). Matches the timestamp convention used by `DeploymentResponse`."},"container_id":{"type":"string"},"container_name":{"type":"string"},"deployment_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"node_id":{"type":["integer","null"],"format":"int32"},"service_name":{"type":["string","null"]},"size_bytes":{"type":"integer","format":"int64"},"truncated":{"type":"boolean"}}},"DeploymentContainerLogsListResponse":{"type":"object","description":"The list of captured container-log dumps for a deployment.","required":["logs"],"properties":{"logs":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentContainerLogResponse"}}}},"DeploymentEnvironmentResponse":{"type":"object","required":["id","name","slug","domains"],"properties":{"domains":{"type":"array","items":{"type":"string"}},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"slug":{"type":"string"}}},"DeploymentJobResponse":{"type":"object","required":["id","deployment_id","job_id","job_type","name","status","created_at","updated_at","log_id"],"properties":{"created_at":{"type":"integer","format":"int64"},"dependencies":{},"deployment_id":{"type":"integer","format":"int32"},"description":{"type":["string","null"]},"error_message":{"type":["string","null"]},"execution_order":{"type":["integer","null"],"format":"int32"},"finished_at":{"type":["integer","null"],"format":"int64"},"id":{"type":"integer","format":"int32"},"job_config":{"description":"Internal workflow configuration is intentionally redacted. It can\ncontain legacy plaintext secrets or encrypted secret envelopes."},"job_id":{"type":"string"},"job_type":{"type":"string"},"log_id":{"type":"string"},"name":{"type":"string"},"outputs":{},"started_at":{"type":["integer","null"],"format":"int64"},"status":{"type":"string"},"updated_at":{"type":"integer","format":"int64"}}},"DeploymentJobsResponse":{"type":"object","required":["jobs","total"],"properties":{"jobs":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentJobResponse"}},"total":{"type":"integer","minimum":0}}},"DeploymentListResponse":{"type":"object","required":["deployments","total","page","per_page"],"properties":{"deployments":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentResponse"}},"page":{"type":"integer","format":"int64"},"per_page":{"type":"integer","format":"int64"},"total":{"type":"integer","format":"int64"}}},"DeploymentMetadata":{"type":"object","description":"Deployment metadata - typed information about the deployment","properties":{"buildDurationMs":{"type":["integer","null"],"format":"int64","description":"Build duration in milliseconds"},"builder":{"type":["string","null"],"description":"Docker builder used (e.g., \"nixpacks\", \"dockerfile\")"},"deploymentDurationMs":{"type":["integer","null"],"format":"int64","description":"Deployment duration in milliseconds"},"deploymentSourceType":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SourceType","description":"Source type for THIS specific deployment (for Manual/flexible projects)\nThis allows Manual projects to have deployments via different methods\n(docker_image, static_files, or git) while keeping per-deployment tracking"}]},"dockerfilePath":{"type":["string","null"],"description":"Dockerfile path if using Dockerfile builder"},"externalImageId":{"type":["integer","null"],"format":"int32","description":"External image ID (reference to external_images table)"},"externalImageRef":{"type":["string","null"],"description":"External Docker image reference (for docker_image source type)\ne.g., \"ghcr.io/org/app:v1.0\" or \"docker.io/myapp:sha-abc123\""},"fileCount":{"type":["integer","null"],"format":"int32","description":"Number of files in the build output"},"gitPushEvent":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/GitPushEvent","description":"Git push event that triggered this deployment (if from webhook)"}]},"healthCheckPath":{"type":["string","null"],"description":"Explicit deploy-time HTTP health-check path override.\nImage/static deploys can't read `.temps.yaml`, so this lets the deploy\nrequest set a custom path (e.g. \"/api/healthz\"). When present it takes\npriority over any `.temps.yaml` `health.path` value. Always starts with '/'."},"imageSizeBytes":{"type":["integer","null"],"format":"int64","description":"Total size of the built image in bytes"},"imageUploadedLocally":{"type":"boolean","description":"Whether the image was uploaded directly (via docker save/load) rather than pulled from registry\nWhen true, the PullExternalImageJob is skipped since the image is already loaded locally"},"isRollback":{"type":"boolean","description":"Whether this is a rollback deployment"},"labels":{"type":"array","items":{"type":"string"},"description":"Custom labels/tags for the deployment"},"rolledBackFromId":{"type":["integer","null"],"format":"int32","description":"ID of the deployment this was rolled back from (if applicable)"},"sourceBundleContentType":{"type":["string","null"],"description":"Uploaded source archive content type."},"sourceBundleId":{"type":["integer","null"],"format":"int32","description":"Uploaded source archive ID. Source archives are extracted before the\nregular preset build pipeline and do not require Git metadata."},"sourceBundlePath":{"type":["string","null"],"description":"Uploaded source archive path in the Temps data directory."},"staticBundleContentType":{"type":["string","null"],"description":"Static bundle content type (for proper extraction: application/gzip or application/zip)"},"staticBundleId":{"type":["integer","null"],"format":"int32","description":"Static bundle ID (reference to static_bundles table, for static_files source type)"},"staticBundlePath":{"type":["string","null"],"description":"Static bundle path in blob storage (for static_files source type)"},"uploadedImageId":{"type":["string","null"],"description":"Docker image ID of the locally uploaded image (sha256:...)\nUsed to verify the image exists before deployment"}}},"DeploymentResponse":{"type":"object","required":["id","project_id","environment_id","environment","status","url","created_at","is_current"],"properties":{"branch":{"type":["string","null"]},"cancelled_reason":{"type":["string","null"]},"commit_author":{"type":["string","null"]},"commit_date":{"type":["integer","null"],"format":"int64"},"commit_hash":{"type":["string","null"]},"commit_message":{"type":["string","null"]},"created_at":{"type":"integer","format":"int64"},"deployment_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DeploymentConfigSnapshot","description":"Deployment configuration snapshot (CPU, memory, replicas, environment variables, etc.)"}]},"environment":{"$ref":"#/components/schemas/DeploymentEnvironmentResponse"},"environment_id":{"type":"integer","format":"int32"},"finished_at":{"type":["integer","null"],"format":"int64"},"id":{"type":"integer","format":"int32"},"is_current":{"type":"boolean"},"metadata":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DeploymentMetadata","description":"Deployment metadata (build info, git event, etc.)"}]},"project_id":{"type":"integer","format":"int32"},"screenshot_location":{"type":["string","null"]},"started_at":{"type":["integer","null"],"format":"int64"},"status":{"type":"string"},"tag":{"type":["string","null"]},"url":{"type":"string"}}},"DeploymentStateResponse":{"type":"object","required":["id","state","message"],"properties":{"id":{"type":"integer","format":"int32"},"message":{"type":"string"},"state":{"type":"string"}}},"DeploymentStrategy":{"type":"string","description":"Deployment strategy","enum":["replace","blue-green","rolling"]},"DeploymentTokenListResponse":{"type":"object","required":["tokens","total"],"properties":{"tokens":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentTokenResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"DeploymentTokenResponse":{"type":"object","required":["id","project_id","name","token_prefix","is_active","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00Z"},"created_by":{"type":["integer","null"],"format":"int32"},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"last_used_at":{"type":["string","null"],"format":"date-time","example":"2024-01-01T00:00:00Z"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"}},"project_id":{"type":"integer","format":"int32"},"token_prefix":{"type":"string"}}},"DetectionConfig":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/StaticParams","description":"v0 (shipping): static threshold comparison of the aggregated value."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["static"]}}}],"description":"v0 (shipping): static threshold comparison of the aggregated value."},{"allOf":[{"$ref":"#/components/schemas/AnomalyParams","description":"Seasonal anomaly band (basic/agile/robust/ewma share this variant — the\nalgorithm is a field, not a new kind). Creation rejected until evaluated."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["anomaly"]}}}],"description":"Seasonal anomaly band (basic/agile/robust/ewma share this variant — the\nalgorithm is a field, not a new kind). Creation rejected until evaluated."},{"allOf":[{"$ref":"#/components/schemas/ForecastParams","description":"Predict a future threshold breach (capacity planning). Stub."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["forecast"]}}}],"description":"Predict a future threshold breach (capacity planning). Stub."},{"allOf":[{"$ref":"#/components/schemas/OutlierParams","description":"Cross-series population outlier (one host misbehaving vs its peers). Stub."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["outlier"]}}}],"description":"Cross-series population outlier (one host misbehaving vs its peers). Stub."},{"allOf":[{"$ref":"#/components/schemas/AutoWatchParams","description":"Watchdog-style self-tuning auto-watch (engine picks bounds). Stub."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["auto_watch"]}}}],"description":"Watchdog-style self-tuning auto-watch (engine picks bounds). Stub."}],"description":"The typed detector definition stored (as jsonb) in\n`metric_alert_rules.detection_config`.\n\nToday only [`DetectionConfig::Static`] is evaluable; the other variants are\nschema-present (so the SDK/UI and storage are already future-shaped) but\nrejected by [`DetectionConfig::validate`] until their evaluator lands. Each is\nthen enabled code-only, with no schema migration."},"DeviceCount":{"type":"object","required":["device_type","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"device_type":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"DigestSections":{"type":"object","description":"Sections that can be included in the weekly digest\nNote: `#[serde(default)]` allows backward compatibility when deserializing\nold data that may have `security` and `resources` fields instead of `projects`","properties":{"deployments":{"type":"boolean","default":true},"errors":{"type":"boolean","default":true},"funnels":{"type":"boolean","default":true},"performance":{"type":"boolean","default":true},"projects":{"type":"boolean","default":true}}},"Direction":{"type":"string","description":"Which side(s) of an anomaly band count as a deviation.","enum":["both","above","below"]},"DisableBlobResponse":{"type":"object","description":"Response after disabling Blob service","required":["success","message"],"properties":{"message":{"type":"string","description":"Human-readable message","example":"Blob service disabled successfully"},"success":{"type":"boolean","description":"Whether the operation succeeded","example":true}}},"DisableKvResponse":{"type":"object","description":"Response after disabling KV service","required":["success","message"],"properties":{"message":{"type":"string","description":"Status message","example":"KV service disabled successfully"},"success":{"type":"boolean","description":"Whether the service was successfully disabled"}}},"DisableMfaRequest":{"type":"object","required":["code"],"properties":{"code":{"type":"string"}}},"DiscoverRequest":{"type":"object","description":"Request to discover workloads","required":["source"],"properties":{"credentials":{"$ref":"#/components/schemas/ImportCredentials","description":"Platform credentials (required for cloud platforms like Vercel, Railway)"},"selector":{"$ref":"#/components/schemas/ImportSelector","description":"Optional selector to filter workloads"},"source":{"$ref":"#/components/schemas/ImportSource","description":"Source to discover from"}}},"DiscoverResponse":{"type":"object","description":"Response with discovered workloads","required":["workloads"],"properties":{"workloads":{"type":"array","items":{"$ref":"#/components/schemas/WorkloadDescriptor"},"description":"Discovered workloads"}}},"DiskInfo":{"type":"object","description":"Disk space information for a single disk/partition","required":["mount_point","total_bytes","used_bytes","available_bytes","usage_percent","file_system"],"properties":{"available_bytes":{"type":"integer","format":"int64","description":"Available space in bytes","minimum":0},"file_system":{"type":"string","description":"File system type (e.g., \"ext4\", \"apfs\")"},"mount_point":{"type":"string","description":"Mount point of the disk"},"total_bytes":{"type":"integer","format":"int64","description":"Total space in bytes","minimum":0},"usage_percent":{"type":"number","format":"double","description":"Usage percentage (0-100)"},"used_bytes":{"type":"integer","format":"int64","description":"Used space in bytes","minimum":0}}},"DiskSpaceAlert":{"type":"object","description":"Alert for a disk that exceeds the threshold","required":["mount_point","usage_percent","threshold_percent","available_bytes","available_human"],"properties":{"available_bytes":{"type":"integer","format":"int64","description":"Available space in bytes","minimum":0},"available_human":{"type":"string","description":"Human-readable available space"},"mount_point":{"type":"string","description":"Mount point of the disk"},"threshold_percent":{"type":"integer","format":"int32","description":"Configured threshold percentage","minimum":0},"usage_percent":{"type":"number","format":"double","description":"Current usage percentage"}}},"DiskSpaceAlertSettings":{"type":"object","description":"Disk space alert settings for monitoring disk usage","properties":{"check_interval_seconds":{"type":"integer","format":"int64","description":"Interval in seconds between disk space checks","default":300,"example":300,"minimum":60},"enabled":{"type":"boolean","description":"Whether disk space alerts are enabled","default":true},"monitor_path":{"type":["string","null"],"description":"Restrict monitoring to the disk backing this path. When unset (the\ndefault), every mounted writable volume is monitored — including\ndedicated volumes such as `/var/lib/docker`.","default":null},"threshold_percent":{"type":"integer","format":"int32","description":"Threshold percentage (0-100) at which to trigger alerts","default":80,"example":80,"maximum":100,"minimum":0}}},"DiskSpaceCheckResult":{"type":"object","description":"Result of a disk space check","required":["checked_at","enabled","threshold_percent","disks","alerts"],"properties":{"alerts":{"type":"array","items":{"$ref":"#/components/schemas/DiskSpaceAlert"},"description":"Disks that meet or exceed the threshold"},"checked_at":{"type":"string","format":"date-time","description":"Timestamp of the check (ISO 8601, UTC)","example":"2026-05-28T12:15:47.609192Z"},"disks":{"type":"array","items":{"$ref":"#/components/schemas/DiskInfo"},"description":"List of all monitored disks"},"enabled":{"type":"boolean","description":"Whether disk space monitoring is enabled in settings"},"threshold_percent":{"type":"integer","format":"int32","description":"Configured alert threshold percentage (0-100)","minimum":0}}},"DnsAckRequest":{"type":"object","required":["applied_generation"],"properties":{"applied_generation":{"type":"integer","format":"int64","description":"Highest generation the agent has actually applied locally."}}},"DnsAckResponse":{"type":"object","required":["node_id","applied_generation","server_generation"],"properties":{"applied_generation":{"type":"integer","format":"int64"},"node_id":{"type":"integer","format":"int32"},"server_generation":{"type":"integer","format":"int64"}}},"DnsChallengeRecordResult":{"type":"object","description":"Result of a single DNS TXT record creation for ACME challenge","required":["name","value","success","message"],"properties":{"message":{"type":"string","description":"Human-readable message about the operation"},"name":{"type":"string","description":"TXT record name (e.g., \"_acme-challenge.example.com\")","example":"_acme-challenge.example.com"},"success":{"type":"boolean","description":"Whether the record was created successfully"},"value":{"type":"string","description":"TXT record value (the ACME challenge token)","example":"abc123..."}}},"DnsChangesResponse":{"type":"object","required":["generation","full_snapshot","records","removed_ids"],"properties":{"full_snapshot":{"type":"boolean","description":"`true` ⇒ replace the local zone with `records`. `false` ⇒ merge\n`records` into the existing zone (and remove `removed_ids`)."},"generation":{"type":"integer","format":"int64","description":"Highest generation included in this response. Agent ACKs this back."},"records":{"type":"array","items":{"$ref":"#/components/schemas/EndpointDto"}},"removed_ids":{"type":"array","items":{"type":"integer","format":"int64"},"description":"IDs the agent should remove from its zone. Always empty in the v1\nprotocol — the resolver reconciles by name on snapshot mode. Kept\nin the wire format so a future tombstone-based protocol doesn't\nrequire a breaking change."}}},"DnsCompletionResponse":{"type":"object","required":["domain","status"],"properties":{"domain":{"type":"string"},"status":{"type":"string"}}},"DnsLookupError":{"type":"object","description":"Error response for DNS lookup failures","required":["error","domain"],"properties":{"domain":{"type":"string","description":"Domain name that failed","example":"nonexistent.com"},"error":{"type":"string","description":"Error message","example":"DNS lookup failed: domain not found"}}},"DnsLookupRequest":{"type":"object","description":"Request to lookup DNS A records for a domain","required":["domain"],"properties":{"domain":{"type":"string","description":"Domain name to lookup","example":"example.com"}}},"DnsLookupResponse":{"type":"object","description":"Response containing DNS A records","required":["domain","records","count","dns_servers"],"properties":{"count":{"type":"integer","description":"Number of records found","example":1,"minimum":0},"dns_servers":{"type":"array","items":{"type":"string"},"description":"DNS servers used for the lookup","example":["8.8.8.8","8.8.4.4"]},"domain":{"type":"string","description":"Domain name that was queried","example":"example.com"},"records":{"type":"array","items":{"type":"string"},"description":"List of A record IP addresses","example":["93.184.216.34"]}}},"DnsProviderCredentials":{"oneOf":[{"type":"object","required":["api_token","type"],"properties":{"account_id":{"type":["string","null"]},"api_token":{"type":"string","example":"your-api-token"},"type":{"type":"string","enum":["cloudflare"]}}},{"type":"object","required":["api_user","api_key","type"],"properties":{"api_key":{"type":"string","example":"your-api-key"},"api_user":{"type":"string","example":"your-username"},"client_ip":{"type":["string","null"]},"sandbox":{"type":"boolean"},"type":{"type":"string","enum":["namecheap"]}}},{"type":"object","required":["access_key_id","secret_access_key","type"],"properties":{"access_key_id":{"type":"string","example":"AKIAIOSFODNN7EXAMPLE"},"region":{"type":["string","null"],"example":"us-east-1"},"secret_access_key":{"type":"string","example":"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"},"session_token":{"type":["string","null"]},"type":{"type":"string","enum":["route53"]}}},{"type":"object","required":["api_token","type"],"properties":{"api_token":{"type":"string","example":"dop_v1_your-token"},"type":{"type":"string","enum":["digitalocean"]}}},{"type":"object","required":["service_account_email","private_key","project_id","type"],"properties":{"private_key":{"type":"string","example":"-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"},"project_id":{"type":"string","example":"my-gcp-project"},"service_account_email":{"type":"string","example":"dns-admin@myproject.iam.gserviceaccount.com"},"type":{"type":"string","enum":["gcp"]}}},{"type":"object","required":["tenant_id","client_id","client_secret","subscription_id","resource_group","type"],"properties":{"client_id":{"type":"string","example":"00000000-0000-0000-0000-000000000000"},"client_secret":{"type":"string"},"resource_group":{"type":"string","example":"my-resource-group"},"subscription_id":{"type":"string","example":"00000000-0000-0000-0000-000000000000"},"tenant_id":{"type":"string","example":"00000000-0000-0000-0000-000000000000"},"type":{"type":"string","enum":["azure"]}}},{"type":"object","description":"Pebble challtestsrv mock DNS (LOCAL DEV/TEST ONLY)","required":["management_url","type"],"properties":{"management_url":{"type":"string","example":"http://localhost:8055"},"type":{"type":"string","enum":["pebble"]}}}],"description":"DNS provider credentials (API-facing)"},"DnsProviderResponse":{"type":"object","description":"DNS provider response","required":["id","name","provider_type","credentials","is_active","flat_hostnames_supported","created_at","updated_at"],"properties":{"created_at":{"type":"string"},"credentials":{"description":"Masked credentials for display"},"description":{"type":["string","null"]},"flat_hostnames_supported":{"type":"boolean","description":"Whether this provider benefits from the flat hostname mode (e.g. Cloudflare\nUniversal SSL). The UI surfaces/recommends the Flat toggle when true."},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"last_error":{"type":["string","null"]},"last_used_at":{"type":["string","null"]},"name":{"type":"string"},"provider_type":{"type":"string"},"updated_at":{"type":"string"}}},"DnsProviderSettings":{"type":"object","properties":{"cloudflare_api_key":{"type":["string","null"],"default":null},"provider":{"type":"string","default":"manual"}}},"DnsProviderSettingsMasked":{"type":"object","description":"DNS provider settings with masked sensitive fields","required":["provider"],"properties":{"cloudflare_api_key":{"type":["string","null"]},"provider":{"type":"string"}}},"DnsProviderType":{"type":"string","description":"Supported DNS provider types","enum":["cloudflare","namecheap","route53","digitalocean","gcp","azure","manual","pebble"]},"DnsRecord":{"type":"object","description":"A DNS record","required":["zone","name","fqdn","content","ttl"],"properties":{"content":{"$ref":"#/components/schemas/DnsRecordContent","description":"Record content"},"fqdn":{"type":"string","description":"Fully qualified domain name","example":"www.example.com"},"id":{"type":["string","null"],"description":"Provider-specific record ID (if exists)","example":"abc123"},"metadata":{"type":"object","description":"Provider-specific metadata","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":"string","description":"Record name (without zone, e.g., \"www\" or \"@\" for root)","example":"www"},"proxied":{"type":"boolean","description":"Whether this record is proxied (Cloudflare-specific)"},"ttl":{"type":"integer","format":"int32","description":"Time to live in seconds","example":300,"minimum":0},"zone":{"type":"string","description":"Zone/domain this record belongs to","example":"example.com"}}},"DnsRecordChange":{"type":"object","description":"A single DNS record change the Cloudflare sync would make.","required":["action","name","record_type","value"],"properties":{"action":{"type":"string","description":"`\"create\"`, `\"update\"`, or `\"delete\"`."},"name":{"type":"string"},"record_type":{"type":"string","description":"Record type, e.g. `\"A\"` or `\"CNAME\"`."},"value":{"type":"string"}}},"DnsRecordContent":{"oneOf":[{"type":"object","description":"A record - IPv4 address (as string, e.g., \"192.0.2.1\")","required":["value","type"],"properties":{"type":{"type":"string","enum":["A"]},"value":{"type":"object","description":"A record - IPv4 address (as string, e.g., \"192.0.2.1\")","required":["address"],"properties":{"address":{"type":"string","example":"192.0.2.1"}}}}},{"type":"object","description":"AAAA record - IPv6 address (as string, e.g., \"2001:db8::1\")","required":["value","type"],"properties":{"type":{"type":"string","enum":["AAAA"]},"value":{"type":"object","description":"AAAA record - IPv6 address (as string, e.g., \"2001:db8::1\")","required":["address"],"properties":{"address":{"type":"string","example":"2001:db8::1"}}}}},{"type":"object","description":"CNAME record - canonical name","required":["value","type"],"properties":{"type":{"type":"string","enum":["CNAME"]},"value":{"type":"object","description":"CNAME record - canonical name","required":["target"],"properties":{"target":{"type":"string"}}}}},{"type":"object","description":"TXT record - text content","required":["value","type"],"properties":{"type":{"type":"string","enum":["TXT"]},"value":{"type":"object","description":"TXT record - text content","required":["content"],"properties":{"content":{"type":"string"}}}}},{"type":"object","description":"MX record - mail exchange","required":["value","type"],"properties":{"type":{"type":"string","enum":["MX"]},"value":{"type":"object","description":"MX record - mail exchange","required":["priority","target"],"properties":{"priority":{"type":"integer","format":"int32","minimum":0},"target":{"type":"string"}}}}},{"type":"object","description":"NS record - nameserver","required":["value","type"],"properties":{"type":{"type":"string","enum":["NS"]},"value":{"type":"object","description":"NS record - nameserver","required":["nameserver"],"properties":{"nameserver":{"type":"string"}}}}},{"type":"object","description":"SRV record - service","required":["value","type"],"properties":{"type":{"type":"string","enum":["SRV"]},"value":{"type":"object","description":"SRV record - service","required":["priority","weight","port","target"],"properties":{"port":{"type":"integer","format":"int32","minimum":0},"priority":{"type":"integer","format":"int32","minimum":0},"target":{"type":"string"},"weight":{"type":"integer","format":"int32","minimum":0}}}}},{"type":"object","description":"CAA record - certification authority authorization","required":["value","type"],"properties":{"type":{"type":"string","enum":["CAA"]},"value":{"type":"object","description":"CAA record - certification authority authorization","required":["flags","tag","value"],"properties":{"flags":{"type":"integer","format":"int32","minimum":0},"tag":{"type":"string"},"value":{"type":"string"}}}}},{"type":"object","description":"PTR record - pointer","required":["value","type"],"properties":{"type":{"type":"string","enum":["PTR"]},"value":{"type":"object","description":"PTR record - pointer","required":["target"],"properties":{"target":{"type":"string"}}}}}],"description":"DNS record content - varies by record type"},"DnsRecordResponse":{"type":"object","required":["record_type","name","value","status"],"properties":{"name":{"type":"string","description":"DNS record name (host)","example":"temps._domainkey.example.com"},"priority":{"type":["integer","null"],"format":"int32","description":"Priority (for MX records)","example":"10","minimum":0},"record_type":{"type":"string","description":"Record type: TXT, CNAME, MX","example":"TXT"},"status":{"$ref":"#/components/schemas/DnsRecordStatusResponse","description":"Verification status: unknown, verified, pending, failed"},"value":{"type":"string","description":"DNS record value","example":"v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3..."}}},"DnsRecordSetupResult":{"type":"object","description":"Result of a single DNS record creation","required":["record_type","name","success","automatic","message"],"properties":{"automatic":{"type":"boolean","description":"Whether the operation was automatic or manual"},"message":{"type":"string","description":"Human-readable message"},"name":{"type":"string","description":"Record name"},"record_type":{"type":"string","description":"Record type (TXT, CNAME, MX)"},"success":{"type":"boolean","description":"Whether the record was created successfully"}}},"DnsRecordStatusResponse":{"type":"string","description":"DNS record verification status","enum":["unknown","verified","pending","failed"]},"DnsZone":{"type":"object","description":"A DNS zone (domain managed by the provider)","required":["id","name","status","nameservers"],"properties":{"id":{"type":"string","description":"Provider-specific zone ID","example":"zone123"},"metadata":{"type":"object","description":"Provider-specific metadata","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":"string","description":"Zone name (domain)","example":"example.com"},"nameservers":{"type":"array","items":{"type":"string"},"description":"Nameservers for this zone"},"status":{"type":"string","description":"Zone status","example":"active"}}},"DockerComposePresetConfig":{"type":"object","description":"Configuration for Docker Compose deployments.","properties":{"composeOverride":{"type":["string","null"],"description":"User-provided docker-compose.override.yml content."},"composePath":{"type":["string","null"],"description":"Path to the Compose file relative to the project directory."},"publicPorts":{"type":"array","items":{"$ref":"#/components/schemas/ComposePublicPort"},"description":"Compose service ports that should be publicly routed."}}},"DockerRegistrySettings":{"type":"object","properties":{"ca_certificate":{"type":["string","null"],"default":null},"enabled":{"type":"boolean","default":false},"password":{"type":["string","null"],"default":null},"registry_url":{"type":["string","null"],"default":null},"tls_verify":{"type":"boolean","default":true},"username":{"type":["string","null"],"default":null}}},"DockerRegistrySettingsMasked":{"type":"object","description":"Docker registry settings with masked sensitive fields","required":["enabled","tls_verify"],"properties":{"ca_certificate":{"type":["string","null"]},"enabled":{"type":"boolean"},"password":{"type":["string","null"]},"registry_url":{"type":["string","null"]},"tls_verify":{"type":"boolean"},"username":{"type":["string","null"]}}},"DockerfilePresetConfig":{"type":"object","description":"Configuration for Dockerfile preset\nAllows customizing the Dockerfile path and build context for Docker-based deployments","properties":{"buildContext":{"type":["string","null"],"description":"Custom build context path (relative to repository root)\nIf not specified, uses the project's directory setting","example":"./api"},"dockerfilePath":{"type":["string","null"],"description":"Custom Dockerfile path (relative to build context)\nIf not specified, defaults to \"Dockerfile\" in the build context","example":"docker/Dockerfile"},"variant":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DockerfileVariant","description":"Catalog variant. Normally omitted; `custom` selects the generated\nDockerfile compatibility preset."}]}}},"DockerfileVariant":{"type":"string","description":"Catalog variant persisted under the canonical Dockerfile preset.\n\nExisting rows predate this discriminator and therefore deserialize as\n[`DockerfileVariant::File`].","enum":["file","custom"]},"DomainAction":{"type":"string","description":"What to do with a domain during migration","enum":["import","skip"]},"DomainChallengeResponse":{"type":"object","required":["domain","txt_records","status"],"properties":{"domain":{"type":"string"},"status":{"type":"string"},"txt_records":{"type":"array","items":{"$ref":"#/components/schemas/TxtRecord"},"description":"Array of TXT records to add to DNS. For wildcards, multiple records are required."}}},"DomainEnvironmentResponse":{"type":"object","required":["id","name","slug"],"properties":{"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"slug":{"type":"string"}}},"DomainError":{"type":"object","required":["message","code"],"properties":{"code":{"type":"string"},"details":{"type":["string","null"]},"message":{"type":"string"}}},"DomainPlan":{"type":"object","description":"Plan for migrating a single custom domain","required":["domain","environment","action","action_description"],"properties":{"action":{"$ref":"#/components/schemas/DomainAction","description":"What to do with this domain"},"action_description":{"type":"string","description":"Human-readable explanation"},"domain":{"type":"string","description":"Full domain name"},"environment":{"type":"string","description":"Which environment to associate with (\"production\")"},"redirect_to":{"type":["string","null"],"description":"Redirect target (if this is a redirect domain)"},"replacement":{"type":["string","null"],"description":"The temps-side address that replaces this domain when it is skipped.\n\nSource-generated domains (sslip.io / traefik.me / platform subdomains)\nembed the source server's IP and would keep pointing at the old\nmachine — this tells the user where the app will be reachable on\ntemps instead."},"status_code":{"type":["integer","null"],"format":"int32","description":"Redirect status code"}}},"DomainResponse":{"type":"object","required":["id","domain","status","is_wildcard","verification_method","created_at","updated_at"],"properties":{"certificate":{"type":["string","null"],"description":"The PEM-encoded certificate chain (can be displayed in browser or downloaded)"},"created_at":{"type":"integer","format":"int64"},"dns_challenge_token":{"type":["string","null"]},"dns_challenge_value":{"type":["string","null"]},"domain":{"type":"string"},"expiration_time":{"type":["integer","null"],"format":"int64"},"id":{"type":"integer","format":"int32"},"is_wildcard":{"type":"boolean"},"last_error":{"type":["string","null"]},"last_error_type":{"type":["string","null"]},"last_renewed":{"type":["integer","null"],"format":"int64"},"on_demand_backoff_until":{"type":["integer","null"],"format":"int64","description":"On-demand TLS negative-cache deadline (epoch millis), when this hostname's\non-demand HTTP-01 issuance is in backoff after a failure (ADR-018 §4).\n`None` means no active backoff."},"status":{"type":"string"},"updated_at":{"type":"integer","format":"int64"},"verification_method":{"type":"string"}}},"DrainNodeResponse":{"type":"object","required":["id","name","status","affected_environments","message"],"properties":{"affected_environments":{"type":"integer","minimum":0},"id":{"type":"integer","format":"int32"},"message":{"type":"string"},"name":{"type":"string"},"status":{"type":"string"}}},"DrainStatusResponse":{"type":"object","description":"Progress of a node drain operation.","required":["node_id","node_name","status","remaining_containers","drain_complete","can_remove","message"],"properties":{"can_remove":{"type":"boolean","description":"Can the node be safely removed?"},"drain_complete":{"type":"boolean","description":"Whether the drain is complete (all containers migrated)"},"message":{"type":"string"},"node_id":{"type":"integer","format":"int32"},"node_name":{"type":"string"},"remaining_containers":{"type":"integer","description":"Number of containers still on this node","minimum":0},"status":{"type":"string"}}},"DropArchiveUpload":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary"}}},"DropInspectionResponse":{"type":"object","required":["suggestedName","candidates"],"properties":{"candidates":{"type":"array","items":{"$ref":"#/components/schemas/DropPresetCandidate"}},"suggestedName":{"type":"string"}}},"DropOffPoint":{"type":"object","description":"Drop-off point: pages where visitors leave the site","required":["page_path","exit_count","total_views","exit_rate"],"properties":{"exit_count":{"type":"integer","format":"int64","description":"Number of exits from this page"},"exit_rate":{"type":"number","format":"double","description":"Exit rate for this page (exit_count / total_views)"},"page_path":{"type":"string","description":"The page path where visitors drop off"},"total_views":{"type":"integer","format":"int64","description":"Total views of this page"}}},"DropPresetCandidate":{"type":"object","required":["directory","preset","label","confidence","reason","isStatic"],"properties":{"confidence":{"type":"string"},"directory":{"type":"string"},"isStatic":{"type":"boolean"},"label":{"type":"string"},"preset":{"type":"string"},"reason":{"type":"string"}}},"EmailConfig":{"type":"object","required":["smtp_host","smtp_port","username","password","from_address","to_addresses"],"properties":{"accept_invalid_certs":{"type":"boolean"},"from_address":{"type":"string"},"from_name":{"type":["string","null"]},"password":{"type":"string"},"smtp_host":{"type":"string"},"smtp_port":{"type":"integer","format":"int32","minimum":0},"starttls_required":{"type":"boolean"},"tls_mode":{"$ref":"#/components/schemas/TlsMode"},"to_addresses":{"type":"array","items":{"type":"string"}},"username":{"type":"string"}}},"EmailDomainResponse":{"type":"object","required":["id","provider_id","domain","status","created_at","updated_at"],"properties":{"created_at":{"type":"string","example":"2025-12-03T10:30:00Z"},"domain":{"type":"string","example":"updates.example.com"},"id":{"type":"integer","format":"int32"},"last_verified_at":{"type":["string","null"]},"provider_id":{"type":"integer","format":"int32"},"status":{"type":"string","example":"verified"},"updated_at":{"type":"string","example":"2025-12-03T10:30:00Z"},"verification_error":{"type":["string","null"]}}},"EmailDomainWithDnsResponse":{"type":"object","required":["domain","dns_records"],"properties":{"dns_records":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecordResponse"}},"domain":{"$ref":"#/components/schemas/EmailDomainResponse"}}},"EmailProviderResponse":{"type":"object","required":["id","name","provider_type","region","is_active","credentials","created_at","updated_at"],"properties":{"created_at":{"type":"string","example":"2025-12-03T10:30:00Z"},"credentials":{"description":"Masked credentials for display"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"name":{"type":"string","example":"My AWS SES"},"provider_type":{"$ref":"#/components/schemas/EmailProviderTypeRoute"},"region":{"type":"string","example":"us-east-1"},"sns_topic_arn":{"type":["string","null"]},"updated_at":{"type":"string","example":"2025-12-03T10:30:00Z"}}},"EmailProviderTypeRoute":{"type":"string","enum":["ses","scaleway","smtp"]},"EmailRequest":{"type":"object","description":"Request body carrying just an email address (password-reset request).","required":["email"],"properties":{"email":{"type":"string"}}},"EmailResponse":{"type":"object","required":["id","from_address","to_addresses","subject","status","created_at","track_opens","track_clicks","open_count","click_count"],"properties":{"bcc_addresses":{"type":["array","null"],"items":{"type":"string"}},"cc_addresses":{"type":["array","null"],"items":{"type":"string"}},"click_count":{"type":"integer","format":"int32","description":"Number of times links in the email were clicked"},"created_at":{"type":"string","example":"2025-12-03T10:30:00Z"},"domain_id":{"type":["integer","null"],"format":"int32"},"error_message":{"type":["string","null"]},"first_clicked_at":{"type":["string","null"],"description":"When a link was first clicked"},"first_opened_at":{"type":["string","null"],"description":"When the email was first opened"},"from_address":{"type":"string","example":"hello@updates.example.com"},"from_name":{"type":["string","null"]},"headers":{"type":["object","null"],"additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"html_body":{"type":["string","null"]},"id":{"type":"string","example":"550e8400-e29b-41d4-a716-446655440000"},"open_count":{"type":"integer","format":"int32","description":"Number of times the email was opened"},"project_id":{"type":["integer","null"],"format":"int32"},"provider_message_id":{"type":["string","null"]},"reply_to":{"type":["string","null"]},"sent_at":{"type":["string","null"]},"status":{"type":"string","example":"sent"},"subject":{"type":"string"},"tags":{"type":["array","null"],"items":{"type":"string"}},"text_body":{"type":["string","null"]},"to_addresses":{"type":"array","items":{"type":"string"}},"track_clicks":{"type":"boolean","description":"Whether click tracking is enabled"},"track_opens":{"type":"boolean","description":"Whether open tracking is enabled"},"tracked_html_body":{"type":["string","null"],"description":"The final HTML sent to the provider (with tracking pixel and rewritten links)"}}},"EmailStatsResponse":{"type":"object","required":["total","sent","failed","queued","captured"],"properties":{"captured":{"type":"integer","format":"int64","description":"Emails captured without sending (Mailhog mode - no provider configured)","minimum":0},"failed":{"type":"integer","format":"int64","minimum":0},"queued":{"type":"integer","format":"int64","minimum":0},"sent":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"EmailStatusResponse":{"type":"object","required":["email_configured","password_reset_available","oidc_providers"],"properties":{"email_configured":{"type":"boolean"},"oidc_providers":{"type":"array","items":{"$ref":"#/components/schemas/OidcProviderSummary"}},"password_reset_available":{"type":"boolean"}}},"EmailTrackingResponse":{"type":"object","description":"Email tracking summary","required":["email_id","track_opens","track_clicks","open_count","click_count","unique_opens","unique_clicks","links"],"properties":{"click_count":{"type":"integer","format":"int32"},"email_id":{"type":"string"},"first_clicked_at":{"type":["string","null"]},"first_opened_at":{"type":["string","null"]},"links":{"type":"array","items":{"$ref":"#/components/schemas/TrackedLinkResponse"}},"open_count":{"type":"integer","format":"int32"},"track_clicks":{"type":"boolean"},"track_opens":{"type":"boolean"},"unique_clicks":{"type":"integer","format":"int64","minimum":0},"unique_opens":{"type":"integer","format":"int64","minimum":0}}},"EmailTrackingSetupResponse":{"type":"object","description":"Result of the one-click AWS-side event-tracking setup.","required":["topic_arn","webhook_url","subscription_requested","event_destination_attached"],"properties":{"event_destination_attached":{"type":"boolean","description":"The SESv2 event destination (bounce/complaint/delivery) is attached\nto the `temps-tracking` configuration set."},"subscription_requested":{"type":"boolean","description":"The webhook subscription was requested; SNS confirms it\nasynchronously through the webhook itself."},"topic_arn":{"type":"string","example":"arn:aws:sns:us-east-1:123456789012:temps-email-events-1"},"webhook_url":{"type":"string"}}},"EmailTrackingStatusResponse":{"type":"object","description":"Live status of the SES event-tracking pipeline for one provider.","required":["webhook_url","supports_event_tracking"],"properties":{"last_event_at":{"type":["string","null"],"description":"Most recent delivered/bounced/complained event recorded for an email\nsent through this provider. `null` means no provider feedback has\narrived yet.","example":"2026-07-18T10:31:00Z"},"sns_topic_arn":{"type":["string","null"]},"subscription_confirmed_at":{"type":["string","null"],"description":"When the SNS subscription for the current topic was confirmed.\n`null` with a topic set usually means the subscription is still\npending — most often because the endpoint was subscribed before the\ntopic ARN was saved here.","example":"2026-07-18T10:30:00Z"},"supports_event_tracking":{"type":"boolean","description":"Only SES providers support SNS event tracking."},"webhook_url":{"type":"string","description":"Public webhook endpoint SNS must deliver events to.","example":"https://temps.example.com/api/t/webhook/ses"}}},"EmbeddingData":{"type":"object","required":["object","embedding","index"],"properties":{"embedding":{"type":"array","items":{"type":"number","format":"double"}},"index":{"type":"integer","format":"int32"},"object":{"type":"string"}}},"EmbeddingInput":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"EmbeddingRequest":{"type":"object","required":["model","input"],"properties":{"dimensions":{"type":["integer","null"],"format":"int32"},"encoding_format":{"type":["string","null"]},"input":{"$ref":"#/components/schemas/EmbeddingInput"},"model":{"type":"string"}}},"EmbeddingResponse":{"type":"object","required":["object","data","model","usage"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/EmbeddingData"}},"model":{"type":"string"},"object":{"type":"string"},"usage":{"$ref":"#/components/schemas/EmbeddingUsage"}}},"EmbeddingUsage":{"type":"object","required":["prompt_tokens","total_tokens"],"properties":{"prompt_tokens":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"EnableBlobRequest":{"type":"object","description":"Request to enable Blob service","properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use (optional, defaults to RustFS)","example":"ghcr.io/rustfs/rustfs:0.5.0"},"root_password":{"type":["string","null"],"description":"Root password for S3 access"},"root_user":{"type":["string","null"],"description":"Root user for S3 access"}}},"EnableBlobResponse":{"type":"object","description":"Response after enabling Blob service","required":["success","message","status"],"properties":{"message":{"type":"string","description":"Human-readable message","example":"Blob service enabled successfully"},"status":{"$ref":"#/components/schemas/BlobStatusResponse","description":"Current status"},"success":{"type":"boolean","description":"Whether the operation succeeded","example":true}}},"EnableKvRequest":{"type":"object","description":"Request to enable the KV service","properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use (optional, uses default if not provided)","example":"gotempsh/redis-walg:8-bookworm"},"max_memory":{"type":["string","null"],"description":"Maximum memory allocation (e.g., \"256mb\", \"1gb\")","example":"256mb"},"persistence":{"type":"boolean","description":"Enable data persistence"}}},"EnableKvResponse":{"type":"object","description":"Response after enabling KV service","required":["success","message","status"],"properties":{"message":{"type":"string","description":"Status message","example":"KV service enabled successfully"},"status":{"$ref":"#/components/schemas/KvStatusResponse","description":"Current service status"},"success":{"type":"boolean","description":"Whether the service was successfully enabled"}}},"EnablePgStatStatementsResponse":{"type":"object","description":"Response for the enable pg_stat_statements endpoint.","required":["message"],"properties":{"message":{"type":"string","description":"Human-readable message confirming the action."}}},"EndpointDto":{"type":"object","description":"One DNS record on the wire. Mirrors `service_endpoints::Model` but\nkeeps the API stable across entity evolution. `target_ip` is a string\n(v4 or v6 literal, or CNAME target hostname) parsed by the resolver.","required":["id","fqdn","record_type","ttl","owner_kind","owner_id","generation"],"properties":{"fqdn":{"type":"string"},"generation":{"type":"integer","format":"int64"},"id":{"type":"integer","format":"int64"},"node_id":{"type":["integer","null"],"format":"int32"},"owner_id":{"type":"integer","format":"int64"},"owner_kind":{"type":"string"},"record_type":{"type":"string"},"target_ip":{"type":["string","null"]},"target_port":{"type":["integer","null"],"format":"int32"},"ttl":{"type":"integer","format":"int32"}}},"EnqueuedJob":{"type":"object","description":"A single job that was successfully enqueued during a fan-out run.","required":["backup_id","job_id","engine"],"properties":{"backup_id":{"type":"integer","format":"int32","description":"FK to `backups.id` for this job."},"engine":{"type":"string","description":"Engine key (e.g. `\"control_plane\"`, `\"redis\"`, `\"postgres_pgdump\"`)."},"job_id":{"type":"integer","format":"int64","description":"FK to `backup_jobs.id` for this job."},"target_service_id":{"type":["integer","null"],"format":"int32","description":"FK to `external_services.id` when this is an external-service job.\n`None` for the control-plane job."}}},"EnrichVisitorRequest":{"type":"object","required":["custom_data"],"properties":{"custom_data":{"type":"object"}}},"EnrichVisitorResponse":{"type":"object","required":["success","visitor_id","message"],"properties":{"message":{"type":"string"},"success":{"type":"boolean"},"visitor_id":{"type":"string"}}},"EnrollCloudRequest":{"type":"object","required":["enrollment_code"],"properties":{"enrollment_code":{"type":"string","example":"ABCD-EFGH","minLength":1}}},"EnrollmentTokenInfo":{"type":"object","required":["id","expires_at","used_count","max_uses","created_at"],"properties":{"bound_node_name":{"type":["string","null"]},"created_at":{"type":"string"},"expires_at":{"type":"string"},"id":{"type":"integer","format":"int32"},"max_uses":{"type":"integer","format":"int32"},"used_count":{"type":"integer","format":"int32"}}},"EnrollmentTokenListResponse":{"type":"object","required":["tokens"],"properties":{"tokens":{"type":"array","items":{"$ref":"#/components/schemas/EnrollmentTokenInfo"}}}},"EntityInfoResponse":{"type":"object","required":["container_path","entity","entity_type","fields"],"properties":{"container_path":{"type":"array","items":{"type":"string"},"description":"Full container path","example":["mydb","public"]},"entity":{"type":"string","description":"Entity name","example":"users"},"entity_type":{"type":"string","description":"Entity type","example":"table"},"fields":{"type":"array","items":{"$ref":"#/components/schemas/FieldResponse"},"description":"Field definitions"},"metadata":{"description":"Additional metadata (content_type, last_modified, etag, etc.)"},"row_count":{"type":["integer","null"],"description":"Approximate row count (for tables/collections)","example":1234,"minimum":0},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size in bytes (for objects/files)","example":1048576,"minimum":0},"sort_schema":{"description":"JSON Schema for sort options (if supported)"}}},"EntityResponse":{"type":"object","required":["name","entity_type"],"properties":{"entity_type":{"type":"string","description":"Entity type (table, view, collection, etc.)","example":"table"},"name":{"type":"string","description":"Entity name (table/collection)","example":"users"},"row_count":{"type":["integer","null"],"description":"Approximate row count","example":1234,"minimum":0},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size in bytes (for files/objects)","example":1048576,"minimum":0}}},"EnvVarInput":{"type":"object","description":"Input for environment variable","required":["name","value"],"properties":{"name":{"type":"string","description":"Variable name"},"value":{"type":"string","description":"Variable value"}}},"EnvVarIntegrationInfo":{"type":"object","required":["service_id","service_name","service_type","service_updated_at"],"properties":{"service_id":{"type":"integer","format":"int32"},"service_name":{"type":"string"},"service_slug":{"type":["string","null"]},"service_type":{"type":"string"},"service_updated_at":{"type":"string"}}},"EnvVarResponse":{"type":"object","description":"Environment variable with masked sensitive values","required":["key","value","is_masked"],"properties":{"is_masked":{"type":"boolean","description":"Whether this is a sensitive/masked value"},"key":{"type":"string"},"value":{"type":"string"}}},"EnvVarTemplateResponse":{"type":"object","description":"Environment variable template response","required":["name","required"],"properties":{"default":{"type":["string","null"],"description":"Default value if not provided by user"},"default_generator":{"type":["string","null"],"description":"Frontend-side generator hint for the default value\n(e.g. `app_url`, `random_secret`, `random_hex_32`)"},"description":{"type":["string","null"],"description":"Description of what this variable is used for"},"example":{"type":["string","null"],"description":"Example value for documentation"},"name":{"type":"string","description":"Name of the environment variable"},"required":{"type":"boolean","description":"Whether this variable is required"}}},"EnvironmentConfiguration":{"type":"object","description":"Environment-level configuration","required":["name","subdomain","resources"],"properties":{"name":{"type":"string","description":"Environment name"},"resources":{"$ref":"#/components/schemas/ResourceLimits","description":"Resource limits for environment"},"subdomain":{"type":"string","description":"Proposed subdomain"}}},"EnvironmentDomainResponse":{"type":"object","required":["id","environment_id","domain","created_at","url"],"properties":{"created_at":{"type":"integer","format":"int64"},"domain":{"type":"string"},"environment_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"url":{"type":"string","description":"Full URL for this domain (e.g., https://buildtolearndev-production.example.com)","example":"https://buildtolearndev-production.example.com"}}},"EnvironmentInfo":{"type":"object","required":["id","name","main_url"],"properties":{"current_deployment_id":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"main_url":{"type":"string"},"name":{"type":"string"}}},"EnvironmentResponse":{"type":"object","required":["id","project_id","name","slug","main_url","subdomain","created_at","updated_at","is_preview","protected","sleeping"],"properties":{"attack_mode":{"type":["boolean","null"],"description":"Per-environment CAPTCHA attack-mode override.\n`null` means inherit the project-level `attack_mode`; `true`/`false`\nexplicitly enable/disable the challenge for this environment. Always\nserialized (NOT skipped) so the UI can distinguish `null` from `false`."},"branch":{"type":["string","null"]},"created_at":{"type":"integer","format":"int64"},"current_deployment_id":{"type":["integer","null"],"format":"int32"},"deployment_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DeploymentConfig","description":"Deployment configuration for this environment (overrides project-level config)"}]},"estimated_sleep_at":{"type":["integer","null"],"format":"int64","description":"Estimated time (epoch millis) when the environment will go to sleep\nbased on last activity + idle timeout. NULL when sleeping or on-demand disabled."},"force_https":{"type":["boolean","null"],"description":"Per-environment HTTP→HTTPS redirect override.\n`null` means inherit the proxy default (redirect only when the host has\nan active TLS certificate); `true` always redirects plain HTTP for this\nenvironment, `false` never does. Always serialized (NOT skipped) so the\nUI can distinguish `null` from `false`."},"id":{"type":"integer","format":"int32"},"is_preview":{"type":"boolean","description":"Indicates if this is a preview environment (auto-created per branch)\nFor preview environments, 'branch' contains the feature branch name"},"last_activity_at":{"type":["integer","null"],"format":"int64","description":"Last proxied request timestamp (epoch millis) for on-demand environments.\nNULL when on-demand is disabled or no traffic has been received yet."},"main_url":{"type":"string"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"protected":{"type":"boolean","description":"When true, git pushes do NOT auto-deploy to this environment.\nDeployments must be promoted from another environment."},"sleeping":{"type":"boolean","description":"When true, the environment's containers are currently stopped due to\ninactivity (on-demand mode) and will start on the next request."},"slug":{"type":"string"},"subdomain":{"type":"string","description":"The host label stored for this environment (e.g.\n`myproject-production`). This is the prefix that is combined with the\nplatform's preview domain at request time to produce `main_url`. Edit\nthis via the rename-subdomain endpoint, not the full URL."},"updated_at":{"type":"integer","format":"int64"}}},"EnvironmentVariable":{"type":"object","description":"Environment variable","required":["key","value","is_secret"],"properties":{"is_secret":{"type":"boolean","description":"Whether this is a secret (should be encrypted)"},"key":{"type":"string","description":"Variable name"},"source_description":{"type":["string","null"],"description":"Where this env var originates from (for traceability)"},"value":{"type":"string","description":"Variable value (may be redacted for secrets)"}}},"EnvironmentVariableInfo":{"type":"object","required":["name","value","sensitive"],"properties":{"name":{"type":"string"},"sensitive":{"type":"boolean","description":"Whether this variable contains sensitive data (passwords, keys, tokens)","example":false},"value":{"type":"string"}}},"EnvironmentVariableResponse":{"type":"object","required":["id","key","created_at","updated_at","environments","include_in_preview","is_secret"],"properties":{"created_at":{"type":"integer","format":"int64"},"environments":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentInfo"}},"id":{"type":"integer","format":"int32"},"include_in_preview":{"type":"boolean","description":"Include this environment variable in preview environments"},"is_secret":{"type":"boolean","description":"Whether the variable is a write-only secret. Secrets always have\n`value: None` in responses."},"key":{"type":"string"},"updated_at":{"type":"integer","format":"int64"},"value":{"type":["string","null"],"description":"Plaintext value for non-secret vars (or `\"***\"` mask for list responses).\n`None` for secret vars — secrets are write-only."}}},"EnvironmentVariableValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"ErrorDashboardStatsQuery":{"type":"object","required":["start_time","end_time"],"properties":{"compare_to_previous":{"type":["boolean","null"]},"end_time":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"start_time":{"type":"string","format":"date-time"}}},"ErrorDashboardStatsResponse":{"type":"object","required":["total_errors","total_errors_previous_period","total_errors_change_percent","error_groups","error_groups_previous_period","start_time","end_time"],"properties":{"comparison_end_time":{"type":["string","null"],"format":"date-time"},"comparison_start_time":{"type":["string","null"],"format":"date-time"},"end_time":{"type":"string","format":"date-time"},"error_groups":{"type":"integer","format":"int64"},"error_groups_previous_period":{"type":"integer","format":"int64"},"start_time":{"type":"string","format":"date-time"},"total_errors":{"type":"integer","format":"int64"},"total_errors_change_percent":{"type":"number","format":"double"},"total_errors_previous_period":{"type":"integer","format":"int64"}}},"ErrorEventResponse":{"type":"object","required":["id","error_group_id","timestamp","created_at"],"properties":{"created_at":{"type":"string"},"data":{"description":"Full error event data (contains raw Sentry event or custom error data)"},"error_group_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int64"},"source":{"type":["string","null"],"description":"Source of the error event (e.g., \"sentry\", \"custom\", \"bugsnag\")"},"timestamp":{"type":"string"}}},"ErrorGroupResponse":{"type":"object","required":["id","title","error_type","first_seen","last_seen","total_count","status","project_id","created_at","updated_at"],"properties":{"assigned_to":{"type":["string","null"]},"created_at":{"type":"string"},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_type":{"type":"string"},"first_seen":{"type":"string"},"id":{"type":"integer","format":"int32"},"last_seen":{"type":"string"},"message_template":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"status":{"type":"string"},"title":{"type":"string"},"total_count":{"type":"integer","format":"int32"},"updated_at":{"type":"string"},"visitor_id":{"type":["integer","null"],"format":"int32"}}},"ErrorGroupStatsResponse":{"type":"object","required":["total_groups","unresolved_groups","resolved_groups","ignored_groups"],"properties":{"ignored_groups":{"type":"integer","format":"int64"},"resolved_groups":{"type":"integer","format":"int64"},"total_groups":{"type":"integer","format":"int64"},"unresolved_groups":{"type":"integer","format":"int64"}}},"ErrorResponse":{"type":"object","required":["error"],"properties":{"details":{"type":["string","null"]},"error":{"type":"string"}}},"ErrorRow":{"type":"object","required":["id","ts","error_group_id","fingerprint","error_class","stacktrace_preview","stacktrace_truncated"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_class":{"type":"string"},"error_group_id":{"type":"integer","format":"int32"},"fingerprint":{"type":"string"},"id":{"type":"integer","format":"int64"},"message":{"type":["string","null"]},"stacktrace_preview":{},"stacktrace_truncated":{"type":"boolean"},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"}}},"ErrorTimeSeriesDataResponse":{"type":"object","required":["timestamp","count"],"properties":{"count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"}}},"ErrorTimeSeriesQuery":{"type":"object","required":["start_time","end_time"],"properties":{"bucket":{"type":"string","description":"Time bucket size (e.g., \"1h\", \"15m\", \"1d\", \"1 hour\", \"30 minutes\")","example":"1h"},"end_time":{"type":"string","format":"date-time"},"start_time":{"type":"string","format":"date-time"}}},"EventActivityBucket":{"type":"object","description":"Time bucket data point for event activity graph","required":["timestamp","count","unique_visitors"],"properties":{"count":{"type":"integer","format":"int64","description":"Number of event occurrences in this bucket"},"timestamp":{"type":"string","description":"Timestamp for this bucket (ISO 8601)"},"unique_visitors":{"type":"integer","format":"int64","description":"Number of unique visitors in this bucket"}}},"EventBreakdown":{"type":"string","enum":["country","region","city"]},"EventBrowserStats":{"type":"object","description":"Browser stats for an event","required":["browser","count","percentage"],"properties":{"browser":{"type":"string","description":"Browser name"},"count":{"type":"integer","format":"int64","description":"Number of event occurrences from this browser"},"percentage":{"type":"number","format":"double","description":"Percentage of total events"}}},"EventCount":{"type":"object","required":["event_name","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"event_name":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"EventCountryStats":{"type":"object","description":"Country stats for an event","required":["country","count","percentage"],"properties":{"count":{"type":"integer","format":"int64","description":"Number of event occurrences from this country"},"country":{"type":"string","description":"Country name"},"country_code":{"type":["string","null"],"description":"ISO country code (2-letter)"},"percentage":{"type":"number","format":"double","description":"Percentage of total events"}}},"EventDetailQuery":{"type":"object","description":"Query parameters for event detail analytics","required":["event_name","project_id","start_date","end_date"],"properties":{"bucket_interval":{"type":["string","null"],"description":"Bucket interval for time series: 'hour', 'day', 'week', 'month' (default: auto)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_name":{"type":"string","description":"The specific event name to get details for"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventDetailResponse":{"type":"object","description":"Summary response for a specific event's analytics","required":["event_name","total_count","unique_visitors","unique_sessions","activity_over_time","referrers","countries","browsers","bucket_interval"],"properties":{"activity_over_time":{"type":"array","items":{"$ref":"#/components/schemas/EventActivityBucket"},"description":"Time series data for event activity graph"},"browsers":{"type":"array","items":{"$ref":"#/components/schemas/EventBrowserStats"},"description":"Browser distribution of visitors who triggered this event"},"bucket_interval":{"type":"string","description":"Bucket interval used for time series ('hour', 'day', etc.)"},"countries":{"type":"array","items":{"$ref":"#/components/schemas/EventCountryStats"},"description":"Geographic distribution of visitors who triggered this event"},"event_name":{"type":"string","description":"The event name being analyzed"},"referrers":{"type":"array","items":{"$ref":"#/components/schemas/EventReferrerStats"},"description":"Top referrer hostnames for visitors who triggered this event"},"total_count":{"type":"integer","format":"int64","description":"Total number of times this event was triggered in the date range"},"unique_sessions":{"type":"integer","format":"int64","description":"Number of unique sessions where this event occurred"},"unique_visitors":{"type":"integer","format":"int64","description":"Number of unique visitors who triggered this event"}}},"EventEntriesQuery":{"type":"object","description":"Query parameters for the raw event entries list","required":["event_name","project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_name":{"type":"string","description":"The specific event name to list occurrences for"},"page":{"type":["integer","null"],"format":"int64","description":"Page number (1-based, default: 1)","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","description":"Items per page (default: 20, max: 100)","minimum":0},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventEntriesResponse":{"type":"object","description":"Paginated response for raw event entries","required":["event_name","total_count","page","per_page","entries"],"properties":{"entries":{"type":"array","items":{"$ref":"#/components/schemas/EventEntryInfo"},"description":"Individual event occurrences, most recent first"},"event_name":{"type":"string","description":"The event name"},"page":{"type":"integer","format":"int64","description":"Current page number","minimum":0},"per_page":{"type":"integer","format":"int64","description":"Items per page","minimum":0},"total_count":{"type":"integer","format":"int64","description":"Total number of occurrences of this event in the date range"}}},"EventEntryInfo":{"type":"object","description":"A single raw occurrence of an event, including its custom JSON properties","required":["id","timestamp","page_path","href"],"properties":{"browser":{"type":["string","null"],"description":"Browser name"},"city":{"type":["string","null"],"description":"City of the visitor at the time of the event"},"country":{"type":["string","null"],"description":"Country of the visitor at the time of the event"},"country_code":{"type":["string","null"],"description":"ISO country code (2-letter)"},"device_type":{"type":["string","null"],"description":"Device type (Desktop, Mobile, Tablet)"},"href":{"type":"string","description":"Full URL where the event was triggered"},"id":{"type":"integer","format":"int64","description":"Event row ID"},"page_path":{"type":"string","description":"Page path where the event was triggered"},"props":{"type":["object","null"],"description":"Custom event properties as JSON (null when the event carried no data)"},"session_id":{"type":["string","null"],"description":"Session ID the event belongs to (if any)"},"timestamp":{"type":"string","format":"date-time","description":"When the event occurred"},"visitor_id":{"type":["integer","null"],"format":"int32","description":"Visitor numeric ID (if known)"},"visitor_uuid":{"type":["string","null"],"description":"Visitor UUID (if known)"}}},"EventKind":{"type":"string","description":"Tag enum for filter parameters and routing. Matches the variant\ndiscriminator used by `ObservabilityEvent`.","enum":["request","span","error","revenue"]},"EventMetricsPayload":{"type":"object","required":["event_name","event_data","request_path","request_query"],"properties":{"cls":{"type":["number","null"],"format":"float","description":"Cumulative Layout Shift (score)"},"event_data":{},"event_name":{"type":"string"},"fcp":{"type":["number","null"],"format":"float","description":"First Contentful Paint (milliseconds)"},"fid":{"type":["number","null"],"format":"float","description":"First Input Delay (milliseconds)"},"inp":{"type":["number","null"],"format":"float","description":"Interaction to Next Paint (milliseconds)"},"language":{"type":["string","null"]},"lcp":{"type":["number","null"],"format":"float","description":"Largest Contentful Paint (milliseconds)"},"page_title":{"type":["string","null"]},"referrer":{"type":["string","null"],"description":"Referrer URL (falls back to Referer header if not provided)"},"request_path":{"type":"string"},"request_query":{"type":"string"},"screen_height":{"type":["integer","null"],"format":"int32","minimum":0},"screen_width":{"type":["integer","null"],"format":"int32","minimum":0},"ttfb":{"type":["number","null"],"format":"float","description":"Time to First Byte (milliseconds)"},"viewport_height":{"type":["integer","null"],"format":"int32","minimum":0},"viewport_width":{"type":["integer","null"],"format":"int32","minimum":0}}},"EventReferrerStats":{"type":"object","description":"Referrer stats for an event","required":["referrer","count","percentage"],"properties":{"count":{"type":"integer","format":"int64","description":"Number of event occurrences from this referrer"},"percentage":{"type":"number","format":"double","description":"Percentage of total events"},"referrer":{"type":"string","description":"Referrer hostname or \"Direct\""}}},"EventTimeline":{"type":"object","required":["date","count"],"properties":{"count":{"type":"integer","format":"int64"},"date":{"type":"string","format":"date-time"}}},"EventTimelineQuery":{"type":"object","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events (raw count), sessions (unique sessions), or visitors (unique visitors)"},"bucket_size":{"type":["string","null"],"description":"Bucket size: hour, day, or week (auto-detected if not specified)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_name":{"type":["string","null"]},"start_date":{"type":"string","format":"date-time"}}},"EventType":{"type":"object","required":["name","count"],"properties":{"count":{"type":"integer","format":"int64"},"name":{"type":"string"}}},"EventTypeBreakdown":{"type":"object","required":["event_type","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"event_type":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"EventTypeBreakdownQuery":{"type":"object","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events (raw count), sessions (unique sessions), or visitors (unique visitors)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventTypeResponse":{"type":"object","required":["event_type","description","category"],"properties":{"category":{"type":"string"},"description":{"type":"string"},"event_type":{"type":"string"}}},"EventTypesResponse":{"type":"object","required":["events","total","page","page_size"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/EventType"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"EventVisitorInfo":{"type":"object","description":"A visitor who triggered a specific event","required":["visitor_id","visitor_uuid","event_count","first_triggered","last_triggered"],"properties":{"browser":{"type":["string","null"],"description":"Browser name"},"city":{"type":["string","null"],"description":"Visitor's city"},"country":{"type":["string","null"],"description":"Visitor's country"},"country_code":{"type":["string","null"],"description":"Visitor's country code"},"device_type":{"type":["string","null"],"description":"Device type (Desktop, Mobile, Tablet)"},"event_count":{"type":"integer","format":"int64","description":"Number of times this visitor triggered the event"},"first_triggered":{"type":"string","format":"date-time","description":"When the visitor first triggered the event in the date range"},"last_triggered":{"type":"string","format":"date-time","description":"When the visitor last triggered the event in the date range"},"referrer_hostname":{"type":["string","null"],"description":"Referrer hostname for the event"},"visitor_id":{"type":"integer","format":"int32","description":"Visitor numeric ID"},"visitor_uuid":{"type":"string","description":"Visitor UUID"}}},"EventVisitorsQuery":{"type":"object","description":"Query parameters for event visitors list","required":["event_name","project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_name":{"type":"string","description":"The specific event name to list visitors for"},"page":{"type":["integer","null"],"format":"int64","description":"Page number (1-based, default: 1)","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","description":"Items per page (default: 20, max: 100)","minimum":0},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventVisitorsResponse":{"type":"object","description":"Paginated response for event visitors","required":["event_name","total_count","page","per_page","visitors"],"properties":{"event_name":{"type":"string","description":"The event name"},"page":{"type":"integer","format":"int64","description":"Current page number","minimum":0},"per_page":{"type":"integer","format":"int64","description":"Items per page","minimum":0},"total_count":{"type":"integer","format":"int64","description":"Total number of unique visitors who triggered this event"},"visitors":{"type":"array","items":{"$ref":"#/components/schemas/EventVisitorInfo"},"description":"Individual visitors who triggered this event"}}},"EventsCountQuery":{"type":"object","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events (raw count), sessions (unique sessions), or visitors (unique visitors)"},"custom_events_only":{"type":["boolean","null"],"description":"Only return custom events, excluding system events like page_view, page_leave, heartbeat (default: true)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventsResponse":{"type":"object","required":["events","applied_kinds"],"properties":{"applied_kinds":{"type":"array","items":{"$ref":"#/components/schemas/EventKind"},"description":"Echo of the kinds filter actually applied (server-resolved). Useful\nfor clients that pass `kinds=` empty and want to know what they got."},"events":{"type":"array","items":{"$ref":"#/components/schemas/ObservabilityEvent"}}}},"ExecBody":{"type":"object","required":["cmd"],"properties":{"cmd":{"type":"array","items":{"type":"string"}},"cwd":{"type":["string","null"]},"env":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}}},"additionalProperties":false},"ExecDetachedResponse":{"type":"object","required":["job_id"],"properties":{"job_id":{"type":"string"}}},"ExecResponse":{"type":"object","required":["exit_code","stdout","stderr"],"properties":{"exit_code":{"type":"integer","format":"int32"},"stderr":{"type":"string"},"stdout":{"type":"string"}}},"ExecuteImportRequest":{"type":"object","description":"Request to execute an import","required":["session_id","project_name","preset","directory","main_branch"],"properties":{"directory":{"type":"string","description":"Project directory","example":"."},"dry_run":{"type":["boolean","null"],"description":"Dry run mode (don't create resources)"},"main_branch":{"type":"string","description":"Main branch name","example":"main"},"preset":{"type":"string","description":"Preset to use for the project (e.g., \"nextjs\", \"express\", \"docker\")"},"project_name":{"type":"string","description":"Project name to use (overrides the name from the plan)","example":"my-app"},"session_id":{"type":"string","description":"Session ID from plan creation"}}},"ExecuteImportResponse":{"type":"object","description":"Response from import execution","required":["session_id","status","step_results"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32","description":"Created deployment ID (if completed)"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Created environment ID (if completed)"},"project_id":{"type":["integer","null"],"format":"int32","description":"Created project ID (if completed)"},"session_id":{"type":"string","description":"Session ID"},"status":{"$ref":"#/components/schemas/ImportExecutionStatus","description":"Execution status"},"step_results":{"type":"array","items":{"$ref":"#/components/schemas/StepResult"},"description":"Per-step results (in execution order)"}}},"ExecuteOperationRequest":{"type":"object","required":["operation"],"properties":{"operation":{"type":"string"}}},"ExpireRequest":{"type":"object","description":"Request to set expiration on a key","required":["key","seconds"],"properties":{"key":{"type":"string","description":"The key to set expiration on","example":"session:abc"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1},"seconds":{"type":"integer","format":"int64","description":"Expiration time in seconds","example":3600}}},"ExpireResponse":{"type":"object","description":"Response for expire operation","required":["success"],"properties":{"success":{"type":"boolean","description":"True if expiration was set, false if key doesn't exist"}}},"ExplorerSupportResponse":{"type":"object","required":["supported","service_type","capabilities","hierarchy"],"properties":{"capabilities":{"type":"array","items":{"type":"string"},"description":"Capabilities supported by this service","example":["sql"]},"filter_schema":{"description":"JSON Schema for filter format with embedded UI hints (if supported)"},"hierarchy":{"type":"array","items":{"$ref":"#/components/schemas/HierarchyLevel"},"description":"Hierarchy levels (describes the navigation structure)"},"reason":{"type":["string","null"],"description":"Reason why explorer is not supported (if applicable)"},"service_type":{"type":"string","description":"Service type","example":"postgres"},"supported":{"type":"boolean","description":"Whether the service supports query explorer functionality","example":true}}},"ExtendTimeoutBody":{"type":"object","properties":{"duration":{"type":["integer","null"],"format":"int64","description":"`@vercel/sandbox`-compatible alternative — duration in milliseconds.\nUsed when `extra_secs` is absent.","minimum":0},"extra_secs":{"type":["integer","null"],"format":"int64","description":"Extra seconds to add to the existing `expires_at` (temps-native).","minimum":0}}},"ExternalImageResponse":{"type":"object","required":["id","project_id","image_ref","pushed_at","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"digest":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"image_ref":{"type":"string"},"metadata":{},"project_id":{"type":"integer","format":"int32"},"pushed_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"size_bytes":{"type":["integer","null"],"format":"int64"},"tag":{"type":["string","null"]}}},"ExternalServiceBackupResponse":{"type":"object","description":"Response type for external service backup","required":["id","service_id","backup_id","backup_type","state","started_at","s3_location","metadata","compression_type","created_by"],"properties":{"backup_id":{"type":"integer","format":"int32"},"backup_type":{"type":"string"},"checksum":{"type":["string","null"]},"compression_type":{"type":"string"},"created_by":{"type":"integer","format":"int32"},"error_message":{"type":["string","null"]},"expires_at":{"type":["string","null"],"example":"2025-02-15T14:30:00.123Z"},"finished_at":{"type":["string","null"],"example":"2025-01-15T14:35:00.456Z"},"id":{"type":"integer","format":"int32"},"metadata":{},"s3_location":{"type":"string"},"service_id":{"type":"integer","format":"int32"},"size_bytes":{"type":["integer","null"],"format":"int64"},"started_at":{"type":"string","example":"2025-01-15T14:30:00.123Z"},"state":{"type":"string"}}},"ExternalServiceDetails":{"type":"object","required":["service","sensitive_parameters"],"properties":{"current_parameters":{"type":["object","null"],"additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"parameter_schema":{},"sensitive_parameters":{"type":"array","items":{"type":"string"},"description":"Parameter names whose values are masked in `current_parameters` and\nmay be fetched only through the audited reveal endpoint."},"service":{"$ref":"#/components/schemas/ExternalServiceInfo"}}},"ExternalServiceInfo":{"type":"object","required":["id","name","service_type","status","created_at","updated_at","topology"],"properties":{"connection_info":{"type":["string","null"]},"created_at":{"type":"string"},"error_message":{"type":["string","null"],"description":"Error message from failed initialization."},"id":{"type":"integer","format":"int32"},"members":{"type":"array","items":{"$ref":"#/components/schemas/ServiceMemberInfo"},"description":"Cluster members (empty for standalone services)."},"metrics_enabled":{"type":"boolean","description":"Whether metric collection is enabled for this service. The UI uses this\nto decide whether to poll the monitoring endpoints."},"name":{"type":"string"},"node_id":{"type":["integer","null"],"format":"int32","description":"Node ID where the service runs. Null means control plane (local)."},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute"},"status":{"type":"string"},"topology":{"type":"string","description":"Service topology: \"standalone\" (single container) or \"cluster\" (HA multi-member).","example":"standalone"},"updated_at":{"type":"string"},"version":{"type":["string","null"]}}},"ExternalServiceSummary":{"type":"object","description":"Summary of the external service that owns a backup. Only populated for\nexternal-service backups (Redis, Postgres, etc.); absent for control-plane\nbackups.","required":["id","name","service_type"],"properties":{"id":{"type":"integer","format":"int32","description":"Database id of the external service."},"name":{"type":"string","description":"Human-readable service name (e.g. \"redis-prod\")."},"service_type":{"type":"string","description":"Service type string (e.g. \"postgres\", \"redis\", \"mongodb\").","example":"postgres"}}},"FieldResponse":{"type":"object","required":["name","field_type","nullable"],"properties":{"field_type":{"type":"string","description":"Field type (Int32, String, Timestamp, etc.)","example":"Int64"},"name":{"type":"string","description":"Field name","example":"id"},"nullable":{"type":"boolean","description":"Whether the field is nullable","example":false}}},"FiringSeriesEntry":{"type":"object","description":"A single currently-firing series for a dynamic alert rule, snapshotted from\nthe evaluator's in-memory per-series firing map at read time (ADR-026 Phase 3).","required":["series_key","series_label"],"properties":{"alarm_id":{"type":["integer","null"],"format":"int32","description":"The open alarm's id, when one was created (absent if suppressed)."},"series_key":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"The series' label pairs, e.g. `[[\"endpoint\",\"/checkout\"],[\"region\",\"eu-west\"]]`."},"series_label":{"type":"string","description":"The human-readable joined label, e.g. `endpoint=/checkout, region=eu-west`."}}},"FlagEnvironmentResponse":{"type":"object","required":["environment_id","enabled"],"properties":{"enabled":{"type":"boolean"},"environment_id":{"type":"integer","format":"int32"},"value":{}}},"FlagListResponse":{"type":"object","description":"Note the absence of `salt`: it is never exposed. Publishing the bucketing\nsalt would let a client predict, and self-select into, a rollout cohort.","required":["flags","total","page","page_size","total_pages"],"properties":{"flags":{"type":"array","items":{"$ref":"#/components/schemas/FlagResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","description":"Total flags matching the filter, across all pages.","minimum":0},"total_pages":{"type":"integer","format":"int64","minimum":0}}},"FlagResponse":{"type":"object","required":["id","key","value_type","default_value","client_visible","created_at","updated_at","environments"],"properties":{"archived_at":{"type":["string","null"]},"client_visible":{"type":"boolean"},"created_at":{"type":"string"},"default_value":{},"description":{"type":["string","null"]},"environments":{"type":"array","items":{"$ref":"#/components/schemas/FlagEnvironmentResponse"},"description":"Per-environment overrides. Empty means the flag inherits its default\neverywhere."},"id":{"type":"integer","format":"int32"},"key":{"type":"string"},"last_evaluated_at":{"type":["string","null"],"description":"When an app last actually evaluated this flag. `None` means never seen,\nwhich is a real answer rather than missing data."},"updated_at":{"type":"string"},"value_type":{"type":"string"}}},"FlagSnapshot":{"type":"object","description":"A single flag, already resolved down to one environment. This is what the\nevaluator sees and what the SDK caches in memory.","required":["key","value_type","default_value","enabled"],"properties":{"default_value":{"description":"Served whenever evaluation cannot do better. Genuinely polymorphic by\ndesign — the surrounding struct carries the type."},"enabled":{"type":"boolean","description":"False means the kill switch is engaged for this environment."},"environment_value":{"description":"`None` means \"inherit `default_value`\"."},"key":{"type":"string"},"value_type":{"$ref":"#/components/schemas/FlagValueType"}}},"FlagSnapshotResponse":{"type":"object","required":["environment_id","flags"],"properties":{"environment_id":{"type":"integer","format":"int32"},"flags":{"type":"array","items":{"$ref":"#/components/schemas/FlagSnapshot"},"description":"Flags collapsed to what the evaluator needs, sorted by key so the\nserialized form — and therefore the ETag — is stable."}}},"FlagValueType":{"type":"string","description":"The declared type of a flag's value. Fixed at create time.","enum":["bool","string","number","json"]},"ForecastAlgorithm":{"type":"string","description":"Forecast model family.","enum":["linear","seasonal"]},"ForecastParams":{"type":"object","description":"Forecast detector parameters (stub — not yet evaluated).","required":["forecast_horizon_secs","comparator","threshold"],"properties":{"algorithm":{"$ref":"#/components/schemas/ForecastAlgorithm"},"comparator":{"$ref":"#/components/schemas/Comparator","description":"Comparator + threshold the *forecast* is checked against."},"deviations":{"type":"number","format":"double"},"forecast_horizon_secs":{"type":"integer","format":"int32","description":"How far ahead to project before checking the breach condition."},"threshold":{"type":"number","format":"double"}}},"FullError":{"type":"object","required":["id","ts","error_group_id","fingerprint","error_class"],"properties":{"data":{"description":"Full JSONB blob from `error_events.data` — stack trace, breadcrumbs,\nrequest context, everything. Schema is documented per source SDK."},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_class":{"type":"string"},"error_group_id":{"type":"integer","format":"int32"},"fingerprint":{"type":"string"},"id":{"type":"integer","format":"int64"},"message":{"type":["string","null"]},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"}}},"FullEvent":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/FullRequest"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["request"]}}}]},{"allOf":[{"$ref":"#/components/schemas/FullError"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["error"]}}}]},{"allOf":[{"$ref":"#/components/schemas/RevenueRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["revenue"]}}}]},{"allOf":[{"$ref":"#/components/schemas/SpanRow","description":"`SpanRow.attributes` is the truncated form; re-fetching returns\nthe same shape so the panel has a stable contract."},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["span"]}}}],"description":"`SpanRow.attributes` is the truncated form; re-fetching returns\nthe same shape so the panel has a stable contract."}],"description":"One un-truncated row, returned by the `/full/{type}/{id}` endpoint when\nthe user clicks \"Show full\". Same shape as the list rows, but with the\nraw heavy fields restored (no truncation flags) so the side panel can\nrender the long form."},"FullRequest":{"type":"object","required":["id","ts","method","host","path","status"],"properties":{"client_ip":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_group_id":{"type":["integer","null"],"format":"int32"},"host":{"type":"string"},"id":{"type":"string","description":"The request's unique `request_id` — same identity the list rows carry\n(backend-agnostic; ClickHouse rows have no serial PK)."},"latency_ms":{"type":["integer","null"],"format":"int32"},"method":{"type":"string"},"path":{"type":"string"},"referrer":{"type":["string","null"]},"request_headers":{},"response_headers":{},"status":{"type":"integer","format":"int32"},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"},"user_agent":{"type":["string","null"]}}},"FunnelMetricsResponse":{"type":"object","required":["funnel_id","funnel_name","total_entries","step_conversions","overall_conversion_rate","average_completion_time_seconds"],"properties":{"average_completion_time_seconds":{"type":"number","format":"double"},"funnel_id":{"type":"integer","format":"int32"},"funnel_name":{"type":"string"},"overall_conversion_rate":{"type":"number","format":"double"},"step_conversions":{"type":"array","items":{"$ref":"#/components/schemas/StepConversionResponse"}},"total_entries":{"type":"integer","format":"int64","minimum":0}}},"FunnelResponse":{"type":"object","required":["id","name","is_active","created_at","updated_at"],"properties":{"created_at":{"type":"string"},"description":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"name":{"type":"string"},"updated_at":{"type":"string"}}},"GatewayStatus":{"type":"object","description":"Detailed gateway container status surfaced to the settings UI.","required":["present","running","health","container_name","expected_image","drift","auto_upgrade"],"properties":{"auto_upgrade":{"type":"boolean","description":"True if `auto_upgrade` is enabled in settings."},"container_name":{"type":"string","description":"Container name."},"drift":{"type":"boolean","description":"True when `image != expected_image` and the container is present."},"expected_image":{"type":"string","description":"The image the supervisor *expects* (from settings/constant). If this\ndiffers from `image`, the UI shows a \"drift\" badge."},"health":{"type":"string","description":"Higher-level health label: \"running\" | \"restarting\" | \"crash_looping\"\n| \"stopped\" | \"missing\". UI should prefer this over `running`."},"host_port":{"type":["integer","null"],"format":"int32","description":"Host port that the container's :8080 is published on.","minimum":0},"image":{"type":["string","null"],"description":"Image reference the container was created with (e.g.\n`ghcr.io/gotempsh/temps-preview-gateway:latest`)."},"image_digest":{"type":["string","null"],"description":"Image digest if available (e.g. `sha256:…`)."},"last_error":{"type":["string","null"],"description":"Error string Docker recorded for the container (e.g. startup failure)."},"last_exit_code":{"type":["integer","null"],"format":"int64","description":"Exit code of the last run, if the container is not currently running."},"network":{"type":["string","null"],"description":"Network the container is attached to (should be `temps-sandbox-net`)."},"present":{"type":"boolean","description":"Whether the container exists at all."},"restart_count":{"type":["integer","null"],"format":"int64","description":"Number of times Docker has restarted the container."},"running":{"type":"boolean","description":"Whether the container is currently running."},"started_at":{"type":["string","null"],"description":"ISO 8601 timestamp the container was started at, if running."}}},"GenAiEvent":{"type":"object","description":"A GenAI-related event extracted from span events.\n\nCovers `gen_ai.client.inference.operation.details` and `gen_ai.evaluation.result`\nevents per the OTel GenAI semantic conventions.","required":["span_id","trace_id","event_name","timestamp","attributes"],"properties":{"attributes":{"type":"object","description":"All event attributes.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"event_name":{"type":"string"},"span_id":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"trace_id":{"type":"string"}}},"GenAiSpanDetail":{"type":"object","description":"A single GenAI span with extracted semantic convention fields.\n\nFields are aligned with the OpenTelemetry GenAI Semantic Conventions spec:\n","required":["span_id","name","kind","start_time","duration_ms","status_code","attributes"],"properties":{"agent_description":{"type":["string","null"],"description":"Agent description from `gen_ai.agent.description`."},"agent_id":{"type":["string","null"],"description":"Agent identifier from `gen_ai.agent.id`."},"agent_name":{"type":["string","null"],"description":"Agent name from `gen_ai.agent.name`."},"agent_version":{"type":["string","null"],"description":"Agent version from `gen_ai.agent.version`."},"attributes":{"type":"object","description":"All span attributes for extensibility.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"aws_bedrock_guardrail_id":{"type":["string","null"],"description":"AWS Bedrock guardrail ID from `aws.bedrock.guardrail.id`."},"aws_bedrock_knowledge_base_id":{"type":["string","null"],"description":"AWS Bedrock knowledge base ID from `aws.bedrock.knowledge_base.id`."},"azure_resource_provider_namespace":{"type":["string","null"],"description":"Azure resource provider namespace from `azure.resource_provider.namespace`."},"cache_creation_input_tokens":{"type":["integer","null"],"format":"int64","description":"Tokens written to provider cache from `gen_ai.usage.cache_creation.input_tokens`."},"cache_read_input_tokens":{"type":["integer","null"],"format":"int64","description":"Tokens served from provider cache from `gen_ai.usage.cache_read.input_tokens`."},"conversation_id":{"type":["string","null"],"description":"Unique conversation/session/thread ID from `gen_ai.conversation.id`."},"data_source_id":{"type":["string","null"],"description":"Data source identifier from `gen_ai.data_source.id`."},"duration_ms":{"type":"number","format":"double"},"embeddings_dimension_count":{"type":["integer","null"],"format":"int64","description":"Output embedding dimensions from `gen_ai.embeddings.dimension.count`."},"error_type":{"type":["string","null"],"description":"Error type from `error.type` when the span status is ERROR."},"gen_ai_model":{"type":["string","null"],"description":"The requested model from `gen_ai.request.model`."},"gen_ai_operation":{"type":["string","null"],"description":"The operation type from `gen_ai.operation.name` (e.g. \"chat\", \"embeddings\", \"execute_tool\")."},"gen_ai_response_model":{"type":["string","null"],"description":"The model that actually generated the response from `gen_ai.response.model`."},"gen_ai_system":{"type":["string","null"],"description":"The GenAI provider from `gen_ai.provider.name` (falls back to deprecated `gen_ai.system`)."},"input_messages":{"type":["string","null"],"description":"Chat history input from `gen_ai.input.messages` (opt-in, JSON string)."},"input_tokens":{"type":["integer","null"],"format":"int64"},"kind":{"$ref":"#/components/schemas/SpanKind"},"name":{"type":"string"},"openai_api_type":{"type":["string","null"],"description":"OpenAI API type from `openai.api.type` (chat_completions, responses)."},"openai_request_service_tier":{"type":["string","null"],"description":"Requested service tier from `openai.request.service_tier`."},"openai_response_service_tier":{"type":["string","null"],"description":"Actual service tier from `openai.response.service_tier`."},"openai_system_fingerprint":{"type":["string","null"],"description":"System fingerprint from `openai.response.system_fingerprint`."},"output_messages":{"type":["string","null"],"description":"Model output from `gen_ai.output.messages` (opt-in, JSON string)."},"output_tokens":{"type":["integer","null"],"format":"int64"},"output_type":{"type":["string","null"],"description":"Output content type from `gen_ai.output.type` (text, json, image, speech)."},"parent_span_id":{"type":["string","null"]},"request_choice_count":{"type":["integer","null"],"format":"int64","description":"Number of choices requested from `gen_ai.request.choice.count`."},"request_encoding_formats":{"type":["array","null"],"items":{"type":"string"},"description":"Requested encoding formats from `gen_ai.request.encoding_formats`."},"request_frequency_penalty":{"type":["number","null"],"format":"double","description":"Frequency penalty from `gen_ai.request.frequency_penalty`."},"request_max_tokens":{"type":["integer","null"],"format":"int64","description":"Max tokens from `gen_ai.request.max_tokens`."},"request_presence_penalty":{"type":["number","null"],"format":"double","description":"Presence penalty from `gen_ai.request.presence_penalty`."},"request_seed":{"type":["integer","null"],"format":"int64","description":"Seed for reproducibility from `gen_ai.request.seed`."},"request_stop_sequences":{"type":["array","null"],"items":{"type":"string"},"description":"Stop sequences from `gen_ai.request.stop_sequences`."},"request_temperature":{"type":["number","null"],"format":"double","description":"Temperature setting from `gen_ai.request.temperature`."},"request_top_k":{"type":["number","null"],"format":"double","description":"Top-k setting from `gen_ai.request.top_k`."},"request_top_p":{"type":["number","null"],"format":"double","description":"Top-p setting from `gen_ai.request.top_p`."},"response_finish_reasons":{"type":["array","null"],"items":{"type":"string"},"description":"Reasons the model stopped from `gen_ai.response.finish_reasons` (e.g. [\"stop\"])."},"response_id":{"type":["string","null"],"description":"Unique completion ID from `gen_ai.response.id` (e.g. \"chatcmpl-123\")."},"retrieval_documents":{"type":["string","null"],"description":"Retrieved documents from `gen_ai.retrieval.documents` (opt-in, JSON string)."},"retrieval_query_text":{"type":["string","null"],"description":"Retrieval query text from `gen_ai.retrieval.query.text` (opt-in)."},"server_address":{"type":["string","null"],"description":"GenAI server address from `server.address`."},"server_port":{"type":["integer","null"],"format":"int64","description":"GenAI server port from `server.port`."},"span_id":{"type":"string"},"start_time":{"type":"string","format":"date-time"},"status_code":{"$ref":"#/components/schemas/SpanStatusCode"},"system_instructions":{"type":["string","null"],"description":"System instructions from `gen_ai.system_instructions` (opt-in, JSON string)."},"tool_call_arguments":{"type":["string","null"],"description":"Tool call arguments from `gen_ai.tool.call.arguments` (opt-in, JSON string)."},"tool_call_id":{"type":["string","null"],"description":"Tool call ID from `gen_ai.tool.call.id`."},"tool_call_result":{"type":["string","null"],"description":"Tool call result from `gen_ai.tool.call.result` (opt-in, JSON string)."},"tool_definitions":{"type":["string","null"],"description":"Tool definitions from `gen_ai.tool.definitions` (opt-in, JSON string)."},"tool_description":{"type":["string","null"],"description":"Tool description from `gen_ai.tool.description`."},"tool_name":{"type":["string","null"],"description":"Tool name from `gen_ai.tool.name`."},"tool_type":{"type":["string","null"],"description":"Tool type from `gen_ai.tool.type` (function, extension, datastore)."}}},"GenAiTraceDetailResponse":{"type":"object","required":["trace_id","spans","span_count","events","event_count"],"properties":{"event_count":{"type":"integer","minimum":0},"events":{"type":"array","items":{"$ref":"#/components/schemas/GenAiEvent"}},"span_count":{"type":"integer","minimum":0},"spans":{"type":"array","items":{"$ref":"#/components/schemas/GenAiSpanDetail"}},"trace_id":{"type":"string"}}},"GenAiTraceSummariesResponse":{"type":"object","required":["data","total"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/GenAiTraceSummary"}},"total":{"type":"integer","format":"int64","minimum":0}}},"GenAiTraceSummary":{"type":"object","description":"Summary of a GenAI conversation — aggregated from OTel spans with `gen_ai.*` attributes.","required":["trace_id","root_span_name","service_name","start_time","duration_ms","span_count","error_count"],"properties":{"duration_ms":{"type":"number","format":"double"},"error_count":{"type":"integer","format":"int64"},"gen_ai_model":{"type":["string","null"],"description":"The requested model from `gen_ai.request.model`."},"gen_ai_operation":{"type":["string","null"],"description":"The operation type from `gen_ai.operation.name` (e.g. \"chat\", \"embeddings\")."},"gen_ai_system":{"type":["string","null"],"description":"The GenAI provider (e.g. \"openai\", \"anthropic\") from `gen_ai.provider.name`."},"root_span_name":{"type":"string"},"service_name":{"type":"string"},"span_count":{"type":"integer","format":"int64"},"start_time":{"type":"string","format":"date-time"},"total_cache_creation_input_tokens":{"type":["integer","null"],"format":"int64","description":"Total cache-creation input tokens across all spans."},"total_cache_read_input_tokens":{"type":["integer","null"],"format":"int64","description":"Total cache-read input tokens across all spans."},"total_input_tokens":{"type":["integer","null"],"format":"int64","description":"Total input tokens across all spans in this trace."},"total_output_tokens":{"type":["integer","null"],"format":"int64","description":"Total output tokens across all spans in this trace."},"trace_id":{"type":"string"}}},"GeneralStatsQuery":{"type":"object","required":["start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"start_date":{"type":"string","format":"date-time"}}},"GeneralStatsResponse":{"type":"object","required":["total_unique_visitors","total_visits","total_page_views","total_events","total_projects","avg_bounce_rate","avg_engagement_rate","project_breakdown"],"properties":{"avg_bounce_rate":{"type":"number","format":"double"},"avg_engagement_rate":{"type":"number","format":"double"},"page_views_trend_percentage":{"type":["number","null"],"format":"double","description":"Percentage change in page views vs previous period"},"previous_page_views":{"type":["integer","null"],"format":"int64","description":"Previous period page views"},"previous_unique_visitors":{"type":["integer","null"],"format":"int64","description":"Previous period unique visitors (same duration, shifted back)"},"project_breakdown":{"type":"array","items":{"$ref":"#/components/schemas/ProjectStatsBreakdown"}},"total_events":{"type":"integer","format":"int64"},"total_page_views":{"type":"integer","format":"int64"},"total_projects":{"type":"integer","format":"int64"},"total_unique_visitors":{"type":"integer","format":"int64"},"total_visits":{"type":"integer","format":"int64"},"visitors_trend_percentage":{"type":["number","null"],"format":"double","description":"Percentage change in unique visitors vs previous period"}}},"GenerateDockerfileRequest":{"type":"object","description":"Request body for generating a Dockerfile from a preset","properties":{"build_command":{"type":["string","null"],"description":"Custom build command (overrides preset default)","example":"npm run build"},"install_command":{"type":["string","null"],"description":"Custom install command (overrides preset default)","example":"npm ci"},"output_dir":{"type":["string","null"],"description":"Output directory for static builds","example":"dist"},"package_manager":{"type":["string","null"],"description":"Package manager used by the project (npm, yarn, pnpm, bun)\nIf not provided, defaults to npm","example":"npm"},"project_name":{"type":["string","null"],"description":"Project name/slug used for container naming","example":"my-app"},"use_buildkit":{"type":"boolean","description":"Whether to use BuildKit cache mounts for faster builds"}}},"GenerateDockerfileResponse":{"type":"object","description":"Response containing a generated Dockerfile and build arguments","required":["dockerfile","build_args","preset"],"properties":{"build_args":{"type":"object","description":"Build arguments to pass to `docker build --build-arg KEY=VALUE`","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"dockerfile":{"type":"string","description":"The generated Dockerfile content"},"preset":{"type":"string","description":"The preset slug used for generation"}}},"GenerateJoinTokenResponse":{"type":"object","description":"Response returned when a join token is generated (plaintext shown once)","required":["token","message"],"properties":{"message":{"type":"string"},"token":{"type":"string","description":"The plaintext join token — shown only once, save it now"}}},"GeoLocationResponse":{"type":"object","description":"Response containing geolocation information for an IP address","required":["ip","is_eu"],"properties":{"city":{"type":["string","null"],"description":"City name","example":"Mountain View"},"country":{"type":["string","null"],"description":"Country name","example":"United States"},"country_code":{"type":["string","null"],"description":"ISO country code (2 letters)","example":"US"},"ip":{"type":"string","description":"IP address that was geolocated","example":"8.8.8.8"},"is_eu":{"type":"boolean","description":"Whether the IP is in the European Union","example":false},"latitude":{"type":["number","null"],"format":"double","description":"Latitude coordinate","example":37.386},"longitude":{"type":["number","null"],"format":"double","description":"Longitude coordinate","example":-122.0838},"region":{"type":["string","null"],"description":"Region/state name","example":"California"},"timezone":{"type":["string","null"],"description":"Timezone identifier","example":"America/Los_Angeles"}}},"GeoRestrictionsConfig":{"type":"object","description":"Geographic restrictions configuration (future feature)","properties":{"allowedCountries":{"type":"array","items":{"type":"string"},"description":"Allow traffic only from specific countries"},"blockedCountries":{"type":"array","items":{"type":"string"},"description":"Block traffic from specific countries (ISO 3166-1 alpha-2 codes)"}}},"GetDeploymentsParams":{"type":"object","properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"page":{"type":["integer","null"],"format":"int64"},"per_page":{"type":["integer","null"],"format":"int64"}}},"GetEnvironmentVariablesQuery":{"type":"object","properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"service_id":{"type":["integer","null"],"format":"int32","description":"Required by integration-value reveals to bind the plaintext response to\nthe exact service displayed by the client."},"var_id":{"type":["integer","null"],"format":"int32","description":"Exact manual env-var row to reveal. Required by the dashboard so\nduplicate keys on disjoint environments cannot cross-reveal."}}},"GetFunnelMetricsQuery":{"type":"object","properties":{"country_code":{"type":["string","null"]},"end_date":{"type":["string","null"],"format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"start_date":{"type":["string","null"],"format":"date-time"}}},"GetOrCreateDSNRequest":{"type":"object","properties":{"base_url":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"}}},"GetProjectSecretsQuery":{"type":"object","properties":{"environment_id":{"type":["integer","null"],"format":"int32"}}},"GetProjectSessionReplaysQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0},"project_id":{"type":"integer","format":"int32"}}},"GetProjectSessionReplaysResponse":{"type":"object","required":["sessions","page","per_page","total_count"],"properties":{"page":{"type":"integer","format":"int64","minimum":0},"per_page":{"type":"integer","format":"int64","minimum":0},"sessions":{"type":"array","items":{"$ref":"#/components/schemas/SessionReplayWithVisitorDto"}},"total_count":{"type":"integer","format":"int64","minimum":0}}},"GetRequest":{"type":"object","description":"Request to get a value by key","required":["key"],"properties":{"key":{"type":"string","description":"The key to retrieve","example":"user:123"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"GetResponse":{"type":"object","description":"Response for get operation","properties":{"value":{"description":"The value, or null if not found"}}},"GetSessionReplayResponse":{"type":"object","required":["session"],"properties":{"session":{"$ref":"#/components/schemas/SessionReplayWithVisitorDto"}}},"GetUniqueEventsQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","minimum":0},"page_size":{"type":["integer","null"],"format":"int64","minimum":0}}},"GetVisitorSessionsQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0}}},"GetVisitorSessionsResponse":{"type":"object","required":["sessions","page","per_page","total_count"],"properties":{"page":{"type":"integer","format":"int64","minimum":0},"per_page":{"type":"integer","format":"int64","minimum":0},"sessions":{"type":"array","items":{"$ref":"#/components/schemas/SessionReplayWithVisitorDto"}},"total_count":{"type":"integer","minimum":0}}},"GitPushEvent":{"type":"object","description":"Git push event information that triggered the deployment","required":["repo","owner","branch","commit"],"properties":{"branch":{"type":"string","description":"Branch that was pushed"},"commit":{"type":"string","description":"Commit SHA"},"owner":{"type":"string","description":"Repository owner/organization"},"repo":{"type":"string","description":"Repository name"}}},"GitRefResponse":{"type":"object","description":"Git repository reference response","required":["url","ref"],"properties":{"path":{"type":["string","null"],"description":"Path within the repository (for monorepos)"},"ref":{"type":"string","description":"Git reference (branch, tag, or commit)"},"url":{"type":"string","description":"Git repository URL"}}},"GitSourcePlan":{"type":"object","description":"Git repository the source platform deploys from","required":["owner","repo","branch","is_public"],"properties":{"branch":{"type":"string","description":"Branch the source platform deploys"},"clone_url":{"type":["string","null"],"description":"Full clone URL, e.g. `https://github.com/owner/repo.git`"},"is_public":{"type":"boolean","description":"True when the repository is public (no credentials on the source\nplatform) — the project can then build without a git provider\nconnection."},"owner":{"type":"string","description":"Repository owner (organization or user)"},"repo":{"type":"string","description":"Repository name"}}},"GlobalConversationResponse":{"type":"object","description":"A conversation in the unified cross-project switcher: carries the project it\nbelongs to (name/slug) so the UI can show where the chat was started and\nlink back to the source.","required":["public_id","project_id","context_type","context_id","status","created_at","last_activity_at"],"properties":{"context_id":{"type":"string"},"context_type":{"type":"string"},"created_at":{"type":"string"},"last_activity_at":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":["string","null"]},"project_slug":{"type":["string","null"]},"public_id":{"type":"string"},"status":{"type":"string"},"title":{"type":["string","null"]}}},"GlobalEventStatsResponse":{"type":"object","required":["delivered","opened","clicked","bounced","complained"],"properties":{"bounce_rate":{"type":["number","null"],"format":"double"},"bounced":{"type":"integer","format":"int64","minimum":0},"click_rate":{"type":["number","null"],"format":"double"},"clicked":{"type":"integer","format":"int64","minimum":0},"complained":{"type":"integer","format":"int64","minimum":0},"delivered":{"type":"integer","format":"int64","minimum":0},"open_rate":{"type":["number","null"],"format":"double"},"opened":{"type":"integer","format":"int64","minimum":0}}},"GlobalMrrResponse":{"type":"object","required":["currency","current_mrr_minor","previous_mrr_minor"],"properties":{"change_percentage":{"type":["number","null"],"format":"double","description":"Percentage change vs 24h ago. Null when previous MRR is zero\n(no baseline to compare against)."},"currency":{"type":"string"},"current_mrr_minor":{"type":"integer","format":"int64"},"previous_mrr_minor":{"type":"integer","format":"int64","description":"MRR 24h before now, reconstructed from the event log."}}},"GlobalRecentEventResponse":{"type":"object","required":["id","project_id","project_name","occurred_at","event_type"],"properties":{"amount_minor":{"type":["integer","null"],"format":"int64"},"currency":{"type":["string","null"]},"customer_ref":{"type":["string","null"]},"event_type":{"type":"string"},"id":{"type":"integer","format":"int64"},"mrr_minor":{"type":["integer","null"],"format":"int64"},"occurred_at":{"type":"string","format":"date-time"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"}}},"GlobalRevenueSummaryResponse":{"type":"object","required":["currency","current_mrr_minor","paid_last_30d_minor","refunded_last_30d_minor","paid_all_time_minor","refunded_all_time_minor","active_subscriptions","active_customers","transactions_last_30d"],"properties":{"active_customers":{"type":"integer","format":"int64"},"active_subscriptions":{"type":"integer","format":"int64"},"currency":{"type":"string"},"current_mrr_minor":{"type":"integer","format":"int64"},"paid_all_time_minor":{"type":"integer","format":"int64"},"paid_last_30d_minor":{"type":"integer","format":"int64"},"refunded_all_time_minor":{"type":"integer","format":"int64"},"refunded_last_30d_minor":{"type":"integer","format":"int64"},"transactions_last_30d":{"type":"integer","format":"int64"}}},"GroupedPageMetric":{"type":"object","required":["group_key","events"],"properties":{"cls":{"type":["number","null"],"format":"float"},"country_code":{"type":["string","null"],"description":"ISO 3166-1 alpha-2 code of the group's country. Populated for the\ngeographic dimensions (country/region/city) so clients can match map\ngeometries without name-based lookups; null otherwise."},"events":{"type":"integer","format":"int64"},"fcp":{"type":["number","null"],"format":"float"},"group_key":{"type":"string"},"inp":{"type":["number","null"],"format":"float"},"lcp":{"type":["number","null"],"format":"float"},"ttfb":{"type":["number","null"],"format":"float"}}},"GroupedPageMetricsQuery":{"allOf":[{"$ref":"#/components/schemas/SpeedSegmentFilters","description":"Segment filters — same shape as `PerformanceMetricsQuery`."},{"type":"object","required":["start_date","end_date","project_id","group_by"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"device_type":{"type":["string","null"],"description":"Device type filter: \"desktop\" or \"mobile\""},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"group_by":{"type":"string"},"include_bots":{"type":["boolean","null"],"description":"Include crawler/datacenter (bot) samples. Defaults to false."},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}}]},"GroupedPageMetricsResponse":{"type":"object","required":["groups","total_events","grouped_by"],"properties":{"grouped_by":{"type":"string"},"groups":{"type":"array","items":{"$ref":"#/components/schemas/GroupedPageMetric"}},"total_events":{"type":"integer","format":"int64"}}},"HasAnalyticsEventsResponse":{"type":"object","required":["has_events"],"properties":{"has_events":{"type":"boolean"}}},"HasErrorGroupsResponse":{"type":"object","required":["has_error_groups"],"properties":{"has_error_groups":{"type":"boolean"}}},"HasEventsQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"HasEventsResponse":{"type":"object","required":["has_events"],"properties":{"has_events":{"type":"boolean"}}},"HasMetricsQuery":{"type":"object","required":["project_id"],"properties":{"project_id":{"type":"integer","format":"int32"}}},"HasMetricsResponse":{"type":"object","required":["has_metrics"],"properties":{"has_metrics":{"type":"boolean"}}},"HealthCheckConfiguration":{"type":"object","description":"Health check configuration","required":["port","interval","timeout","retries"],"properties":{"http_path":{"type":["string","null"],"description":"HTTP path to check (if applicable)"},"interval":{"type":"integer","format":"int32","description":"Interval between checks (seconds)","minimum":0},"port":{"type":"integer","format":"int32","description":"Port to check","minimum":0},"retries":{"type":"integer","format":"int32","description":"Number of retries before marking unhealthy","minimum":0},"timeout":{"type":"integer","format":"int32","description":"Timeout for each check (seconds)","minimum":0}}},"HealthCheckEntryResponse":{"type":"object","required":["checked_at","status"],"properties":{"checked_at":{"type":"string","description":"ISO 8601 timestamp of when the probe ran.","example":"2026-04-22T11:30:00Z"},"error_message":{"type":["string","null"],"description":"Present only when the probe failed or was degraded."},"response_time_ms":{"type":["integer","null"],"format":"int32","description":"TCP connect latency in milliseconds."},"status":{"type":"string","description":"\"operational\" | \"degraded\" | \"down\"","example":"operational"}}},"HealthResponse":{"type":"object","required":["summaries"],"properties":{"summaries":{"type":"array","items":{"$ref":"#/components/schemas/HealthSummary"}}}},"HealthStatus":{"type":"string","description":"Overall health status.","enum":["healthy","degraded","down","unknown"]},"HealthSummary":{"type":"object","description":"Pre-computed health summary for a project environment.","required":["project_id","service_name","status","uptime_pct","error_rate","p95_latency_ms","cpu_usage_pct","memory_usage_pct","computed_at"],"properties":{"computed_at":{"type":"string","format":"date-time"},"cpu_usage_pct":{"type":"number","format":"double"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_rate":{"type":"number","format":"double"},"last_deploy_at":{"type":["string","null"],"format":"date-time"},"last_deploy_id":{"type":["integer","null"],"format":"int32"},"memory_usage_pct":{"type":"number","format":"double"},"p95_latency_ms":{"type":"number","format":"double"},"project_id":{"type":"integer","format":"int32"},"service_name":{"type":"string"},"status":{"$ref":"#/components/schemas/HealthStatus"},"uptime_pct":{"type":"number","format":"double"}}},"HeartbeatApiRequest":{"type":"object","properties":{"architecture":{"type":["string","null"],"description":"Container platform of this node's Docker daemon (`linux/amd64`,\n`linux/arm64`), read from `docker info` by the agent. Absent from\npre-multi-arch agents; the stored value is then left untouched."},"capacity":{"description":"Resource capacity/usage info as JSON (cpu_usage, memory_usage, etc.)"},"containers":{"type":["array","null"],"items":{"$ref":"#/components/schemas/ContainerInventoryItem"},"description":"Container inventory for reconciliation (sent on first heartbeat after agent startup).\nEach entry has `container_id` and `container_name` of temps-managed containers."},"labels":{"description":"Updated node labels for scheduling (allows runtime label changes)."}}},"HeartbeatResponse":{"type":"object","required":["status","message"],"properties":{"message":{"type":"string"},"status":{"type":"string"}}},"HierarchyLevel":{"type":"object","description":"Describes a level in the data source hierarchy","required":["level","name","container_type","can_list_containers","can_list_entities"],"properties":{"can_list_containers":{"type":"boolean","description":"Can list containers at this level?","example":true},"can_list_entities":{"type":"boolean","description":"Can list entities at this level?","example":false},"container_type":{"type":"string","description":"Type of container at this level","example":"database"},"level":{"type":"integer","format":"int32","description":"Level number (0 = root)","example":0,"minimum":0},"name":{"type":"string","description":"Human-readable name for this level","example":"root"}}},"HistogramSummary":{"type":"object","description":"An explicit-bucket histogram aggregated over a time bucket.\n\nCarries the reduced scalars (count/sum/min/max) plus the explicit bucket\nlayout — `bounds` (the upper bounds) and `bucket_counts` (observation counts,\nsummed element-wise across the window; length is `bounds.len() + 1`, the last\nentry being the +Inf overflow bucket). With these, a caller can reconstruct\nany quantile (e.g. p95) via cumulative-count interpolation.","required":["count","sum","bounds","bucket_counts"],"properties":{"bounds":{"type":"array","items":{"type":"number","format":"double"},"description":"Explicit bucket upper bounds (OTLP `explicit_bounds`), ascending."},"bucket_counts":{"type":"array","items":{"type":"integer","format":"int64","minimum":0},"description":"Per-bucket observation counts summed element-wise across the window.\nLength is `bounds.len() + 1` (the trailing element is the +Inf bucket)."},"count":{"type":"integer","format":"int64","description":"Total observation count summed across the bucket window.","minimum":0},"max":{"type":["number","null"],"format":"double","description":"Maximum observed value, when reported by the producer."},"min":{"type":["number","null"],"format":"double","description":"Minimum observed value, when reported by the producer."},"sum":{"type":"number","format":"double","description":"Sum of observed values across the bucket window."}}},"HostnameChange":{"type":"object","description":"A single generated-hostname change in a flatten preview/apply.","required":["kind","id","old","new"],"properties":{"id":{"type":"integer","format":"int32","description":"Row id of the affected record."},"kind":{"type":"string","description":"`\"deployment\"` or `\"environment\"`."},"new":{"type":"string"},"old":{"type":"string"}}},"HostnamePreviewResponse":{"type":"object","description":"Combined preview of a hostname-mode change.","required":["hostname_changes","dns_changes","total"],"properties":{"dns_changes":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecordChange"}},"hostname_changes":{"type":"array","items":{"$ref":"#/components/schemas/HostnameChange"}},"total":{"type":"integer","minimum":0},"zone_access_ok":{"type":["boolean","null"],"description":"Whether the provider token can manage this zone (None if not checked)."}}},"HourlyPageSessions":{"type":"object","required":["timestamp","session_count","event_count","avg_duration_seconds"],"properties":{"avg_duration_seconds":{"type":"number","format":"double"},"event_count":{"type":"integer","format":"int64"},"session_count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"}}},"HourlyVisitsQuery":{"type":"object","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events (page views), sessions (unique sessions), or visitors (unique visitors)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"HttpChallengeDebugResponse":{"type":"object","required":["domain","challenge_exists","dns_a_records","dns_aaaa_records"],"properties":{"challenge_exists":{"type":"boolean"},"challenge_token":{"type":["string","null"]},"challenge_url":{"type":["string","null"],"description":"The full URL that Let's Encrypt will try to access to validate the challenge"},"dns_a_records":{"type":"array","items":{"type":"string"},"description":"IPv4 addresses the domain points to"},"dns_aaaa_records":{"type":"array","items":{"type":"string"},"description":"IPv6 addresses the domain points to"},"dns_error":{"type":["string","null"],"description":"Any DNS resolution errors"},"domain":{"type":"string"},"validation_url":{"type":["string","null"],"description":"The ACME validation URL (internal to ACME protocol)"}}},"ImportCredentials":{"type":"object","description":"Platform-specific credentials for accessing the source system.\n\nFor platforms like Vercel and Railway, this contains the API token.\nFor self-hosted platforms like Coolify and Dokploy, this also contains\nthe `base_url` of the instance.\n\nLocal importers (Docker) can use `ImportCredentials::none()`.","properties":{"base_url":{"type":["string","null"],"description":"Base URL override (for self-hosted platforms like Coolify, Dokploy)\n\nExample: `https://coolify.example.com`"},"extra":{"type":"object","description":"Additional platform-specific parameters","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"team_id":{"type":["string","null"],"description":"Team or organization ID (for platforms with team scoping like Vercel)"},"token":{"type":["string","null"],"description":"API token / bearer token for the source platform"}}},"ImportExecutionStatus":{"type":"string","description":"Import execution status","enum":["pending","inprogress","completed","failed"]},"ImportExternalServiceRequest":{"type":"object","description":"Request to import a Docker container as a managed service","required":["name","service_type","parameters","container_id"],"properties":{"container_id":{"type":"string","description":"Container ID or name to import","example":"abc123def456"},"name":{"type":"string","description":"Name to register the service as in Temps","example":"production-database"},"parameters":{"type":"object","description":"Service configuration parameters","additionalProperties":{},"propertyNames":{"type":"string"}},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute","description":"Service type"},"version":{"type":["string","null"],"description":"Optional version override"}}},"ImportOutcomeResponse":{"type":"object","required":["rows_read","inserted","updated","skipped_stale","skipped_invalid","errors"],"properties":{"errors":{"type":"array","items":{"$ref":"#/components/schemas/ImportRowErrorResponse"}},"inserted":{"type":"integer","minimum":0},"rows_read":{"type":"integer","minimum":0},"skipped_invalid":{"type":"integer","minimum":0},"skipped_stale":{"type":"integer","minimum":0},"updated":{"type":"integer","minimum":0}}},"ImportPlan":{"type":"object","description":"Complete import plan describing all operations to onboard a workload.\n\nThe plan is generated from a snapshot and presented to the user for review\nbefore any resources are created. Users can modify individual items\n(skip services, change actions) before approving execution.","required":["version","source","source_id","project","environment","deployment","summary","metadata"],"properties":{"additional_deployments":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentConfiguration"},"description":"Additional deployments (workers, cron jobs, etc.)"},"cost_analysis":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/CostAnalysis","description":"Cost, overprovisioning, and savings analysis. Populated by importers\nthat can observe the whole source cluster (currently Kubernetes);\n`None` for container/platform imports."}]},"deployment":{"$ref":"#/components/schemas/DeploymentConfiguration","description":"Primary deployment configuration"},"domains":{"type":"array","items":{"$ref":"#/components/schemas/DomainPlan"},"description":"Custom domains to migrate"},"environment":{"$ref":"#/components/schemas/EnvironmentConfiguration","description":"Environment configuration"},"metadata":{"$ref":"#/components/schemas/PlanMetadata","description":"Plan metadata"},"project":{"$ref":"#/components/schemas/ProjectConfiguration","description":"Project configuration"},"services":{"type":"array","items":{"$ref":"#/components/schemas/ServicePlan"},"description":"Services to migrate (databases, caches, blob stores)\n\nEach service has an `action` field the user can change before execution."},"source":{"type":"string","description":"Source system this plan was generated from"},"source_id":{"type":"string","description":"Source workload / project ID in the source system"},"steps":{"type":"array","items":{"$ref":"#/components/schemas/MigrationStep"},"description":"Ordered list of migration steps that will be executed.\n\nThis is the human-readable execution plan. Each step describes what\nwill happen, what risks are involved, and what the user should verify.\nSteps are executed in order. If a step fails, execution stops and\nalready-created resources are reported for manual cleanup."},"summary":{"$ref":"#/components/schemas/MigrationSummary","description":"Human-readable summary of the entire migration"},"version":{"type":"string","description":"Plan version for compatibility tracking"}}},"ImportRowErrorResponse":{"type":"object","required":["row","reason"],"properties":{"reason":{"type":"string"},"row":{"type":"integer","minimum":0}}},"ImportSelector":{"type":"object","description":"Selector for discovering workloads","properties":{"label_filter":{"type":["object","null"],"description":"Filter by labels/tags","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"limit":{"type":["integer","null"],"description":"Limit number of results","minimum":0},"name_pattern":{"type":["string","null"],"description":"Filter by name pattern (glob/regex)"},"status_filter":{"type":["array","null"],"items":{"type":"string"},"description":"Filter by status (running, stopped, deployed, etc.)"},"workload_type_filter":{"type":["array","null"],"items":{"type":"string"},"description":"Filter by workload type (container, function, static-site, etc.)"}}},"ImportSource":{"type":"string","description":"Import source identifier","enum":["docker","coolify","dokploy","vercel","netlify","railway","render","fly","kubernetes","caprover","portainer","kamal","custom"]},"ImportSourceCapabilities":{"type":"object","description":"Source capabilities","required":["supports_volumes","supports_networks","supports_health_checks","supports_resource_limits","supports_build","supports_services","supports_domains","supports_project_snapshot","supports_cost_analysis","requires_credentials"],"properties":{"requires_credentials":{"type":"boolean","description":"Whether this source requires API credentials (token, base URL)"},"supports_build":{"type":"boolean"},"supports_cost_analysis":{"type":"boolean","description":"Supports cluster cost + overprovisioning analysis in the plan"},"supports_domains":{"type":"boolean","description":"Supports custom domain migration"},"supports_health_checks":{"type":"boolean"},"supports_networks":{"type":"boolean"},"supports_project_snapshot":{"type":"boolean","description":"Supports full project-level snapshots"},"supports_resource_limits":{"type":"boolean"},"supports_services":{"type":"boolean","description":"Supports service migration (databases, caches, etc.)"},"supports_volumes":{"type":"boolean"}}},"ImportSourceInfo":{"type":"object","description":"Information about an import source","required":["source","name","version","available","capabilities"],"properties":{"available":{"type":"boolean","description":"Whether the source is currently available"},"capabilities":{"$ref":"#/components/schemas/ImportSourceCapabilities","description":"Capabilities"},"name":{"type":"string","description":"Human-readable name"},"source":{"$ref":"#/components/schemas/ImportSource","description":"Source identifier"},"version":{"type":"string","description":"Source version"}}},"ImportStatusResponse":{"type":"object","description":"Response with import status","required":["session_id","status","errors","warnings","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","description":"Created at timestamp"},"deployment_id":{"type":["integer","null"],"format":"int32","description":"Created deployment ID"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Created environment ID"},"errors":{"type":"array","items":{"type":"string"},"description":"Errors (if any)"},"plan":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ImportPlan","description":"Import plan"}]},"project_id":{"type":["integer","null"],"format":"int32","description":"Created project ID"},"session_id":{"type":"string","description":"Session ID"},"status":{"$ref":"#/components/schemas/ImportExecutionStatus","description":"Current status"},"updated_at":{"type":"string","format":"date-time","description":"Updated at timestamp"},"validation":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ValidationReport","description":"Validation report"}]},"warnings":{"type":"array","items":{"type":"string"},"description":"Warnings (if any)"}}},"IncidentBucket":{"type":"object","required":["bucket_start","total_incidents","minor_incidents","major_incidents","critical_incidents","resolved_incidents","active_incidents"],"properties":{"active_incidents":{"type":"integer","format":"int64"},"avg_resolution_time_minutes":{"type":["number","null"],"format":"double"},"bucket_start":{"type":"string","format":"date-time"},"critical_incidents":{"type":"integer","format":"int64"},"major_incidents":{"type":"integer","format":"int64"},"minor_incidents":{"type":"integer","format":"int64"},"resolved_incidents":{"type":"integer","format":"int64"},"total_incidents":{"type":"integer","format":"int64"}}},"IncidentBucketedResponse":{"type":"object","required":["project_id","interval","buckets"],"properties":{"buckets":{"type":"array","items":{"$ref":"#/components/schemas/IncidentBucket"}},"environment_id":{"type":["integer","null"],"format":"int32"},"interval":{"type":"string"},"project_id":{"type":"integer","format":"int32"}}},"IncidentResponse":{"type":"object","required":["id","project_id","title","severity","status","started_at","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time"},"description":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"monitor_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"resolved_at":{"type":["string","null"],"format":"date-time"},"severity":{"type":"string"},"started_at":{"type":"string","format":"date-time"},"status":{"type":"string"},"title":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}},"IncidentUpdateResponse":{"type":"object","required":["id","incident_id","status","message","created_at"],"properties":{"created_at":{"type":"string","format":"date-time"},"id":{"type":"integer","format":"int32"},"incident_id":{"type":"integer","format":"int32"},"message":{"type":"string"},"status":{"type":"string"}}},"IncrRequest":{"type":"object","description":"Request to increment a value","required":["key"],"properties":{"amount":{"type":["integer","null"],"format":"int64","description":"Amount to increment by (default: 1)"},"key":{"type":"string","description":"The key to increment","example":"counter"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"IncrResponse":{"type":"object","description":"Response for increment operation","required":["value"],"properties":{"value":{"type":"integer","format":"int64","description":"New value after increment","example":42}}},"InitAuthResponse":{"type":"object","required":["auth_url","session_token"],"properties":{"auth_url":{"type":"string"},"session_token":{"type":"string"}}},"Insight":{"type":"object","description":"An anomaly insight.","required":["id","project_id","service_name","severity","status","title","description","anomaly_ids","started_at","created_at","updated_at"],"properties":{"anomaly_ids":{"type":"array","items":{"type":"integer","format":"int64"}},"correlated_deploy_id":{"type":["integer","null"],"format":"int32"},"created_at":{"type":"string","format":"date-time"},"description":{"type":"string"},"environment":{"type":["string","null"]},"id":{"type":"integer","format":"int64"},"metric_name":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"resolved_at":{"type":["string","null"],"format":"date-time"},"service_name":{"type":"string"},"severity":{"$ref":"#/components/schemas/InsightSeverity"},"started_at":{"type":"string","format":"date-time"},"status":{"$ref":"#/components/schemas/InsightStatus"},"title":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}},"InsightSeverity":{"type":"string","description":"Severity of an anomaly insight.","enum":["low","medium","high","critical"]},"InsightStatus":{"type":"string","description":"Status of an insight.","enum":["active","resolved"]},"InsightsResponse":{"type":"object","required":["data","count"],"properties":{"count":{"type":"integer","minimum":0},"data":{"type":"array","items":{"$ref":"#/components/schemas/Insight"}}}},"IntegrationResponse":{"type":"object","required":["id","project_id","provider","webhook_path_token","webhook_path","status","has_secret","created_at"],"properties":{"config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ProviderConfig","description":"Typed provider config — allowlist and metered-billing mode. Null\nwhen the operator hasn't configured one yet (accept everything)."}]},"created_at":{"type":"string","format":"date-time"},"has_secret":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"last_event_at":{"type":["string","null"],"format":"date-time"},"project_id":{"type":"integer","format":"int32"},"provider":{"type":"string"},"status":{"type":"string"},"webhook_path":{"type":"string","description":"Relative path the UI can display and copy. The frontend builds\nthe full URL by prefixing its own origin."},"webhook_path_token":{"type":"string","description":"Unguessable token embedded in the public webhook URL. The full\nURL is `{api_origin}/webhooks/revenue/{provider}/{webhook_path_token}`."}}},"IpAccessControlQuery":{"type":"object","description":"Query parameters for listing IP access control rules","properties":{"action":{"type":["string","null"],"description":"Filter by action (\"block\" or \"allow\")"}}},"IpAccessControlResponse":{"type":"object","description":"Response model for IP access control rules","required":["id","ip_address","action","created_at","updated_at"],"properties":{"action":{"type":"string"},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609Z"},"created_by":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":"string"},"reason":{"type":["string","null"]},"updated_at":{"type":"string","example":"2025-10-12T12:15:47.609Z"}}},"JobStatusResponse":{"type":"object","description":"Snapshot of a background job. `status` is one of \"running\" | \"exited\"\n| \"failed\"; `exit_code` is populated only when `status == \"exited\"`.","required":["status","stdout","stderr"],"properties":{"exit_code":{"type":["integer","null"],"format":"int32"},"reason":{"type":["string","null"]},"status":{"type":"string"},"stderr":{"type":"string"},"stdout":{"type":"string"}}},"JobSummaryResponse":{"type":"object","description":"Row in the jobs list. Omits stdout/stderr so a noisy dev server doesn't\nbloat the list payload — callers drill into `GET /jobs/{id}` for the\nfull buffer.","required":["id","status","cmd","started_at"],"properties":{"cmd":{"type":"string"},"exit_code":{"type":["integer","null"],"format":"int32"},"id":{"type":"string"},"reason":{"type":["string","null"]},"started_at":{"type":"string"},"status":{"type":"string"}}},"JoinTokenStatusResponse":{"type":"object","description":"Response for join token status check","required":["has_token"],"properties":{"has_token":{"type":"boolean","description":"Whether a join token has been configured"}}},"JourneyEvent":{"type":"object","description":"A single event in the visitor journey timeline","required":["id","event_type","event_name","occurred_at","is_entry","is_exit","is_bounce"],"properties":{"event_data":{"description":"Custom event properties (for custom events)"},"event_name":{"type":"string","description":"Resolved event name (event_name for custom events, event_type for system events)"},"event_type":{"type":"string","description":"Event type: \"page_view\", \"page_leave\", \"custom\", \"web_vitals\""},"id":{"type":"integer","format":"int64","description":"Event ID"},"is_bounce":{"type":"boolean","description":"Whether this was a bounce"},"is_entry":{"type":"boolean","description":"Whether this is the entry page of the session"},"is_exit":{"type":"boolean","description":"Whether this is the exit page of the session"},"occurred_at":{"type":"string","format":"date-time","description":"When the event occurred"},"page_path":{"type":["string","null"],"description":"Page path where the event happened"},"page_title":{"type":["string","null"],"description":"Page title (if available)"},"referrer":{"type":["string","null"],"description":"Referrer URL for this event"},"scroll_depth":{"type":["integer","null"],"format":"int32","description":"Scroll depth percentage (0-100)"},"session_page_number":{"type":["integer","null"],"format":"int32","description":"Page number within the session (1-indexed)"},"time_on_page":{"type":["integer","null"],"format":"int32","description":"Time spent on page in seconds (computed, not from column)"}}},"JourneySession":{"type":"object","description":"A session within the visitor journey, grouping events","required":["session_id","started_at","duration_seconds","page_views","events_count","is_bounced","is_engaged","events"],"properties":{"channel":{"type":["string","null"],"description":"Traffic source: channel (e.g. \"organic\", \"direct\", \"social\")"},"duration_seconds":{"type":"integer","format":"int64","description":"Session duration in seconds"},"ended_at":{"type":["string","null"],"format":"date-time","description":"When the session ended"},"entry_path":{"type":["string","null"],"description":"Entry page path"},"events":{"type":"array","items":{"$ref":"#/components/schemas/JourneyEvent"},"description":"Events within this session, ordered chronologically"},"events_count":{"type":"integer","format":"int64","description":"Total events in this session"},"exit_path":{"type":["string","null"],"description":"Exit page path"},"is_bounced":{"type":"boolean","description":"Whether the session was a bounce"},"is_engaged":{"type":"boolean","description":"Whether the visitor was engaged (had non-pageview events)"},"page_views":{"type":"integer","format":"int64","description":"Number of page views in this session"},"referrer":{"type":["string","null"],"description":"Traffic source: referrer URL"},"referrer_hostname":{"type":["string","null"],"description":"Traffic source: referrer hostname"},"session_id":{"type":"integer","format":"int32","description":"Session internal ID"},"started_at":{"type":"string","format":"date-time","description":"When the session started"},"utm_campaign":{"type":["string","null"],"description":"UTM campaign parameter"},"utm_medium":{"type":["string","null"],"description":"UTM medium parameter"},"utm_source":{"type":["string","null"],"description":"UTM source parameter"}}},"KeysRequest":{"type":"object","description":"Request to get keys matching a pattern","required":["pattern"],"properties":{"pattern":{"type":"string","description":"Pattern to match (supports * and ? wildcards)","example":"user:*"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"KeysResponse":{"type":"object","description":"Response for keys operation","required":["keys"],"properties":{"keys":{"type":"array","items":{"type":"string"},"description":"List of matching keys","example":["user:1","user:2","user:3"]}}},"KillJobBody":{"type":"object","properties":{"force":{"type":"boolean","description":"When true, sends SIGKILL immediately. Defaults to SIGTERM so the\nprocess gets a chance to flush (mirrors `Command.kill()` in\n`@vercel/sandbox`, which also accepts a signal override)."}},"additionalProperties":false},"KnownAiAgentsResponse":{"type":"object","description":"Response listing every AI agent the detector knows about.","required":["items"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AiAgentDescriptor"}}}},"KvStatusResponse":{"type":"object","description":"Response for KV service status","required":["enabled","healthy"],"properties":{"docker_image":{"type":["string","null"],"description":"Docker image being used","example":"gotempsh/redis-walg:8-bookworm"},"enabled":{"type":"boolean","description":"Whether the KV service is enabled"},"healthy":{"type":"boolean","description":"Whether the underlying Redis service is healthy"},"version":{"type":["string","null"],"description":"Service version","example":"7.2"}}},"LemonSqueezyConfig":{"type":"object","properties":{"product_allowlist":{"type":"array","items":{"type":"string"}},"variant_allowlist":{"type":"array","items":{"type":"string"}}}},"LetsEncryptSettings":{"type":"object","properties":{"email":{"type":["string","null"],"default":null},"environment":{"type":"string","default":"production"}}},"LineContext":{"type":"object","description":"Raw surrounding lines for a single match (grep -C style).","required":["before","after"],"properties":{"after":{"type":"array","items":{"$ref":"#/components/schemas/ContextLine"},"description":"Lines immediately after the match, oldest-first."},"before":{"type":"array","items":{"$ref":"#/components/schemas/ContextLine"},"description":"Lines immediately before the match, oldest-first."}}},"LinkServiceRequest":{"type":"object","required":["project_id"],"properties":{"project_id":{"type":"integer","format":"int32"}}},"ListAgentsResponse":{"type":"object","required":["items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AgentConfigResponse"}},"total":{"type":"integer","minimum":0}}},"ListApiKeysQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","minimum":0},"page_size":{"type":["integer","null"],"format":"int64","minimum":0}}},"ListAuditLogsQuery":{"type":"object","description":"Query parameters for listing audit logs.\n\nEvery field is optional — omitting one means \"don't filter on it\". Deriving\n`IntoParams` makes utoipa render them as optional query params with the\ncorrect types; the previous hand-written `params((\"operation_type\", Query,\n…))` tuples defaulted every param to `required: true, type: string`, which\nmisled both API clients and the AI `describe_api`/`call_api` tools into\nthinking all filters were mandatory.","properties":{"from":{"type":["string","null"],"format":"date-time","description":"Start timestamp (milliseconds since epoch)"},"limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of logs to return"},"offset":{"type":["integer","null"],"format":"int32","description":"Number of logs to skip"},"operation_type":{"type":["string","null"],"description":"Filter logs by operation type (omit for all)"},"to":{"type":["string","null"],"format":"date-time","description":"End timestamp (milliseconds since epoch)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter logs by user ID (omit for all users)"}}},"ListBlobsQuery":{"type":"object","description":"Query parameters for listing blobs","properties":{"cursor":{"type":["string","null"],"description":"Continuation token for pagination"},"limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of items to return","example":100},"prefix":{"type":["string","null"],"description":"Prefix to filter by","example":"images/"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"ListBlobsResponse":{"type":"object","description":"Response for listing blobs","required":["blobs","hasMore"],"properties":{"blobs":{"type":"array","items":{"$ref":"#/components/schemas/BlobResponse"},"description":"List of blobs"},"cursor":{"type":["string","null"],"description":"Continuation token for next page"},"hasMore":{"type":"boolean","description":"Whether there are more results","example":false}}},"ListCustomDomainsResponse":{"type":"object","required":["domains","total"],"properties":{"domains":{"type":"array","items":{"$ref":"#/components/schemas/CustomDomainResponse"}},"total":{"type":"integer","minimum":0}}},"ListDeploymentTokensQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","example":1,"minimum":0},"page_size":{"type":["integer","null"],"format":"int64","example":20,"minimum":0}}},"ListDomainsResponse":{"type":"object","required":["domains","total","page","page_size"],"properties":{"domains":{"type":"array","items":{"$ref":"#/components/schemas/DomainResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"ListEntitiesQuery":{"type":"object","properties":{"limit":{"type":"integer","description":"Maximum number of entities to return","example":100,"minimum":0},"token":{"type":["string","null"],"description":"Continuation token for pagination (backend-specific)"}}},"ListErrorEventsQuery":{"type":"object","properties":{"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0}}},"ListErrorGroupsQuery":{"type":"object","properties":{"end_date":{"type":["string","null"],"format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"sort_by":{"type":["string","null"]},"sort_order":{"type":"string"},"start_date":{"type":["string","null"],"format":"date-time"},"status":{"type":["string","null"]}}},"ListJobsResponse":{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/JobSummaryResponse"}}}},"ListMcpsResponse":{"type":"object","description":"Concrete list wrapper for MCP server definitions (utoipa requires non-generic types).","required":["items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/McpDefinitionResponse"}},"total":{"type":"integer","minimum":0}}},"ListOnDemandCertsResponse":{"type":"object","description":"Paginated list of on-demand cert attempts (ADR-018 §5 console \"Certificates\"\nsurface). Joined with current `domains.status`, newest first.","required":["certs","total","page","page_size"],"properties":{"certs":{"type":"array","items":{"$ref":"#/components/schemas/OnDemandCertRow"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"ListOrdersResponse":{"type":"object","required":["orders"],"properties":{"orders":{"type":"array","items":{"$ref":"#/components/schemas/AcmeOrderResponse"}}}},"ListPresetsResponse":{"type":"object","required":["presets","total"],"properties":{"presets":{"type":"array","items":{"$ref":"#/components/schemas/PresetResponse"}},"total":{"type":"integer","minimum":0}}},"ListRunsResponse":{"type":"object","required":["items","total","page","page_size"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AgentRunResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"ListSandboxesResponse":{"type":"object","description":"SDK list response: `{ sandboxes: [...], pagination: {...} }`.","required":["sandboxes","pagination"],"properties":{"pagination":{"$ref":"#/components/schemas/Pagination"},"sandboxes":{"type":"array","items":{"$ref":"#/components/schemas/SandboxInner"}}}},"ListScansQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","example":1,"minimum":0},"page_size":{"type":["integer","null"],"format":"int64","example":20,"minimum":0}}},"ListSecretsResponse":{"type":"object","required":["items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/SecretResponse"}},"total":{"type":"integer","minimum":0}}},"ListSkillsResponse":{"type":"object","description":"Concrete list wrapper for skill definitions (utoipa requires non-generic types).","required":["items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/SkillDefinitionResponse"}},"total":{"type":"integer","minimum":0}}},"ListTagsResponse":{"type":"object","description":"Response for listing tags","required":["tags","total"],"properties":{"tags":{"type":"array","items":{"type":"string"},"description":"List of available tags"},"total":{"type":"integer","description":"Total number of tags","minimum":0}}},"ListTemplatesQuery":{"type":"object","description":"Query parameters for listing templates","properties":{"featured":{"type":["boolean","null"],"description":"Only return featured templates"},"tag":{"type":["string","null"],"description":"Filter templates by tag"}}},"ListTemplatesResponse":{"type":"object","description":"Response for listing templates","required":["templates","total"],"properties":{"templates":{"type":"array","items":{"$ref":"#/components/schemas/TemplateResponse"},"description":"List of templates"},"total":{"type":"integer","description":"Total number of templates","minimum":0}}},"ListVulnerabilitiesQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","example":1,"minimum":0},"page_size":{"type":["integer","null"],"format":"int64","example":20,"minimum":0},"severity":{"type":["string","null"],"example":"CRITICAL"}}},"LiveVisitorInfo":{"type":"object","required":["id","visitor_id","project_id","environment_id","first_seen","last_seen","is_crawler"],"properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"crawler_name":{"type":["string","null"]},"current_page":{"type":["string","null"],"description":"Most recent page path visited by this visitor"},"custom_data":{},"environment_id":{"type":"integer","format":"int32"},"first_channel":{"type":["string","null"],"description":"Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")"},"first_referrer":{"type":["string","null"],"description":"Full referrer URL from the visitor's first session"},"first_referrer_hostname":{"type":["string","null"],"description":"Hostname extracted from first_referrer"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":["string","null"]},"ip_address_id":{"type":["integer","null"],"format":"int32"},"is_crawler":{"type":"boolean"},"is_eu":{"type":["boolean","null"]},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"latitude":{"type":["number","null"],"format":"double"},"longitude":{"type":["number","null"],"format":"double"},"project_id":{"type":"integer","format":"int32"},"region":{"type":["string","null"]},"timezone":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":"string"}}},"LiveVisitorsListResponse":{"type":"object","required":["total_count","visitors","window_minutes"],"properties":{"total_count":{"type":"integer","format":"int64"},"visitors":{"type":"array","items":{"$ref":"#/components/schemas/LiveVisitorInfo"}},"window_minutes":{"type":"integer","format":"int32"}}},"LocationCount":{"type":"object","required":["location","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"location":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"LocationGranularity":{"type":"string","enum":["country","region","city"]},"LocationInfo":{"type":"object","properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"region":{"type":["string","null"]}}},"LogLevel":{"type":"string","description":"Normalized log level","enum":["TRACE","DEBUG","INFO","WARN","ERROR"]},"LogRecord":{"type":"object","description":"A single log record ready for storage.","required":["project_id","resource","timestamp","observed_timestamp","severity","severity_text","body","attributes"],"properties":{"attributes":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"body":{"type":"string"},"deployment_id":{"type":["integer","null"],"format":"int32"},"observed_timestamp":{"type":"string","format":"date-time"},"project_id":{"type":"integer","format":"int32"},"resource":{"$ref":"#/components/schemas/ResourceInfo"},"severity":{"$ref":"#/components/schemas/LogSeverity"},"severity_text":{"type":"string"},"span_id":{"type":["string","null"]},"timestamp":{"type":"string","format":"date-time"},"trace_id":{"type":["string","null"]}}},"LogSearchLine":{"type":"object","description":"A single line in search results","required":["timestamp","level","service","message","chunk_id","line_offset"],"properties":{"chunk_id":{"type":"string"},"container_id":{"type":"string","description":"Container this line came from — lets the UI tag/group lines by container\nin a combined (\"show all\") multi-container view."},"context":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/LineContext","description":"Raw surrounding lines (grep -C). `None` unless `context_lines > 0` was\nrequested. Overlapping windows between nearby matches are merged: the\nshared neighbors appear on the earlier match only, so the frontend can\nrender one continuous block without duplicated lines."}]},"deploy_id":{"type":["integer","null"],"format":"int32"},"fields":{},"level":{"$ref":"#/components/schemas/LogLevel"},"line_offset":{"type":"integer","format":"int32"},"message":{"type":"string"},"node_id":{"type":["integer","null"],"format":"int32","description":"Worker node the line came from (`None` = control-plane-local)."},"node_name":{"type":["string","null"],"description":"Human-readable node name for display."},"service":{"type":"string"},"timestamp":{"type":"string"}}},"LogSeverity":{"type":"string","description":"Log severity level (simplified from OTel's 24 levels).","enum":["TRACE","DEBUG","INFO","WARN","ERROR","FATAL"]},"LogSource":{"type":"object","description":"A distinct log source (container) seen in the queried scope. Used to populate\nthe history filter dropdowns with the *full* set of containers/nodes for the\nproject + env + deployment + time window — independent of the active\ncontainer/node/service filter, so the user can switch between them.","required":["container_id","service"],"properties":{"container_id":{"type":"string"},"node_id":{"type":["integer","null"],"format":"int32"},"node_name":{"type":["string","null"]},"service":{"type":"string"}}},"LogStream":{"type":"string","description":"Log output stream","enum":["stdout","stderr"]},"LoginRequest":{"type":"object","required":["email","password"],"properties":{"email":{"type":"string"},"password":{"type":"string"}}},"LogsQuery":{"type":"object","properties":{"tail":{"type":["integer","null"],"description":"Number of lines to return from the tail. Defaults to 200, capped at 2000.","minimum":0}}},"LogsResponse":{"type":"object","required":["data","count"],"properties":{"count":{"type":"integer","minimum":0},"data":{"type":"array","items":{"$ref":"#/components/schemas/LogRecord"}}}},"ManagedDomainResponse":{"type":"object","description":"Managed domain response","required":["id","provider_id","domain","auto_manage","verified","generated_hostname_mode","sync_generated_records","created_at","updated_at"],"properties":{"auto_manage":{"type":"boolean"},"created_at":{"type":"string"},"domain":{"type":"string"},"generated_hostname_mode":{"type":"string","description":"Generated hostname layout: `\"standard\"` or `\"flat\"`."},"id":{"type":"integer","format":"int32"},"provider_id":{"type":"integer","format":"int32"},"sync_generated_records":{"type":"boolean","description":"Whether generated hostnames are reconciled into the provider's DNS zone."},"updated_at":{"type":"string"},"verification_error":{"type":["string","null"]},"verified":{"type":"boolean"},"verified_at":{"type":["string","null"]},"zone_access_error":{"type":["string","null"],"description":"Detail for a failed zone-access check."},"zone_access_ok":{"type":["boolean","null"],"description":"Last token zone-access check: `Some(true)`/`Some(false)`/`None` (unchecked)."},"zone_id":{"type":["string","null"]}}},"ManualAction":{"type":"object","description":"A manual action the user must perform outside of the automated migration","required":["timing","description","reason"],"properties":{"description":{"type":"string","description":"Human-readable description"},"reason":{"type":"string","description":"Why this can't be automated"},"timing":{"$ref":"#/components/schemas/ManualActionTiming","description":"When this action needs to happen"}}},"ManualActionTiming":{"type":"string","description":"When a manual action needs to happen relative to migration","enum":["before-migration","after-migration","within-hours"]},"McpDefinitionResponse":{"type":"object","required":["id","slug","name","config","created_at","updated_at"],"properties":{"config":{"type":"object"},"created_at":{"type":"string"},"description":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"project_id":{"type":["integer","null"],"format":"int32"},"slug":{"type":"string"},"updated_at":{"type":"string"}}},"MessageContent":{"oneOf":[{"type":"string"},{"type":"array","items":{"$ref":"#/components/schemas/ContentPart"}}]},"MessagePart":{"oneOf":[{"type":"object","required":["text","type"],"properties":{"text":{"type":"string"},"type":{"type":"string","enum":["text"]}}},{"type":"object","required":["tool","type"],"properties":{"tool":{"$ref":"#/components/schemas/ToolInfo"},"type":{"type":"string","enum":["tool"]}}}],"description":"One ordered segment of an assistant turn: a chunk of prose, or a tool\ninvocation. Mirrors the `metadata.parts` persisted by the chat service."},"MessageResponse":{"type":"object","required":["role","content","created_at"],"properties":{"content":{"type":"string"},"created_at":{"type":"string"},"parts":{"type":["array","null"],"items":{"$ref":"#/components/schemas/MessagePart"},"description":"Ordered render segments (text / tool, in the order they occurred) so a\nreloaded chat shows the same interleaving as the live stream. Absent for\nolder messages persisted before parts were tracked; the client then falls\nback to `tools` (rendered first) + `content`."},"role":{"type":"string"},"tools":{"type":["array","null"],"items":{"$ref":"#/components/schemas/ToolInfo"},"description":"Tools the assistant ran on this turn (persisted in message metadata), so\nthe chat replays its tool work after a reload. Absent for plain turns."}}},"MeteredMode":{"type":"string","description":"How to treat metered-billing subscriptions when computing MRR.\n\n* `DeriveFromInvoices` (default): ignore the subscription row's\n `mrr_minor` for metered items and rely on the per-invoice\n [`NormalizedEventType::MrrRealized`] events instead. Correct for\n pure-metered, hybrid, tiered, and flat — recommended.\n* `UseSubscription`: trust whatever MRR the subscription parser\n returns (0 for metered). Legacy behavior.\n* `Ignore`: drop metered subscriptions from MRR entirely.","enum":["derive_from_invoices","use_subscription","ignore"]},"MetricAggregation":{"oneOf":[{"type":"string","description":"Arithmetic mean of the scalar value in each bucket. The default.","enum":["avg"]},{"type":"string","description":"Sum of the scalar value in each bucket.","enum":["sum"]},{"type":"string","description":"Minimum scalar value in each bucket.","enum":["min"]},{"type":"string","description":"Maximum scalar value in each bucket.","enum":["max"]},{"type":"string","description":"Number of points in each bucket.","enum":["count"]},{"type":"string","description":"Per-second rate of change of a cumulative monotonic counter, computed as\n`(max - min) / window_seconds` within each bucket. Non-monotonic series\nfall back to a simple delta.","enum":["rate_per_sec"]},{"type":"object","description":"A quantile of the scalar value in each bucket. The carried `f64` is the\nrequested quantile in `[0.0, 1.0]`.","required":["quantile"],"properties":{"quantile":{"type":"number","format":"double","description":"A quantile of the scalar value in each bucket. The carried `f64` is the\nrequested quantile in `[0.0, 1.0]`."}}}],"description":"The aggregation applied when reducing raw metric points into a time bucket.\n\nStore-neutral: every storage backend (ClickHouse today, TimescaleDB later)\nmust be able to satisfy this contract. `Quantile(q)` carries the requested\nquantile in `[0.0, 1.0]` (e.g. `0.95` for p95)."},"MetricBucket":{"type":"object","description":"A time-bucketed metric aggregate for chart display.\n\nStore-neutral response contract. The legacy scalar fields\n(`avg_value`/`min_value`/`max_value`/`count`) are always populated for chart\nback-compat. The richer fields describe the explicitly-requested\n[`MetricAggregation`] (`value`), optional `quantiles`, an optional\n`histogram_summary`, and a `series_key` identifying the label-set when the\nquery used `group_by`.","required":["bucket","avg_value","min_value","max_value","count"],"properties":{"avg_value":{"type":"number","format":"double"},"bucket":{"type":"string","format":"date-time"},"count":{"type":"integer","format":"int64"},"histogram_summary":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/HistogramSummary","description":"A reduced histogram summary when the bucketed metric is a histogram."}]},"max_value":{"type":"number","format":"double"},"min_value":{"type":"number","format":"double"},"quantiles":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"number","format":"double"},{"type":"number","format":"double"}]},"description":"Computed quantile/value pairs `(quantile, value)` when the query asked for\nquantile aggregation; otherwise empty."},"series_key":{"type":["array","null"],"items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"The label-set this bucket belongs to, as ordered `(key, value)` pairs,\nwhen the query grouped by labels. Empty/`None` = the single ungrouped\naggregate stream."},"value":{"type":"number","format":"double","description":"The value of the requested [`MetricAggregation`] for this bucket. For the\ndefault `Avg` aggregation this equals `avg_value`. `#[serde(default)]` so\npre-existing payloads (which only carried avg/min/max/count) still parse."}}},"MetricDataPoint":{"type":"object","description":"A single `(timestamp, value)` data point in a metric series.","required":["time","value"],"properties":{"time":{"type":"string","description":"ISO 8601 timestamp with `Z` suffix."},"value":{"type":"number","format":"double","description":"Metric value at this bucket."}}},"MetricType":{"type":"string","description":"The type of an OTel metric.","enum":["gauge","sum","histogram","exponential_histogram","summary"]},"MetricsOverTimeResponse":{"type":"object","required":["timestamps","ttfb","lcp","fid","fcp","cls","inp"],"properties":{"cls":{"type":"array","items":{"type":["number","null"],"format":"float"}},"cls_p75":{"type":["number","null"],"format":"float"},"cls_p90":{"type":["number","null"],"format":"float"},"cls_p95":{"type":["number","null"],"format":"float"},"cls_p99":{"type":["number","null"],"format":"float"},"fcp":{"type":"array","items":{"type":["number","null"],"format":"float"}},"fcp_p75":{"type":["number","null"],"format":"float"},"fcp_p90":{"type":["number","null"],"format":"float"},"fcp_p95":{"type":["number","null"],"format":"float"},"fcp_p99":{"type":["number","null"],"format":"float"},"fid":{"type":"array","items":{"type":["number","null"],"format":"float"}},"fid_p75":{"type":["number","null"],"format":"float"},"fid_p90":{"type":["number","null"],"format":"float"},"fid_p95":{"type":["number","null"],"format":"float"},"fid_p99":{"type":["number","null"],"format":"float"},"inp":{"type":"array","items":{"type":["number","null"],"format":"float"}},"inp_p75":{"type":["number","null"],"format":"float"},"inp_p90":{"type":["number","null"],"format":"float"},"inp_p95":{"type":["number","null"],"format":"float"},"inp_p99":{"type":["number","null"],"format":"float"},"lcp":{"type":"array","items":{"type":["number","null"],"format":"float"}},"lcp_p75":{"type":["number","null"],"format":"float"},"lcp_p90":{"type":["number","null"],"format":"float"},"lcp_p95":{"type":["number","null"],"format":"float"},"lcp_p99":{"type":["number","null"],"format":"float"},"timestamps":{"type":"array","items":{"type":"string"}},"ttfb":{"type":"array","items":{"type":["number","null"],"format":"float"}},"ttfb_p75":{"type":["number","null"],"format":"float"},"ttfb_p90":{"type":["number","null"],"format":"float"},"ttfb_p95":{"type":["number","null"],"format":"float"},"ttfb_p99":{"type":["number","null"],"format":"float"}}},"MetricsQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"MetricsRangeQuery":{"type":"object","description":"Query params for range metric queries.","required":["metric"],"properties":{"metric":{"type":"string","description":"Metric name, e.g. `\"pg.connections_active\"`."},"percentile":{"type":["number","null"],"format":"double","description":"Optional histogram percentile (0–100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile."},"range":{"type":"string","description":"Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`."}}},"MetricsStatusResponse":{"type":"object","description":"Freshness status: when metrics were last received for this service.","properties":{"last_received_at":{"type":["string","null"],"description":"ISO 8601 timestamp of the most recent metric row, or null if none yet."}}},"MetricsStoreKind":{"type":"string","description":"Which storage backend to use for the MetricsStore.","enum":["timescale_db","click_house"]},"MetricsSummaryResponse":{"type":"object","required":["currency","current_mrr_minor","current_arr_minor","active_subscriptions","active_customers","churned_last_30d","arpu_minor"],"properties":{"active_customers":{"type":"integer","format":"int64"},"active_subscriptions":{"type":"integer","format":"int64"},"arpu_minor":{"type":"integer","format":"int64"},"churned_last_30d":{"type":"integer","format":"int64"},"currency":{"type":"string"},"current_arr_minor":{"type":"integer","format":"int64"},"current_mrr_minor":{"type":"integer","format":"int64"}}},"MfaRequiredResponse":{"type":"object","required":["requires_mfa","session_token"],"properties":{"requires_mfa":{"type":"boolean"},"session_token":{"type":"string"}}},"MfaSetupResponse":{"type":"object","required":["secret_key","qr_code","recovery_codes"],"properties":{"qr_code":{"type":"string"},"recovery_codes":{"type":"array","items":{"type":"string"}},"secret_key":{"type":"string"}}},"MfaVerificationRequest":{"type":"object","required":["code"],"properties":{"code":{"type":"string"}}},"MigrationStep":{"type":"object","description":"A single step in the migration execution plan.\n\nSteps are presented to the user before execution so they know exactly\nwhat will happen. During execution, each step runs in order and reports\nits outcome before proceeding to the next.","required":["order","id","title","description","resource_type","risk","skippable","reversible"],"properties":{"data_implications":{"type":"array","items":{"$ref":"#/components/schemas/DataImplication"},"description":"Data implications — what could go wrong or what the user needs to know"},"description":{"type":"string","description":"Detailed description of what this step does"},"estimated_duration":{"type":["string","null"],"description":"Estimated duration hint (e.g., \"< 1 second\", \"10-30 seconds\")"},"id":{"type":"string","description":"Machine-readable step identifier (e.g., \"create-project\", \"create-service-postgres\")"},"order":{"type":"integer","description":"Step number (1-based, for display)","minimum":0},"post_conditions":{"type":"array","items":{"type":"string"},"description":"Things the user should verify AFTER this step completes"},"pre_conditions":{"type":"array","items":{"type":"string"},"description":"Things the user should verify BEFORE this step runs"},"resource_type":{"$ref":"#/components/schemas/StepResourceType","description":"What kind of resource this step creates/modifies"},"reversible":{"type":"boolean","description":"Whether this step is reversible (can be cleaned up on failure)"},"risk":{"$ref":"#/components/schemas/RiskLevel","description":"Risk level for this step"},"skippable":{"type":"boolean","description":"Whether this step can be skipped by the user"},"skipped":{"type":"boolean","description":"Whether the user has chosen to skip this step (set during review)"},"title":{"type":"string","description":"Human-readable title (e.g., \"Create project 'my-app'\")"}}},"MigrationSummary":{"type":"object","description":"Human-readable summary of the entire migration plan","required":["headline","overall_risk","resource_counts"],"properties":{"critical_warnings":{"type":"array","items":{"type":"string"},"description":"Critical warnings that must be acknowledged before proceeding.\nThese are the most important things the user needs to know."},"headline":{"type":"string","description":"One-line summary (e.g., \"Migrate 'my-app' from Vercel with 1 database, 2 domains\")"},"manual_actions_required":{"type":"array","items":{"$ref":"#/components/schemas/ManualAction"},"description":"Manual actions the user must perform (before or after migration)"},"overall_risk":{"$ref":"#/components/schemas/RiskLevel","description":"Overall risk assessment for the migration"},"resource_counts":{"$ref":"#/components/schemas/ResourceCounts","description":"Resource counts for quick overview"},"unsupported_features":{"type":"array","items":{"$ref":"#/components/schemas/UnsupportedFeature"},"description":"Features from the source platform that cannot be migrated"}}},"MintEnrollmentTokenRequest":{"type":"object","properties":{"bound_node_name":{"type":["string","null"],"description":"Optional: restrict the token to register one specific node name."},"max_uses":{"type":["integer","null"],"format":"int32","description":"Maximum registrations this token may authorize (default 1)."},"ttl_secs":{"type":["integer","null"],"format":"int64","description":"Time-to-live in seconds (default 3600 = 1h)."}}},"MintEnrollmentTokenResponse":{"type":"object","required":["id","token","expires_at","max_uses","message"],"properties":{"ca_fingerprint":{"type":["string","null"],"description":"SHA-256 fingerprint of the cluster CA (if mTLS is set up). Pass it to the\nworker as `temps join --ca-fingerprint ` to verify the CA on join."},"expires_at":{"type":"string"},"id":{"type":"integer","format":"int32"},"max_uses":{"type":"integer","format":"int32"},"message":{"type":"string"},"token":{"type":"string","description":"The plaintext enrollment token — shown only once, save it now."}}},"MiscResult":{"type":"object","description":"Miscellaneous validation result","required":["is_disposable","is_role_account","is_b2c"],"properties":{"gravatar_url":{"type":["string","null"],"description":"Gravatar URL if available"},"is_b2c":{"type":"boolean","description":"Whether the email provider is a B2C (consumer) email provider"},"is_disposable":{"type":"boolean","description":"Whether the email is from a disposable email provider"},"is_role_account":{"type":"boolean","description":"Whether the email is a role-based account (e.g., admin@, info@)"}}},"MkdirBody":{"type":"object","required":["path"],"properties":{"path":{"type":"string"}},"additionalProperties":false},"ModelInfo":{"type":"object","required":["id","object","owned_by"],"properties":{"id":{"type":"string"},"object":{"type":"string"},"owned_by":{"type":"string"}}},"ModelListResponse":{"type":"object","required":["object","data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ModelInfo"}},"object":{"type":"string"}}},"ModelPricing":{"type":"object","description":"Pricing for a single model, all values in USD per 1M tokens.\nFields are optional because not every provider supports every pricing tier.","required":["model","display_name","provider","input_per_million","output_per_million"],"properties":{"batch_input_per_million":{"type":["number","null"],"format":"double","description":"Batch API input cost per 1M tokens (if provider offers batch pricing)"},"batch_output_per_million":{"type":["number","null"],"format":"double","description":"Batch API output cost per 1M tokens"},"cache_hit_per_million":{"type":["number","null"],"format":"double","description":"Cache hit / refresh cost per 1M tokens"},"cache_write_1h_per_million":{"type":["number","null"],"format":"double","description":"1-hour cache write cost per 1M tokens"},"cache_write_5m_per_million":{"type":["number","null"],"format":"double","description":"5-minute cache write cost per 1M tokens (Anthropic-style prompt caching)"},"deprecated":{"type":"boolean","description":"Whether the model is deprecated"},"display_name":{"type":"string","description":"Human-readable model name (e.g. \"Claude Sonnet 4.6\")"},"input_per_million":{"type":"number","format":"double","description":"Base input token cost per 1M tokens"},"model":{"type":"string","description":"Model identifier (e.g. \"gpt-5.4\", \"claude-sonnet-4-6\")"},"output_per_million":{"type":"number","format":"double","description":"Output token cost per 1M tokens"},"provider":{"type":"string","description":"Provider ID (e.g. \"openai\", \"anthropic\")"}}},"ModelUsage":{"type":"object","required":["model","provider","request_count","input_tokens","output_tokens","total_tokens","avg_latency_ms"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"input_tokens":{"type":"integer","format":"int64"},"model":{"type":"string"},"output_tokens":{"type":"integer","format":"int64"},"provider":{"type":"string"},"request_count":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"MonitorResponse":{"type":"object","required":["id","project_id","name","monitor_type","monitor_url","check_interval_seconds","is_active","created_at","updated_at"],"properties":{"check_interval_seconds":{"type":"integer","format":"int32"},"check_path":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"monitor_type":{"type":"string"},"monitor_url":{"type":"string"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","format":"date-time"}}},"MonitorStatus":{"type":"object","required":["monitor","current_status","uptime_percentage"],"properties":{"avg_response_time_ms":{"type":["integer","null"],"format":"int32"},"current_status":{"type":"string"},"monitor":{"$ref":"#/components/schemas/MonitorResponse"},"uptime_percentage":{"type":"number","format":"double"}}},"MonitoringSettings":{"type":"object","description":"Global metrics observability configuration.\n\nControls whether the MetricsScraper and AlertEvaluator background tasks\nare active, which storage backend they write to, and how long data is kept\nat each retention tier.","properties":{"clickhouse_url":{"type":["string","null"],"description":"ClickHouse DSN (legacy, optional). The runtime metrics store is built\nfrom the `TEMPS_CLICKHOUSE_*` env vars, never from this field; it is\nretained for compatibility and operator reference only.\nExample: `\"http://localhost:8123\"`.","default":null},"enabled":{"type":"boolean","description":"Enable or disable all metrics collection (scraping + alerting).\nDefaults to `false` so new installs don't write to TimescaleDB until\nan operator explicitly enables the feature.","default":false},"retention_daily_years":{"type":"integer","format":"int32","description":"How many years of daily-aggregate data to keep (converted to days internally).","default":2,"example":2,"maximum":10,"minimum":1},"retention_hourly_days":{"type":"integer","format":"int32","description":"How many days of hourly-aggregate data to keep.","default":90,"example":90,"minimum":1},"retention_raw_days":{"type":"integer","format":"int32","description":"How many days of raw (30 s resolution) metric data to keep.","default":7,"example":7,"minimum":1},"scrape_interval_secs":{"type":"integer","format":"int64","description":"How often the MetricsScraper collects data from all sources, in seconds.\nMinimum effective value is 10 s; values below that are clamped at runtime.","default":30,"example":30,"minimum":10},"store":{"oneOf":[{"$ref":"#/components/schemas/MetricsStoreKind","description":"Storage backend for metric data."}],"default":"timescale_db"}}},"MonitoringSettingsMasked":{"type":"object","description":"Monitoring settings with the ClickHouse DSN masked.\n\n`clickhouse_url` can embed credentials (`http://user:pass@host`), so it is\nreported only as a boolean (`clickhouse_url_set`) rather than echoed back —\nconsistent with how the DNS API key and Docker registry password are masked.","required":["enabled","store","scrape_interval_secs","retention_raw_days","retention_hourly_days","retention_daily_years","clickhouse_url_set"],"properties":{"clickhouse_url_set":{"type":"boolean","description":"True when a ClickHouse DSN is configured. The DSN itself is never\nreturned over HTTP because it may contain credentials."},"enabled":{"type":"boolean"},"retention_daily_years":{"type":"integer","format":"int32","minimum":0},"retention_hourly_days":{"type":"integer","format":"int32","minimum":0},"retention_raw_days":{"type":"integer","format":"int32","minimum":0},"scrape_interval_secs":{"type":"integer","format":"int64","minimum":0},"store":{"$ref":"#/components/schemas/MetricsStoreKind"}}},"MrrBucketResponse":{"type":"object","required":["bucket","mrr_minor","charge_total_minor","refund_total_minor","charge_count"],"properties":{"bucket":{"type":"string","format":"date-time"},"charge_count":{"type":"integer","format":"int64"},"charge_total_minor":{"type":"integer","format":"int64"},"mrr_minor":{"type":"integer","format":"int64"},"refund_total_minor":{"type":"integer","format":"int64"}}},"MultiNodeSettings":{"type":"object","description":"Multi-node cluster settings","properties":{"cluster_ca_cert_pem":{"type":["string","null"],"description":"Per-cluster CA certificate (PEM) for multi-node mTLS (ADR-020 WS-2.1).\nPublic — distributed to nodes as the trust root and used by the control\nplane as the root for verifying agent server certs. Minted lazily on the\nfirst CSR-bearing registration.","default":null},"cluster_ca_key_encrypted":{"type":["string","null"],"description":"Per-cluster CA private key, AES-256-GCM ciphertext (EncryptionService).\nSECRET — never returned over HTTP (elided in the masked response).","default":null},"join_token_hash":{"type":["string","null"],"description":"SHA-256 hash of the join token (never store plaintext)","default":null},"legacy_shared_token_enabled":{"type":"boolean","description":"Whether the legacy single shared join token is still accepted for node\nregistration (ADR-020 WS-1.1). Defaults to `true` so existing clusters\nkeep working on upgrade; fresh installs should set it `false` and rely on\nshort-lived, single-use enrollment tokens instead.","default":true},"node_cpu_alert_percent":{"type":["number","null"],"format":"double","description":"CPU-usage percent above which a worker node raises a resource alert\n(ADR-020 / monitoring). `None` disables CPU alerting. Default 90.","default":90.0},"node_disk_alert_percent":{"type":["number","null"],"format":"double","description":"Disk-usage percent above which a worker node raises a resource alert.\n`None` disables disk alerting. Default 90.","default":90.0},"node_memory_alert_percent":{"type":["number","null"],"format":"double","description":"Memory-usage percent above which a worker node raises a resource alert.\n`None` disables memory alerting. Default 90.","default":90.0},"private_address":{"type":["string","null"],"description":"Private/WireGuard IP address of the control plane node.\nUsed by remote worker nodes to reach services (databases, etc.) running on the control plane.\nSet via `--private-address` or `TEMPS_PRIVATE_ADDRESS`.","default":null},"require_mtls":{"type":"boolean","description":"Whether to enforce multi-node mTLS (ADR-020 WS-2.1). When `false`\n(default), the control plane ignores join-time CSRs and nodes keep\nserving plaintext HTTP — zero behavior change. When `true`, the CP signs\nnode CSRs, nodes serve mutual TLS, and every CP→agent call uses the\ncluster client cert. Observe-then-enforce: flip this on only once all\nworkers have re-enrolled with certs.","default":false}}},"MultiNodeSettingsMasked":{"type":"object","description":"Multi-node settings with `join_token_hash` elided.","required":["has_join_token","require_mtls","legacy_shared_token_enabled"],"properties":{"cluster_ca_fingerprint":{"type":["string","null"],"description":"SHA-256 fingerprint of the cluster CA certificate (public — operators can\nverify it out of band; the CA private key is never exposed)."},"has_join_token":{"type":"boolean"},"legacy_shared_token_enabled":{"type":"boolean","description":"Whether the deprecated shared join token is still accepted."},"node_cpu_alert_percent":{"type":["number","null"],"format":"double","description":"Node resource-alert thresholds (percent); `None` = that alert disabled."},"node_disk_alert_percent":{"type":["number","null"],"format":"double"},"node_memory_alert_percent":{"type":["number","null"],"format":"double"},"private_address":{"type":["string","null"]},"require_mtls":{"type":"boolean","description":"Whether control-plane↔agent mutual TLS is enforced."}}},"MxResult":{"type":"object","description":"MX (Mail Exchange) validation result","required":["accepts_mail","records"],"properties":{"accepts_mail":{"type":"boolean","description":"Whether the domain accepts mail"},"error":{"type":["string","null"],"description":"Error message if MX lookup failed"},"records":{"type":"array","items":{"type":"string"},"description":"List of MX records for the domain","example":["alt1.gmail-smtp-in.l.google.com.","gmail-smtp-in.l.google.com."]}}},"NavEntry":{"type":"object","description":"A navigation entry that the plugin contributes to the Temps UI.","required":["label","icon","section","path","order"],"properties":{"icon":{"type":"string","description":"Lucide icon name (e.g., \"puzzle\", \"database\", \"activity\")"},"label":{"type":"string","description":"Display label in the sidebar"},"order":{"type":"integer","format":"int32","description":"Sort order within the section (lower = higher in list)","minimum":0},"path":{"type":"string","description":"Client-side route path (e.g., \"/my-plugin\")"},"section":{"$ref":"#/components/schemas/NavSection","description":"Which sidebar section this entry belongs to"}}},"NavSection":{"type":"string","description":"Where the plugin's nav entry appears in the Temps UI sidebar.","enum":["platform","settings","project"]},"NetworkConfiguration":{"type":"object","description":"Network configuration","required":["mode","dns_servers"],"properties":{"dns_servers":{"type":"array","items":{"type":"string"},"description":"DNS servers"},"hostname":{"type":["string","null"],"description":"Hostname"},"mode":{"$ref":"#/components/schemas/NetworkMode","description":"Network mode"}}},"NetworkMode":{"oneOf":[{"type":"string","enum":["bridge"]},{"type":"string","enum":["host"]},{"type":"string","enum":["none"]},{"type":"object","required":["custom"],"properties":{"custom":{"type":"string"}}}],"description":"Network mode"},"NixpacksPresetConfig":{"type":"object","description":"Configuration for Nixpacks preset\nNixpacks provider and inline build-plan configuration.","properties":{"nixpacksConfig":{"type":["string","null"],"description":"Optional inline nixpacks.toml contents."},"providers":{"type":"array","items":{"$ref":"#/components/schemas/NixpacksProvider"},"description":"Ordered Nixpacks providers. Empty means repository config or auto-detect;\ninclude `...` to combine auto-detection with explicit providers."}}},"NixpacksProvider":{"type":"string","description":"A Nixpacks build provider.\n\n`Auto` serializes as the native Nixpacks `...` marker, which includes the\nprovider detected from the project alongside any explicitly listed\nproviders.","enum":["...","node","python","rust","go","java","php","ruby","deno","elixir","csharp","fsharp","dart","swift","zig","scala","haskell","clojure","crystal","cobol","gleam","lunatic","scheme","static"]},"NodeContainerListResponse":{"type":"object","required":["containers","total"],"properties":{"containers":{"type":"array","items":{"$ref":"#/components/schemas/NodeContainerResponse"}},"total":{"type":"integer","minimum":0}}},"NodeContainerResponse":{"type":"object","description":"A container running on a specific node, enriched with project/environment context.","required":["container_id","container_name","image_name","status","created_at","deployment_id","project_id","project_name","environment_id","environment_name"],"properties":{"container_id":{"type":"string"},"container_name":{"type":"string"},"created_at":{"type":"string"},"deployment_id":{"type":"integer","format":"int32"},"environment_id":{"type":"integer","format":"int32"},"environment_name":{"type":"string"},"image_name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"status":{"type":"string"}}},"NodeCostInfo":{"type":"object","description":"One cluster node with capacity and (when priceable) a cost estimate","required":["name","cpu_millis","memory_mb"],"properties":{"cpu_millis":{"type":"integer","format":"int64","description":"CPU capacity in millicores"},"instance_type":{"type":["string","null"],"description":"Instance type from `node.kubernetes.io/instance-type` (e.g. \"m5.xlarge\")"},"memory_mb":{"type":"integer","format":"int64","description":"Memory capacity in MB"},"monthly_usd":{"type":["number","null"],"format":"double","description":"Estimated on-demand monthly price in USD. `None` when the instance\ntype is unknown or not in the price table."},"name":{"type":"string","description":"Node name"},"region":{"type":["string","null"],"description":"Region from `topology.kubernetes.io/region`"}}},"NodeInfoResponse":{"type":"object","required":["id","name","address","private_address","role","status","labels","capacity","created_at"],"properties":{"address":{"type":"string"},"architecture":{"type":["string","null"],"description":"Container platform this node runs (`linux/amd64`, `linux/arm64`).\n`None` until an agent that reports it has heartbeated."},"capacity":{"description":"Resource capacity/usage metrics from the latest heartbeat"},"created_at":{"type":"string"},"id":{"type":"integer","format":"int32"},"labels":{},"last_heartbeat":{"type":["string","null"]},"name":{"type":"string"},"private_address":{"type":"string"},"role":{"type":"string"},"status":{"type":"string"}}},"NodeListResponse":{"type":"object","required":["nodes","total"],"properties":{"nodes":{"type":"array","items":{"$ref":"#/components/schemas/NodeInfoResponse"}},"total":{"type":"integer","minimum":0}}},"NotificationPreferencesResponse":{"type":"object","required":["email_enabled","slack_enabled","batch_similar_notifications","minimum_severity","deployment_failures_enabled","build_errors_enabled","runtime_errors_enabled","error_threshold","error_time_window","ssl_expiration_enabled","ssl_days_before_expiration","domain_expiration_enabled","dns_changes_enabled","backup_failures_enabled","backup_successes_enabled","s3_connection_issues_enabled","retention_policy_violations_enabled","route_downtime_enabled","load_balancer_issues_enabled","weekly_digest_enabled","digest_send_day","digest_send_time","digest_sections"],"properties":{"backup_failures_enabled":{"type":"boolean"},"backup_successes_enabled":{"type":"boolean"},"batch_similar_notifications":{"type":"boolean"},"build_errors_enabled":{"type":"boolean"},"deployment_failures_enabled":{"type":"boolean"},"digest_sections":{"$ref":"#/components/schemas/DigestSections"},"digest_send_day":{"type":"string"},"digest_send_time":{"type":"string"},"dns_changes_enabled":{"type":"boolean"},"domain_expiration_enabled":{"type":"boolean"},"email_enabled":{"type":"boolean"},"error_threshold":{"type":"integer","format":"int32"},"error_time_window":{"type":"integer","format":"int32"},"load_balancer_issues_enabled":{"type":"boolean"},"minimum_severity":{"type":"string"},"retention_policy_violations_enabled":{"type":"boolean"},"route_downtime_enabled":{"type":"boolean"},"runtime_errors_enabled":{"type":"boolean"},"s3_connection_issues_enabled":{"type":"boolean"},"slack_enabled":{"type":"boolean"},"ssl_days_before_expiration":{"type":"integer","format":"int32"},"ssl_expiration_enabled":{"type":"boolean"},"weekly_digest_enabled":{"type":"boolean"}}},"NotificationProviderResponse":{"type":"object","required":["id","name","provider_type","config","enabled","created_at","updated_at"],"properties":{"config":{},"created_at":{"type":"integer","format":"int64"},"enabled":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"provider_type":{"type":"string"},"updated_at":{"type":"integer","format":"int64"}}},"ObservabilityCompressionSettings":{"type":"object","description":"TimescaleDB compression policy configuration for append-only observability\ntables. Values are expressed in hours so operators can choose sub-day\nwindows while keeping the API representation unambiguous.","properties":{"otel_spans_after_hours":{"type":"integer","format":"int32","description":"Compress OpenTelemetry span chunks after this many hours. Defaults to\n24 hours.","default":24,"example":24,"maximum":2160,"minimum":1},"proxy_logs_after_hours":{"type":"integer","format":"int32","description":"Compress proxy-log chunks after this many hours. Defaults to 24 hours.","default":24,"example":24,"maximum":720,"minimum":1}}},"ObservabilityEvent":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/RequestRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["request"]}}}]},{"allOf":[{"$ref":"#/components/schemas/SpanRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["span"]}}}]},{"allOf":[{"$ref":"#/components/schemas/ErrorRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["error"]}}}]},{"allOf":[{"$ref":"#/components/schemas/RevenueRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["revenue"]}}}]}],"description":"Discriminated union of every row that can appear in the Observe list.\n\nSerializes to `{ \"type\": \"request\" | \"span\" | ... , ...rest }` so the UI\ncan switch on `event.type` without ambiguity.\n\n**No `Log` variant**: runtime stdout/stderr lines live on a dedicated\nLogs page rather than Observe. Logs are too high-volume to interleave\nwith business signals (requests, errors, revenue) without dominating\nthe timeline, and they have their own retention/storage constraints\n(TimescaleDB hypertable + chunked file/S3 store) that don't compose\nwith the merge service's per-kind LIMIT strategy."},"ObservabilityRetentionSettings":{"type":"object","description":"Retention policy configuration for raw observability tables. Values are in\ndays. The Settings API applies them to TimescaleDB; ClickHouse-backed proxy\nlogs and spans retain their storage-level per-row TTL behavior.","properties":{"otel_logs_days":{"type":"integer","format":"int32","description":"Retain OpenTelemetry log events for this many days.","default":90,"example":90,"maximum":3650,"minimum":1},"otel_metrics_days":{"type":"integer","format":"int32","description":"Retain OpenTelemetry metric points for this many days.","default":90,"example":90,"maximum":3650,"minimum":1},"otel_spans_days":{"type":"integer","format":"int32","description":"Retain OpenTelemetry spans (traces) for this many days.","default":90,"example":90,"maximum":3650,"minimum":1},"proxy_logs_days":{"type":"integer","format":"int32","description":"Retain proxy request logs for this many days.","default":30,"example":30,"maximum":3650,"minimum":1}}},"OidcProviderResponse":{"type":"object","required":["id","name","issuer_url","client_id","client_secret","scopes","jit_provisioning","enabled","template","group_claim","role_claim","default_role","trust_idp_email"],"properties":{"client_id":{"type":"string"},"client_secret":{"type":"string","description":"Always masked — the secret is never returned after creation."},"default_role":{"type":"string"},"enabled":{"type":"boolean"},"group_claim":{"type":"string"},"id":{"type":"integer","format":"int32"},"issuer_url":{"type":"string"},"jit_provisioning":{"type":"boolean"},"name":{"type":"string"},"role_claim":{"type":"string"},"scopes":{"type":"string"},"template":{"type":"string"},"trust_idp_email":{"type":"boolean","description":"When true, the resolver skips the `email_verified` claim gate\nduring SSO login. Only safe for IdPs where an admin controls\nuser provisioning — see `oidc_providers::Model::trust_idp_email`."}}},"OidcProviderSummary":{"type":"object","required":["slug","name","template"],"properties":{"name":{"type":"string"},"slug":{"type":"string","description":"Stable opaque slug — use this as the path parameter when initiating\nOIDC login (`/auth/oidc/login/{slug}`). The integer database ID is\nintentionally omitted from this public endpoint to prevent provider\nenumeration."},"template":{"type":"string","description":"The template the provider was created from — e.g. `keycloak`,\n`okta`, `auth0`, `google`, `azure-ad`, or `generic`. Surfaced on\nthe public login endpoint so the unauthenticated login page can\nrender the right brand logo on the \"Sign in with X\" button.\nNever sensitive — the template name is part of the provider's\npublic identity, not configuration."}}},"OidcProviderUserResponse":{"type":"object","description":"A user that has logged in via a given OIDC provider. Used by the\nadmin \"Users for provider\" panel — the `oidc_subject` is the\nIdP-side identifier we matched on, useful when diagnosing why a\nuser can or can't log in.","required":["id","name","email","email_verified","mfa_enabled","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-15T14:30:00Z"},"email":{"type":"string"},"email_verified":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"mfa_enabled":{"type":"boolean"},"name":{"type":"string"},"oidc_subject":{"type":["string","null"]},"updated_at":{"type":"string","format":"date-time","example":"2024-01-15T14:30:00Z"}}},"OidcProvidersListResponse":{"type":"object","required":["providers"],"properties":{"providers":{"type":"array","items":{"$ref":"#/components/schemas/OidcProviderSummary"}}}},"OidcRoleMappingResponse":{"type":"object","required":["id","provider_id","priority","idp_group","role"],"properties":{"id":{"type":"integer","format":"int32"},"idp_group":{"type":"string"},"priority":{"type":"integer","format":"int32"},"provider_id":{"type":"integer","format":"int32"},"role":{"type":"string"}}},"OidcTestConnectionResponse":{"type":"object","required":["success","message"],"properties":{"message":{"type":"string"},"success":{"type":"boolean"}}},"OnDemandCertAttemptResponse":{"type":"object","description":"A single on-demand HTTP-01 issuance attempt from the append-only\n`on_demand_cert_attempts` audit log. Carries the full forensic detail for one\nattempt; the current cert state lives on the enclosing row's domain fields.\n\nContains no private-key or certificate material — only audit metadata — so it\nis safe to return without masking.","required":["id","hostname","trigger","outcome","created_at"],"properties":{"acme_request_sent":{"type":["boolean","null"],"description":"Did we reach the Let's Encrypt API?"},"acme_response_status":{"type":["string","null"],"description":"HTTP status or ACME error type returned by Let's Encrypt, when known."},"challenge_served":{"type":["boolean","null"],"description":"Did the proxy serve the `/.well-known/acme-challenge/` request?"},"created_at":{"type":"integer","format":"int64","description":"When the attempt was recorded (epoch millis)."},"duration_ms":{"type":["integer","null"],"format":"int32","description":"End-to-end issuance duration in milliseconds (0/None for skipped)."},"error_category":{"type":["string","null"],"description":"Coarse error category for UI labelling: `\"rate_limited\"`, `\"dns_failure\"`,\n`\"acme_order_expired\"`, `\"challenge_mismatch\"`, `\"timeout\"`, `\"internal\"`."},"error_chain":{"type":["string","null"],"description":"Full `Display` chain of the error (all `source()` levels), when failed."},"hostname":{"type":"string","description":"SNI hostname that triggered the attempt."},"id":{"type":"integer","format":"int32"},"outcome":{"type":"string","description":"Final outcome: `\"issued\"`, `\"failed\"`, `\"skipped_duplicate\"`,\n`\"skipped_gate\"`, `\"skipped_rate_limit\"`, or `\"skipped_no_route\"`."},"trigger":{"type":"string","description":"What triggered the attempt (always `\"tls_callback\"` today)."}}},"OnDemandCertRow":{"type":"object","description":"One row of the on-demand certificates list: the most-recent attempt for a\nhostname plus the current authoritative cert state from its `domains` row.","required":["hostname","attempt"],"properties":{"attempt":{"$ref":"#/components/schemas/OnDemandCertAttemptResponse","description":"The audit record for the attempt this row represents (newest first in\nthe list)."},"backoff_until":{"type":["integer","null"],"format":"int64","description":"On-demand negative-cache deadline (epoch millis), when in backoff."},"expiration_time":{"type":["integer","null"],"format":"int64","description":"Certificate expiration (epoch millis), when an active cert exists."},"hostname":{"type":"string","description":"SNI hostname."},"status":{"type":["string","null"],"description":"Current cert lifecycle status from the `domains` row, when one exists:\n`on_demand_pending`, `on_demand_issuing`, `active`, `on_demand_failed`,\netc. `None` when no `domains` row exists yet for this hostname."}}},"OnDemandTlsSettings":{"type":"object","description":"On-demand (lazy) HTTP-01 TLS issuance settings (ADR-018).\n\nWhen `enabled`, the proxy's `certificate_callback` triggers ACME HTTP-01\nissuance for allowlisted, STABLE hostnames (per-environment aliases and the\nconsole host) that have no active cert, rather than silently failing the\nhandshake. Ephemeral per-deployment hostnames are NEVER certed (ADR §2).\n\nOff by default — operators opt in explicitly, except QuickStart (`sslip.io`)\ninstalls where `temps setup` auto-enables it and derives `zone`.","properties":{"deployment_url_mode":{"type":"string","description":"How ephemeral per-deployment hostnames behave when they have no cert\n(they are NEVER certed — see ADR §2). One of:\n - `\"http\"` (default): serve plain HTTP on :80.\n - `\"redirect_to_env\"`: 308-redirect to the stable per-environment URL,\n which IS certed.","default":"http","example":"http"},"enabled":{"type":"boolean","description":"Master switch. When `false` (default) the proxy's on-demand cert gate\nrejects every SNI and no issuance is ever triggered.","default":false,"example":false},"hourly_cap":{"type":"integer","format":"int32","description":"Global cap on total on-demand issuances per hour across all hostnames\n(ADR §4 Layer 3). The operator's self-imposed safety net, separate from\nthe Let's Encrypt rate limit.","default":10,"example":10,"minimum":1},"max_concurrent":{"type":"integer","format":"int32","description":"Maximum number of ACME issuance flows allowed to run simultaneously\n(the concurrent-issuance semaphore, ADR §4 Layer 1). Min 1.","default":3,"example":3,"minimum":1},"zone":{"type":["string","null"],"description":"Zone suffix for the allowlist gate. A hostname passes the gate only if\nit is a direct subdomain of this zone (e.g. zone `1.2.3.4.sslip.io`\nadmits `myapp.1.2.3.4.sslip.io` but not `deep.sub.1.2.3.4.sslip.io`).\n`None` (default) means \"auto-derive from `external_url`\"; if no zone can\nbe derived the gate rejects all SNI, disabling the feature.","default":null,"example":"1.2.3.4.sslip.io"}}},"OpenAiError":{"type":"object","required":["message","type"],"properties":{"code":{"type":["string","null"]},"message":{"type":"string"},"type":{"type":"string"}}},"OpenAiErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"$ref":"#/components/schemas/OpenAiError"}}},"OperatingSystemCount":{"type":"object","required":["operating_system","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"operating_system":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"OperationResultResponse":{"type":"object","required":["operation","success","message","executed_at"],"properties":{"data":{},"executed_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"message":{"type":"string"},"operation":{"type":"string"},"success":{"type":"boolean"}}},"OperationResultsResponse":{"type":"object","required":["deployment_id","operations"],"properties":{"deployment_id":{"type":"string"},"operations":{"type":"array","items":{"$ref":"#/components/schemas/OperationResultResponse"}}}},"OtelDashboardResponse":{"type":"object","required":["id","project_id","name","layout","created_at","updated_at"],"properties":{"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"id":{"type":"integer","format":"int32"},"layout":{"$ref":"#/components/schemas/DashboardLayout"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"}}},"OtelDashboardsResponse":{"type":"object","required":["data","total"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OtelDashboardResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"OtelMetricAlertRuleResponse":{"type":"object","required":["id","project_id","name","metric_name","aggregation","detection_kind","detection_config","window_secs","for_duration_secs","severity","enabled","last_state","label_filters","group_by","dynamic_alerts","max_series","grouped_notification_threshold","last_dropped_series_count","series_states","created_at","updated_at"],"properties":{"aggregation":{"type":"string"},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"detection_config":{"$ref":"#/components/schemas/DetectionConfig","description":"The typed detector definition (discriminated union keyed by `kind`)."},"detection_kind":{"type":"string","description":"Coarse detector discriminator: `static|anomaly|forecast|outlier|auto_watch`."},"dynamic_alerts":{"type":"boolean","description":"Whether per-series (\"dynamic\") alerting is enabled for this rule."},"enabled":{"type":"boolean"},"firing_series":{"type":"array","items":{"$ref":"#/components/schemas/FiringSeriesEntry"},"description":"Currently-firing series for a dynamic rule, snapshotted from the evaluator's\nin-memory firing map at read time. Empty for static/aggregate rules or when\nnothing is firing."},"for_duration_secs":{"type":"integer","format":"int32"},"group_by":{"type":"array","items":{"type":"string"},"description":"Label keys the rule breaks the metric down by. Empty = one aggregate stream."},"grouped_notification_threshold":{"type":"integer","format":"int32","description":"Notification-grouping threshold: when more than this many series fire in the\nsame tick, only the first gets chart/AI enrichment (1–1000)."},"id":{"type":"integer","format":"int32"},"label_filters":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"AND-combined label equality filters applied when evaluating this rule.\nEmpty = no filtering (matches all series)."},"last_dropped_series_count":{"type":"integer","format":"int32","description":"Number of series dropped by the cardinality cap on the latest dynamic tick\n(0 when nothing was dropped or for static/aggregate rules). Lets a UI warn\n\"N series were dropped this tick\" without reading server logs."},"last_evaluated_at":{"type":["string","null"],"example":"2025-10-12T12:15:47.609192Z"},"last_state":{"type":"string","description":"One of `ok|firing|unknown`."},"last_value":{"type":["number","null"],"format":"double"},"max_series":{"type":"integer","format":"int32","description":"Cardinality cap for dynamic alerting (1–100)."},"metric_name":{"type":"string"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"series_states":{"type":"object","description":"Full per-series state snapshot persisted after the latest dynamic-rule tick,\nkeyed by the human-readable series label (`endpoint=/checkout`). Empty for\nstatic/aggregate rules. Unlike `firing_series` (a live in-memory snapshot),\nthis is decoded from the persisted `series_states` jsonb column, so an\nexternal consumer that only reads the rule row still sees per-series detail.","additionalProperties":{"$ref":"#/components/schemas/SeriesStateEntry"},"propertyNames":{"type":"string"}},"severity":{"type":"string"},"updated_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"window_secs":{"type":"integer","format":"int32"}}},"OtelMetricAlertsResponse":{"type":"object","required":["data","total"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OtelMetricAlertRuleResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"OtelMetricLabelKeysResponse":{"type":"object","required":["keys"],"properties":{"keys":{"type":"array","items":{"type":"string"}}}},"OtelMetricLabelValuesResponse":{"type":"object","required":["values"],"properties":{"values":{"type":"array","items":{"type":"string"}}}},"OtelMetricNamesResponse":{"type":"object","required":["names"],"properties":{"names":{"type":"array","items":{"type":"string"}}}},"OtelMetricsResponse":{"type":"object","required":["data","count"],"properties":{"count":{"type":"integer","minimum":0},"data":{"type":"array","items":{"$ref":"#/components/schemas/MetricBucket"}}}},"OutlierAlgorithm":{"type":"string","description":"Outlier detection algorithm.","enum":["dbscan","scaled_dbscan","mad","scaled_mad"]},"OutlierParams":{"type":"object","description":"Outlier (cross-series population) detector parameters (stub — not evaluated).","required":["peer_group_key"],"properties":{"algorithm":{"$ref":"#/components/schemas/OutlierAlgorithm"},"peer_group_key":{"type":"string","description":"Label key defining the peer population compared across series (e.g. `host`)."},"tolerance":{"type":"number","format":"double","description":"Sensitivity; higher tolerates larger spread before flagging."}}},"OverprovisioningAssessment":{"type":"object","description":"Requests-vs-capacity-vs-usage assessment","required":["verdict","explanation"],"properties":{"cpu_request_inflation_ratio":{"type":["number","null"],"format":"double","description":"Ratio of requested CPU to measured CPU usage (e.g. 40.0 = requests\nreserve 40× what the workloads actually use). `None` without metrics."},"cpu_requested_pct":{"type":["number","null"],"format":"double","description":"Requested CPU as % of cluster capacity"},"cpu_utilization_pct":{"type":["number","null"],"format":"double","description":"Measured CPU usage as % of cluster capacity (`None` without metrics)"},"explanation":{"type":"string","description":"Human-readable explanation of the verdict, e.g. \"Cluster capacity is\n8 vCPU but measured usage is 0.3 vCPU (3.7%) — severely overprovisioned\""},"memory_request_inflation_ratio":{"type":["number","null"],"format":"double","description":"Ratio of requested memory to measured memory usage"},"memory_requested_pct":{"type":["number","null"],"format":"double","description":"Requested memory as % of cluster capacity"},"memory_utilization_pct":{"type":["number","null"],"format":"double","description":"Measured memory usage as % of cluster capacity (`None` without metrics)"},"verdict":{"$ref":"#/components/schemas/OverprovisioningVerdict","description":"Overall verdict"}}},"OverprovisioningVerdict":{"type":"string","description":"Overall overprovisioning verdict","enum":["severe","moderate","reasonable","unknown"]},"PageActivityBucket":{"type":"object","description":"Time bucket data point for page activity graph","required":["timestamp","visitors","page_views","avg_time_seconds"],"properties":{"avg_time_seconds":{"type":"number","format":"double","description":"Average time on page in seconds"},"page_views":{"type":"integer","format":"int64","description":"Number of page views in this bucket"},"timestamp":{"type":"string","description":"Timestamp for this bucket (ISO 8601)"},"visitors":{"type":"integer","format":"int64","description":"Number of unique visitors in this bucket"}}},"PageCountryStats":{"type":"object","description":"Geographic distribution of visitors for a page","required":["country","visitors","page_views","percentage"],"properties":{"country":{"type":"string","description":"Country name"},"country_code":{"type":["string","null"],"description":"ISO country code (2-letter)"},"page_views":{"type":"integer","format":"int64","description":"Number of page views from this country"},"percentage":{"type":"number","format":"double","description":"Percentage of total visitors"},"visitors":{"type":"integer","format":"int64","description":"Number of unique visitors from this country"}}},"PageFlowEntry":{"type":"object","description":"A single page with its entry/exit/bounce statistics","required":["page_path","entry_count","exit_count","bounce_count","total_views","entry_rate","exit_rate","bounce_rate"],"properties":{"avg_time_on_page":{"type":["number","null"],"format":"double","description":"Average time spent on this page in seconds"},"bounce_count":{"type":"integer","format":"int64","description":"Number of times visitors bounced on this page"},"bounce_rate":{"type":"number","format":"double","description":"Bounce rate: bounce_count / entry_count (only meaningful for entry pages)"},"entry_count":{"type":"integer","format":"int64","description":"Number of times this page was the entry page of a session"},"entry_rate":{"type":"number","format":"double","description":"Entry rate: entry_count / total_views"},"exit_count":{"type":"integer","format":"int64","description":"Number of times this page was the exit page of a session"},"exit_rate":{"type":"number","format":"double","description":"Exit rate: exit_count / total_views"},"page_path":{"type":"string","description":"The page path (e.g. \"/pricing\", \"/docs/getting-started\")"},"total_views":{"type":"integer","format":"int64","description":"Total page views for this page"}}},"PageFlowQuery":{"type":"object","description":"Query parameters for page flow analytics","required":["project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of entry/exit pages to return (default: 20)"},"min_views_for_dropoff":{"type":["integer","null"],"format":"int32","description":"Minimum views for drop-off analysis (default: 5)"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"},"transitions_limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of transitions to return (default: 50)"}}},"PageFlowResponse":{"type":"object","description":"Complete page flow analytics response","required":["top_entry_pages","top_exit_pages","drop_off_points","transitions","total_pages","total_sessions"],"properties":{"drop_off_points":{"type":"array","items":{"$ref":"#/components/schemas/DropOffPoint"},"description":"Top drop-off points (highest exit rates with meaningful traffic)"},"top_entry_pages":{"type":"array","items":{"$ref":"#/components/schemas/PageFlowEntry"},"description":"Top entry pages (where visitors land), sorted by entry_count DESC"},"top_exit_pages":{"type":"array","items":{"$ref":"#/components/schemas/PageFlowEntry"},"description":"Top exit pages (where visitors leave), sorted by exit_count DESC"},"total_pages":{"type":"integer","format":"int64","description":"Total unique pages seen in the period"},"total_sessions":{"type":"integer","format":"int64","description":"Total sessions in the period"},"transitions":{"type":"array","items":{"$ref":"#/components/schemas/PageTransition"},"description":"Page-to-page transitions (most common navigation paths)"}}},"PageHourlySessionsQuery":{"type":"object","description":"Query parameters for page hourly sessions endpoint","required":["page_path","project_id","start_time","end_time"],"properties":{"bucket_interval":{"type":["string","null"]},"end_time":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page_path":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"start_time":{"type":"string","format":"date-time"}}},"PageHourlySessionsResponse":{"type":"object","required":["page_path","hourly_data","total_sessions","hours"],"properties":{"hourly_data":{"type":"array","items":{"$ref":"#/components/schemas/HourlyPageSessions"}},"hours":{"type":"integer","format":"int32"},"page_path":{"type":"string"},"total_sessions":{"type":"integer","format":"int64"}}},"PagePathDetailQuery":{"type":"object","description":"Query parameters for page path detail analytics","required":["page_path","project_id","start_date","end_date"],"properties":{"bucket_interval":{"type":["string","null"],"description":"Bucket interval for time series: 'hour', 'day', 'week', 'month' (default: auto)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page_path":{"type":"string","description":"The specific page path to get details for (URL-encoded)"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"PagePathDetailResponse":{"type":"object","description":"Detailed analytics response for a specific page path","required":["page_path","unique_visitors","total_page_views","avg_time_on_page","bounce_rate","entry_rate","exit_rate","activity_over_time","countries","referrers","bucket_interval"],"properties":{"activity_over_time":{"type":"array","items":{"$ref":"#/components/schemas/PageActivityBucket"},"description":"Time series data for activity graph"},"avg_time_on_page":{"type":"number","format":"double","description":"Average time on page in seconds"},"bounce_rate":{"type":"number","format":"double","description":"Bounce rate percentage (0-100)"},"bucket_interval":{"type":"string","description":"Bucket interval used for time series ('hour', 'day', etc.)"},"countries":{"type":"array","items":{"$ref":"#/components/schemas/PageCountryStats"},"description":"Geographic distribution of visitors"},"entry_rate":{"type":"number","format":"double","description":"Entry rate - percentage of sessions that started on this page"},"exit_rate":{"type":"number","format":"double","description":"Exit rate - percentage of sessions that ended on this page"},"page_path":{"type":"string","description":"The page path being analyzed"},"referrers":{"type":"array","items":{"$ref":"#/components/schemas/PageReferrerStats"},"description":"Top referrers to this page"},"total_page_views":{"type":"integer","format":"int64","description":"Total page views in the date range"},"unique_visitors":{"type":"integer","format":"int64","description":"Total unique visitors to this page in the date range"}}},"PagePathInfo":{"type":"object","required":["page_path","session_count","page_view_count","first_seen","last_seen"],"properties":{"avg_time_seconds":{"type":["number","null"],"format":"double"},"first_seen":{"type":"string"},"last_seen":{"type":"string"},"page_path":{"type":"string"},"page_view_count":{"type":"integer","format":"int64"},"session_count":{"type":"integer","format":"int64"}}},"PagePathSparkline":{"type":"object","required":["page_path","points"],"properties":{"page_path":{"type":"string"},"points":{"type":"array","items":{"$ref":"#/components/schemas/PagePathSparklinePoint"}}}},"PagePathSparklinePoint":{"type":"object","required":["timestamp","session_count"],"properties":{"session_count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"}}},"PagePathVisitorsQuery":{"type":"object","description":"Query parameters for page path visitors","required":["page_path","project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page":{"type":["integer","null"],"format":"int64","description":"Page number (1-based, default: 1)","minimum":0},"page_path":{"type":"string","description":"The specific page path to get visitors for"},"per_page":{"type":["integer","null"],"format":"int64","description":"Items per page (default: 50, max: 100)","minimum":0},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"PagePathVisitorsResponse":{"type":"object","description":"Response for page path visitors endpoint","required":["page_path","total_count","page","per_page","sessions"],"properties":{"page":{"type":"integer","format":"int64","description":"Current page number","minimum":0},"page_path":{"type":"string","description":"The page path"},"per_page":{"type":"integer","format":"int64","description":"Items per page","minimum":0},"sessions":{"type":"array","items":{"$ref":"#/components/schemas/PageVisitorSession"},"description":"Individual visitor sessions"},"total_count":{"type":"integer","format":"int64","description":"Total number of visitor sessions matching the query"}}},"PagePathsQuery":{"type":"object","required":["project_id"],"properties":{"end_date":{"type":["string","null"],"format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":["string","null"],"format":"date-time"}}},"PagePathsResponse":{"type":"object","required":["page_paths","total_count"],"properties":{"page_paths":{"type":"array","items":{"$ref":"#/components/schemas/PagePathInfo"}},"total_count":{"type":"integer","minimum":0}}},"PagePathsSparklineQuery":{"type":"object","description":"Query parameters for batch page paths sparkline endpoint","required":["project_id","start_time","end_time","page_paths"],"properties":{"end_time":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page_paths":{"type":"string","description":"Comma-separated list of page paths"},"project_id":{"type":"integer","format":"int32"},"start_time":{"type":"string","format":"date-time"}}},"PagePathsSparklineResponse":{"type":"object","required":["sparklines"],"properties":{"sparklines":{"type":"array","items":{"$ref":"#/components/schemas/PagePathSparkline"}}}},"PageReferrerStats":{"type":"object","description":"Referrer source for the page","required":["referrer","visits","percentage"],"properties":{"percentage":{"type":"number","format":"double","description":"Percentage of total visits"},"referrer":{"type":"string","description":"Referrer URL or domain"},"visits":{"type":"integer","format":"int64","description":"Number of visits from this referrer"}}},"PageSessionComparison":{"type":"object","required":["page_path","date","session_count","event_count","avg_duration_seconds"],"properties":{"avg_duration_seconds":{"type":"number","format":"double"},"date":{"type":"string"},"event_count":{"type":"integer","format":"int64"},"page_path":{"type":"string"},"session_count":{"type":"integer","format":"int64"}}},"PageSessionStats":{"type":"object","required":["page_path","total_sessions","avg_time_seconds","min_time_seconds","max_time_seconds","total_page_views","avg_page_views_per_session"],"properties":{"avg_page_views_per_session":{"type":"number","format":"double"},"avg_time_seconds":{"type":"number","format":"double"},"max_time_seconds":{"type":"number","format":"double"},"min_time_seconds":{"type":"number","format":"double"},"page_path":{"type":"string"},"total_page_views":{"type":"integer","format":"int64"},"total_sessions":{"type":"integer","format":"int64"}}},"PageSessionStatsQuery":{"type":"object","required":["page_path","project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page_path":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"PageTransition":{"type":"object","description":"A page-to-page transition with count","required":["from_page","to_page","transition_count","percentage"],"properties":{"from_page":{"type":"string","description":"The source page path"},"percentage":{"type":"number","format":"double","description":"Percentage of transitions from the source page that go to this destination"},"to_page":{"type":"string","description":"The destination page path"},"transition_count":{"type":"integer","format":"int64","description":"Number of times this transition occurred"}}},"PageVisit":{"type":"object","required":["path","visits"],"properties":{"path":{"type":"string"},"visits":{"type":"integer","format":"int64"}}},"PageVisitorSession":{"type":"object","description":"Individual visitor session that viewed a specific page","required":["visitor_id","visitor_uuid","viewed_at","is_entry","is_exit","is_bounce"],"properties":{"browser":{"type":["string","null"],"description":"Browser name"},"city":{"type":["string","null"],"description":"Visitor's city"},"country":{"type":["string","null"],"description":"Visitor's country"},"country_code":{"type":["string","null"],"description":"Visitor's country code"},"device_type":{"type":["string","null"],"description":"Device type (Desktop, Mobile, Tablet)"},"is_bounce":{"type":"boolean","description":"Whether this was a bounce"},"is_entry":{"type":"boolean","description":"Whether this was the entry page for the session"},"is_exit":{"type":"boolean","description":"Whether this was the exit page for the session"},"operating_system":{"type":["string","null"],"description":"Operating system"},"referrer":{"type":["string","null"],"description":"Referrer URL"},"session_id":{"type":["string","null"],"description":"Session ID"},"session_page_number":{"type":["integer","null"],"format":"int32","description":"Page number in session flow"},"time_on_page":{"type":["integer","null"],"format":"int32","description":"Time spent on this page in seconds"},"viewed_at":{"type":"string","format":"date-time","description":"When the page was viewed"},"visitor_id":{"type":"integer","format":"int32","description":"Visitor numeric ID"},"visitor_uuid":{"type":"string","description":"Visitor UUID"}}},"PagesComparisonResponse":{"type":"object","required":["comparisons","page_paths"],"properties":{"comparisons":{"type":"array","items":{"$ref":"#/components/schemas/PageSessionComparison"}},"page_paths":{"type":"array","items":{"type":"string"}}}},"PaginatedEmailsResponse":{"type":"object","required":["data","total","page","page_size"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/EmailResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"PaginatedEntitiesResponse":{"type":"object","required":["entities","count","limit","has_more"],"properties":{"count":{"type":"integer","description":"Number of entities returned","minimum":0},"entities":{"type":"array","items":{"$ref":"#/components/schemas/EntityResponse"},"description":"List of entities"},"has_more":{"type":"boolean","description":"Whether there are more entities available"},"limit":{"type":"integer","description":"Limit used for this request","minimum":0},"next_token":{"type":["string","null"],"description":"Continuation token for next page (S3, etc.)"},"total":{"type":["integer","null"],"description":"Total number of entities (if available)","minimum":0}}},"PaginatedErrorEventsResponse":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ErrorEventResponse"}},"pagination":{"$ref":"#/components/schemas/PaginationMeta"}}},"PaginatedErrorGroupsResponse":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ErrorGroupResponse"}},"pagination":{"$ref":"#/components/schemas/PaginationMeta"}}},"PaginatedEventsResponse":{"type":"object","required":["events","total","page","page_size"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/TrackingEventResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"PaginatedExternalImagesResponse":{"type":"object","required":["data","total","page","page_size"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ExternalImageResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"PaginatedProjectList":{"type":"object","required":["projects","total","page","per_page"],"properties":{"page":{"type":"integer","format":"int64"},"per_page":{"type":"integer","format":"int64"},"projects":{"type":"array","items":{"$ref":"#/components/schemas/ProjectResponse"}},"total":{"type":"integer","format":"int64"}}},"PaginatedStaticBundlesResponse":{"type":"object","required":["data","total","page","page_size"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/StaticBundleResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"Pagination":{"type":"object","description":"SDK pagination cursor. We use opaque page numbers internally but\nexpose `count`/`next`/`prev` the way `@vercel/sandbox` expects.","required":["count"],"properties":{"count":{"type":"integer","format":"int64","minimum":0},"next":{"type":["integer","null"],"format":"int64","minimum":0},"prev":{"type":["integer","null"],"format":"int64","minimum":0}}},"PaginationMeta":{"type":"object","required":["page","page_size","total_count","total_pages"],"properties":{"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total_count":{"type":"integer","format":"int64","minimum":0},"total_pages":{"type":"integer","format":"int64","minimum":0}}},"PaginationParams":{"type":"object","properties":{"page":{"type":"integer","format":"int64"},"per_page":{"type":"integer","format":"int64"}}},"PasswordProtectionConfig":{"type":"object","description":"Password protection configuration\n\nWhen enabled, the proxy shows an HTML password form before allowing access.\nAfter the user enters the correct password, an HMAC-signed cookie is set\nso subsequent requests pass through without re-entering the password.","required":["enabled","passwordHash"],"properties":{"enabled":{"type":"boolean","description":"Whether password protection is enabled"},"passwordHash":{"type":"string","description":"The bcrypt-hashed password (never stored or returned in plaintext)"}}},"PatchSettingsRequest":{"type":"object","properties":{"auto_upgrade":{"type":["boolean","null"]},"host_port":{"type":["integer","null"],"format":"int32","minimum":0},"image":{"type":["string","null"]}}},"PathVisitors":{"type":"object","required":["name","visitors","percentage"],"properties":{"name":{"type":"string"},"percentage":{"type":"number","format":"double"},"visitors":{"type":"integer","format":"int64"}}},"PathVisitorsAnalyticsQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"PathVisitorsResponse":{"type":"object","required":["results"],"properties":{"results":{"type":"array","items":{"$ref":"#/components/schemas/PathVisitors"}}}},"PeerEntry":{"type":"object","description":"Wire-format peer entry. Matches `temps_network::config::Peer` but\nuses strings on the wire to keep the API stable across underlying\ntype evolution.","required":["node_id","compute_cidr","underlay_address"],"properties":{"compute_cidr":{"type":"string","description":"Per-node CIDR (e.g. `\"172.20.5.0/24\"`)."},"node_id":{"type":"string","description":"Stable v5 UUID derived from the database node id. Workers use\nthis as the kernel-layer identifier when calling\n`NetworkManager::reconcile_peers`."},"underlay_address":{"type":"string","description":"Address the local node should use to reach this peer over the\nunderlay (private VPC IP for same-DC, public IP for cross-DC)."}}},"PeerListResponse":{"type":"object","description":"Response body for `GET /internal/nodes/{node_id}/network/peers`.","required":["peers","cluster_dns_enabled"],"properties":{"alloc":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AllocEntry","description":"Caller's own allocation, or `null` if multi-host networking has\nnot been enabled for this node yet."}]},"cluster_dns_enabled":{"type":"boolean","description":"Whether the cluster-DNS resolver is enabled on this control plane\n(`AppSettings.cluster_dns.enabled`). Workers should start their\nper-node resolver and write `overlay_bridge_address` only when this\nis `true`. Always serialized (never `skip_serializing_if`) so older\nand newer version skew degrades to the safe default of `false`."},"peers":{"type":"array","items":{"$ref":"#/components/schemas/PeerEntry"},"description":"All other nodes with a `compute_cidr` set, excluding the caller."}}},"PendingActionResponse":{"type":"object","description":"A proposed AI write action awaiting human confirmation.","required":["public_id","operation_id","method","summary","status","step_index","params","created_at"],"properties":{"confirmed_at":{"type":["string","null"]},"created_at":{"type":"string"},"error":{"type":["string","null"]},"executed_at":{"type":["string","null"]},"method":{"type":"string"},"operation_id":{"type":"string"},"params":{"description":"The flat params to be replayed at execute time (shown pre-execution for review)."},"plan_public_id":{"type":["string","null"],"description":"Set when this action is one step of a multi-step plan (chained actions);\nall steps of the plan share this id. Absent for standalone single actions."},"public_id":{"type":"string"},"required_permission":{"type":["string","null"]},"result":{},"status":{"type":"string"},"step_index":{"type":"integer","format":"int32","description":"0-based order of this step within its plan (0 for standalone actions)."},"summary":{"type":"string"}}},"PerformanceMetricsQuery":{"allOf":[{"$ref":"#/components/schemas/SpeedSegmentFilters","description":"Segment filters (filter_path, filter_country, filter_region,\nfilter_city, filter_browser, filter_operating_system) — flattened so\neach remains a top-level query string param."},{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"device_type":{"type":["string","null"],"description":"Device type filter: \"desktop\" or \"mobile\""},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"include_bots":{"type":["boolean","null"],"description":"Include crawler/datacenter (bot) samples. Defaults to false — bots\nare excluded from the read view but always stored at ingest."},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}}]},"PerformanceMetricsResponse":{"type":"object","properties":{"cls":{"type":["number","null"],"format":"float"},"cls_p75":{"type":["number","null"],"format":"float"},"cls_p90":{"type":["number","null"],"format":"float"},"cls_p95":{"type":["number","null"],"format":"float"},"cls_p99":{"type":["number","null"],"format":"float"},"fcp":{"type":["number","null"],"format":"float"},"fcp_p75":{"type":["number","null"],"format":"float"},"fcp_p90":{"type":["number","null"],"format":"float"},"fcp_p95":{"type":["number","null"],"format":"float"},"fcp_p99":{"type":["number","null"],"format":"float"},"fid":{"type":["number","null"],"format":"float"},"fid_p75":{"type":["number","null"],"format":"float"},"fid_p90":{"type":["number","null"],"format":"float"},"fid_p95":{"type":["number","null"],"format":"float"},"fid_p99":{"type":["number","null"],"format":"float"},"inp":{"type":["number","null"],"format":"float"},"inp_p75":{"type":["number","null"],"format":"float"},"inp_p90":{"type":["number","null"],"format":"float"},"inp_p95":{"type":["number","null"],"format":"float"},"inp_p99":{"type":["number","null"],"format":"float"},"lcp":{"type":["number","null"],"format":"float"},"lcp_p75":{"type":["number","null"],"format":"float"},"lcp_p90":{"type":["number","null"],"format":"float"},"lcp_p95":{"type":["number","null"],"format":"float"},"lcp_p99":{"type":["number","null"],"format":"float"},"ttfb":{"type":["number","null"],"format":"float"},"ttfb_p75":{"type":["number","null"],"format":"float"},"ttfb_p90":{"type":["number","null"],"format":"float"},"ttfb_p95":{"type":["number","null"],"format":"float"},"ttfb_p99":{"type":["number","null"],"format":"float"}}},"PermissionInfo":{"type":"object","description":"Information about a single permission","required":["name","description","category"],"properties":{"category":{"type":"string","description":"Category of the permission (e.g., \"Projects\", \"Deployments\")"},"description":{"type":"string","description":"Human-readable description of the permission"},"name":{"type":"string","description":"The permission identifier (e.g., \"projects:read\")"}}},"PgUpgradeLogResponse":{"type":"object","required":["log_id","content"],"properties":{"content":{"type":"string"},"log_id":{"type":"string"}}},"PgUpgradeResponse":{"type":"object","required":["id","service_id","from_version","to_version","from_image","to_image","status","phase","log_id","attempt","created_at"],"properties":{"attempt":{"type":"integer","format":"int32"},"created_at":{"type":"string"},"error_message":{"type":["string","null"]},"finished_at":{"type":["string","null"]},"from_image":{"type":"string"},"from_version":{"type":"string"},"id":{"type":"integer","format":"int32"},"log_id":{"type":"string"},"phase":{"type":"string"},"pre_upgrade_backup_id":{"type":["integer","null"],"format":"int32"},"rollback_volume_name":{"type":["string","null"]},"service_id":{"type":"integer","format":"int32"},"started_at":{"type":["string","null"]},"status":{"type":"string"},"to_image":{"type":"string"},"to_version":{"type":"string"}}},"PipelineStats":{"type":"object","description":"Internal pipeline statistics for self-observability.","required":["metrics_received","metrics_stored","metrics_dropped","spans_received","spans_stored","spans_dropped","logs_received","logs_stored_db","logs_stored_s3","logs_dropped","ingest_errors"],"properties":{"ingest_errors":{"type":"integer","format":"int64","minimum":0},"logs_dropped":{"type":"integer","format":"int64","minimum":0},"logs_received":{"type":"integer","format":"int64","minimum":0},"logs_stored_db":{"type":"integer","format":"int64","minimum":0},"logs_stored_s3":{"type":"integer","format":"int64","minimum":0},"metrics_dropped":{"type":"integer","format":"int64","minimum":0},"metrics_received":{"type":"integer","format":"int64","minimum":0},"metrics_stored":{"type":"integer","format":"int64","minimum":0},"spans_dropped":{"type":"integer","format":"int64","minimum":0},"spans_received":{"type":"integer","format":"int64","minimum":0},"spans_stored":{"type":"integer","format":"int64","minimum":0}}},"PipelineStatsResponse":{"type":"object","required":["stats"],"properties":{"stats":{"$ref":"#/components/schemas/PipelineStats"}}},"PlanComplexity":{"type":"string","description":"Plan complexity indicator","enum":["low","medium","high"]},"PlanMetadata":{"type":"object","description":"Plan metadata","required":["generated_at","generator_version","complexity","warnings"],"properties":{"complexity":{"$ref":"#/components/schemas/PlanComplexity","description":"Estimated complexity (low, medium, high)"},"generated_at":{"type":"string","format":"date-time","description":"When the plan was generated"},"generator_version":{"type":"string","description":"Generator (importer) version"},"warnings":{"type":"array","items":{"type":"string"},"description":"Warnings detected during planning"}}},"PlanSourceBackup":{"type":"object","required":["location","location_was_resolved","format"],"properties":{"created_at":{"type":["string","null"]},"format":{"type":"string","description":"\"walg\", \"pg_dump\", \"unknown\"."},"id":{"type":["integer","null"],"format":"int32","description":"DB id, absent for orphan (S3-scan) backups."},"location":{"type":"string","description":"Resolved S3 location the orchestrator will actually use."},"location_was_resolved":{"type":"boolean","description":"True when the original row's `s3_location` was empty and we resolved\na location by probing S3. The UI shows this as a warning."},"origin_service_name":{"type":["string","null"],"description":"Service that originally produced the backup, if known."},"size_bytes":{"type":["integer","null"],"format":"int64"}}},"PlanTarget":{"type":"object","required":["id","name","container"],"properties":{"container":{"type":"string","description":"Expected Docker container name."},"id":{"type":"integer","format":"int32"},"name":{"type":"string"}}},"PlatformInfo":{"type":"object","description":"Platform compatibility information","required":["os_type","architecture","platforms"],"properties":{"architecture":{"type":"string","description":"System architecture (e.g., \"x86_64\", \"aarch64\")"},"os_type":{"type":"string","description":"Operating system type (e.g., \"linux\", \"windows\", \"darwin\")"},"platforms":{"type":"array","items":{"type":"string"},"description":"List of supported platforms in \"os/arch\" format (e.g., [\"linux/amd64\"])"}}},"PluginManifest":{"type":"object","description":"The complete plugin manifest — the handshake contract.","required":["name","version"],"properties":{"description":{"type":["string","null"],"description":"Short description of what the plugin does"},"display_name":{"type":["string","null"],"description":"Human-readable display name"},"events":{"type":"array","items":{"type":"string"},"description":"Platform event types the plugin subscribes to.\n\nWhen specified, Temps will POST matching events to the plugin's\n`/_events` endpoint. Uses dot-notation event names matching the\nwebhook event types (e.g., \"deployment.succeeded\", \"project.created\").\n\nAvailable events:\n- `deployment.created`, `deployment.succeeded`, `deployment.failed`,\n `deployment.cancelled`, `deployment.ready`\n- `project.created`, `project.deleted`\n- `domain.created`, `domain.provisioned`"},"health_path":{"type":"string","description":"Health check endpoint path (relative to plugin root)"},"name":{"type":"string","description":"Unique plugin identifier (kebab-case, e.g., \"backup-manager\")"},"nav":{"type":"array","items":{"$ref":"#/components/schemas/NavEntry"},"description":"Navigation entries for the UI sidebar"},"requires_db":{"type":"boolean","description":"Whether the plugin needs database access"},"ui":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/UiManifest","description":"UI bundle manifest (if the plugin has a UI)"}]},"version":{"type":"string","description":"SemVer version string"}}},"PortMapping":{"type":"object","description":"Port mapping","required":["container_port","protocol","is_primary"],"properties":{"container_port":{"type":"integer","format":"int32","description":"Container port","minimum":0},"host_port":{"type":["integer","null"],"format":"int32","description":"Host port (optional - can be assigned dynamically)","minimum":0},"is_primary":{"type":"boolean","description":"Whether this is the primary HTTP port"},"protocol":{"$ref":"#/components/schemas/Protocol","description":"Protocol (tcp, udp)"}}},"PostgresWalHealth":{"type":"object","required":["probed_at","pg_wal_bytes","max_wal_size_bytes","archive_mode","archive_backlog","stale_slots","oldest_wal_age_secs","warnings"],"properties":{"archive_backlog":{"type":"integer","format":"int64","description":"Number of `archive_status/*.ready` files — un-shipped WAL segments."},"archive_command":{"type":["string","null"],"description":"The literal `archive_command` setting. May be empty or `/bin/true`\nwhen archiving is effectively disabled despite `archive_mode = on`."},"archive_mode":{"$ref":"#/components/schemas/ArchiveMode"},"archiver_failed_count":{"type":["integer","null"],"format":"int64"},"archiver_last_failed_at":{"type":["string","null"],"format":"date-time"},"max_wal_size_bytes":{"type":"integer","format":"int64","description":"`max_wal_size` setting in bytes (parsed from `pg_settings`)."},"oldest_wal_age_secs":{"type":"integer","format":"int64","description":"Age of the oldest WAL file in `pg_wal/` (seconds)."},"pg_wal_bytes":{"type":"integer","format":"int64","description":"Total size of files under `pg_wal/`, from `pg_ls_waldir()`."},"probed_at":{"type":"string","format":"date-time","description":"When the snapshot was taken."},"stale_slots":{"type":"array","items":{"$ref":"#/components/schemas/StaleSlot"}},"warnings":{"type":"array","items":{"$ref":"#/components/schemas/WalWarning"},"description":"Computed warnings, ordered by severity (critical first)."}}},"PresetConfigSchema":{"oneOf":[{"$ref":"#/components/schemas/DockerfilePresetConfig","description":"Configuration for Dockerfile preset"},{"$ref":"#/components/schemas/DockerComposePresetConfig","description":"Configuration for Docker Compose"},{"$ref":"#/components/schemas/NixpacksPresetConfig","description":"Configuration for Nixpacks provider selection and inline build plan"},{"$ref":"#/components/schemas/StaticPresetConfig","description":"Configuration for static site presets (Vite, Next.js, etc.)"}],"description":"Union type for preset configurations\nUse the appropriate configuration type based on your preset"},"PresetInfo":{"type":"object","description":"Detected preset information","required":["path","preset","preset_label","project_type"],"properties":{"compose_files":{"type":["array","null"],"items":{"type":"string"},"description":"Compose file paths found in the repository (only for docker-compose preset)"},"exposed_port":{"type":["integer","null"],"format":"int32","description":"Default exposed port for this preset"},"icon_url":{"type":["string","null"],"description":"Icon URL for this preset"},"path":{"type":"string","description":"Path where preset was detected (empty for root)"},"preset":{"type":"string","description":"Preset slug (e.g., \"nextjs\", \"fastapi\")"},"preset_label":{"type":"string","description":"Human-readable preset label"},"project_type":{"type":"string","description":"Project type (e.g., \"frontend\", \"backend\", \"fullstack\")"}}},"PresetResponse":{"type":"object","required":["slug","label","icon_url","project_type","description"],"properties":{"default_port":{"type":["integer","null"],"format":"int32","description":"Default port the application listens on (None for static sites)","example":3000,"minimum":0},"description":{"type":"string","description":"Description of what this preset does"},"icon_url":{"type":"string","description":"Icon URL for the preset"},"label":{"type":"string","description":"Display name/label for the preset"},"project_type":{"type":"string","description":"Project type (server or static)"},"slug":{"type":"string","description":"Unique identifier slug for the preset"}}},"PreviewGatewaySettings":{"type":"object","description":"Workspace preview gateway settings.\n\nThe preview gateway is a single shared Docker container that lives on the\n`temps-sandbox-net` network and routes requests to workspace sandbox dev\nservers based on the `Host` header (`ws--.`).\n`temps serve` reconciles this container on startup; these settings let an\noperator override the image, host port, and auto-upgrade behavior.","properties":{"auto_upgrade":{"type":"boolean","description":"When true (default), the supervisor will pull and apply the image\npinned in the Temps binary on every startup. When false, the\ncurrently-running image is left alone — operators upgrade manually\nfrom the settings UI.","default":true,"example":true},"host_port":{"type":"integer","format":"int32","description":"Host port to publish the gateway on (always bound to 127.0.0.1).\nPingora forwards `ws-*` traffic to this port after authenticating.","default":8090,"example":8090,"minimum":0},"image":{"type":"string","description":"Docker image reference for the gateway. Pinned per Temps release.\nOperators can override this to test a custom build.","default":"ghcr.io/gotempsh/temps-preview-gateway:latest","example":"ghcr.io/gotempsh/temps-preview-gateway:latest"},"shared_secret":{"type":"string","description":"Shared secret the host-side Pingora sends on every forwarded preview\nrequest via `X-Temps-Preview-Token`; the gateway rejects requests\nwithout it. Auto-generated on first boot, persisted in DB so the\nsecret is stable across `temps serve` restarts regardless of cwd,\n`TEMPS_DATA_DIR`, or data-dir changes. MUST be masked (`***`) in any\nAPI response — never expose it over HTTP.","default":"","example":""}}},"PreviewGatewaySettingsMasked":{"type":"object","description":"Preview gateway settings with `shared_secret` elided.","required":["image","host_port","auto_upgrade","shared_secret_set"],"properties":{"auto_upgrade":{"type":"boolean"},"host_port":{"type":"integer","format":"int32","minimum":0},"image":{"type":"string"},"shared_secret_set":{"type":"boolean"}}},"PreviewGatewaySettingsResponse":{"type":"object","required":["image","host_port","auto_upgrade","default_image","default_host_port"],"properties":{"auto_upgrade":{"type":"boolean"},"default_host_port":{"type":"integer","format":"int32","description":"The compile-time default host port.","minimum":0},"default_image":{"type":"string","description":"The compile-time default image — exposed so the UI can offer a\n\"Reset to default\" link without round-tripping."},"host_port":{"type":"integer","format":"int32","minimum":0},"image":{"type":"string"}}},"PreviewShareLinkBody":{"type":"object","description":"Request body for minting a preview share link.","required":["port"],"properties":{"path":{"type":["string","null"],"description":"Path the recipient lands on. Must be same-origin (start with a single\n`/`); anything else is replaced with `/` so a share link can never be\nturned into an open redirect."},"port":{"type":"integer","format":"int32","description":"Port inside the sandbox the preview serves on.","minimum":0},"ttl_seconds":{"type":["integer","null"],"format":"int64","description":"How long the link stays usable, in seconds. Clamped to 24 hours.\nDefaults to one hour — long enough to send to a reviewer, short enough\nthat a link pasted in a ticket does not stay live indefinitely.","minimum":0}}},"PreviewShareLinkResponse":{"type":"object","required":["url","expires_at"],"properties":{"expires_at":{"type":"integer","format":"int64","description":"Unix seconds after which the link stops working.","minimum":0},"url":{"type":"string","description":"The full link. Its fragment contains the grant and must be treated as a\ncredential; URL fragments are not sent to servers or in Referer headers."}}},"PricingResponse":{"type":"object","required":["models"],"properties":{"models":{"type":"array","items":{"$ref":"#/components/schemas/ModelPricing"}}}},"ProblemDetails":{"type":"object","description":"Representation of a Problem error to return to the client.\nFollows RFC 7807 - Problem Details for HTTP APIs","required":["title","extensions"],"properties":{"detail":{"type":["string","null"],"description":"A human-readable explanation specific to this occurrence of the problem","example":"The server encountered an unexpected condition"},"extensions":{"type":"object","description":"Additional properties of the problem","additionalProperties":true},"instance":{"type":["string","null"],"description":"A URI reference that identifies the specific occurrence of the problem","example":"/account/12345/msgs/abc"},"title":{"type":"string","description":"A short, human-readable summary of the problem type","example":"Internal Server Error"},"type":{"type":["string","null"],"description":"A URI reference that identifies the problem type","example":"https://example.com/probs/out-of-memory"}},"example":{"type":"https://example.com/probs/out-of-memory","title":"Internal Server Error","detail":"The server encountered an unexpected condition","instance":"/account/12345/msgs/abc","additional_info":"Custom field with additional details"}},"ProjectAccessResponse":{"type":"object","required":["id","project_id","team_id","role","granted_by","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"},"granted_by":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"role":{"$ref":"#/components/schemas/TeamRole"},"team_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"}}},"ProjectConfiguration":{"type":"object","description":"Project-level configuration","required":["name","slug","project_type","is_web_app"],"properties":{"is_web_app":{"type":"boolean","description":"Whether this is a web application"},"name":{"type":"string","description":"Proposed project name"},"project_type":{"$ref":"#/components/schemas/ProjectType","description":"Project type"},"slug":{"type":"string","description":"Proposed slug (URL-safe identifier)"}}},"ProjectDSNResponse":{"type":"object","required":["id","project_id","name","public_key","dsn","created_at","is_active","event_count"],"properties":{"created_at":{"type":"string"},"deployment_id":{"type":["integer","null"],"format":"int32"},"dsn":{"type":"string"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_count":{"type":"integer","format":"int64"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"public_key":{"type":"string"}}},"ProjectDashboardAnalytics":{"type":"object","description":"Analytics data for a single project in the dashboard batch response","required":["project_id","unique_visitors","previous_unique_visitors","hourly_visits"],"properties":{"hourly_visits":{"type":"array","items":{"$ref":"#/components/schemas/EventTimeline"},"description":"Hourly sparkline data points"},"previous_unique_visitors":{"type":"integer","format":"int64","description":"Unique visitor count in the previous period (same duration, shifted back)"},"project_id":{"type":"integer","format":"int32"},"trend_percentage":{"type":["number","null"],"format":"double","description":"Percentage change from previous period (positive = growth, negative = decline)\nNull when previous period had zero visitors (no baseline to compare)"},"unique_visitors":{"type":"integer","format":"int64","description":"Unique visitor count in the current time range"}}},"ProjectHealthSummary":{"type":"object","description":"Health summary for a single project (last 1 hour)","required":["project_id","total_requests","total_errors","avg_response_time_ms","error_rate","status"],"properties":{"avg_response_time_ms":{"type":"number","format":"double","description":"Average response time in ms"},"error_rate":{"type":"number","format":"double","description":"Error rate as a percentage (0-100)"},"project_id":{"type":"integer","format":"int32"},"status":{"type":"string","description":"Health status: \"healthy\", \"degraded\", \"down\", \"unknown\""},"total_errors":{"type":"integer","format":"int64","description":"Total server errors (status >= 500) in the period"},"total_requests":{"type":"integer","format":"int64","description":"Total requests in the period"}}},"ProjectInfo":{"type":"object","required":["id","slug","created_at"],"properties":{"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"id":{"type":"integer","format":"int32"},"slug":{"type":"string"}}},"ProjectMonitorHealth":{"type":"object","description":"Health summary for a single project based on its production monitors","required":["project_id","status"],"properties":{"project_id":{"type":"integer","format":"int32"},"status":{"type":"string","description":"Overall status: \"operational\", \"degraded\", \"down\", or \"no_monitors\""}}},"ProjectPresetResponse":{"type":"object","required":["path","preset","presetLabel","projectType"],"properties":{"composeFiles":{"type":["array","null"],"items":{"type":"string"},"description":"Compose file paths found in the repository (only for docker-compose preset)"},"exposedPort":{"type":["integer","null"],"format":"int32","description":"Default exposed port for this preset (e.g., 3000 for Next.js, 8000 for FastAPI)"},"iconUrl":{"type":["string","null"],"description":"Icon URL for the preset"},"path":{"type":"string"},"preset":{"type":"string"},"presetLabel":{"type":"string"},"projectType":{"type":"string","description":"Project type category (e.g., \"frontend\", \"backend\", \"fullstack\")"}}},"ProjectQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"ProjectRef":{"type":"object","description":"A lightweight project descriptor included in `UnifiedTrace`.","required":["project_id","project_name","project_slug"],"properties":{"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"project_slug":{"type":"string","description":"URL slug used to link a span back into its owning project's trace view."}}},"ProjectResponse":{"type":"object","required":["id","slug","name","directory","main_branch","created_at","updated_at","deployment_config","attack_mode","ai_write_actions_enabled","error_source_context_enabled","enable_preview_environments","preview_envs_on_demand","preview_envs_idle_timeout_seconds","preview_envs_wake_timeout_seconds","source_type","cross_project_trace_sharing"],"properties":{"ai_alert_summaries_enabled":{"type":["boolean","null"],"description":"Opt-in to AI summarization of metric alert notifications (NULL/false = off)."},"ai_debug_chat_enabled":{"type":["boolean","null"],"description":"Opt-in to AI debugging chat, e.g. on deployment failures (NULL/false = off)."},"ai_write_actions_enabled":{"type":"boolean","description":"Opt-in to AI propose-then-confirm write capability (false = off)."},"attack_mode":{"type":"boolean","description":"Attack mode - when enabled, requires CAPTCHA verification for all project environments"},"created_at":{"type":"integer","format":"int64"},"cross_project_trace_sharing":{"type":"boolean","description":"ADR-027 Phase 3 opt-out: when false, this project's traces are suppressed\nfrom cross-project discovery results. Default true (consistent with the\nOSS global-observability model where any OtelRead holder can query any\nproject's telemetry)."},"deployment_config":{"$ref":"#/components/schemas/DeploymentConfig","description":"Deployment configuration (resources, autoscaling, features)"},"directory":{"type":"string"},"enable_preview_environments":{"type":"boolean","description":"Enable automatic preview environment creation for each branch"},"error_source_context_enabled":{"type":"boolean","description":"Opt-in to native error-tracking source context (false = off). When on,\nTemps stores uploaded source files and shows source code in stack traces."},"error_source_root":{"type":["string","null"],"description":"Where auto-capture reads source from (relative to the checkout). Null =\nthe deployment's Docker build context."},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"git_url":{"type":["string","null"],"description":"Git clone URL for the repository (used for public repos without a provider connection)"},"gitlab_webhook_id":{"type":["integer","null"],"format":"int32","description":"GitLab webhook ID installed on the connected repository.\n`null` when no GitLab webhook is installed (not connected to GitLab,\nor webhook was removed / never created).","example":42},"id":{"type":"integer","format":"int32"},"last_deployment":{"type":["integer","null"],"format":"int64"},"main_branch":{"type":"string"},"name":{"type":"string"},"preset":{"type":["string","null"]},"preset_config":{"description":"Preset-specific configuration (Dockerfile path, build context, etc.)"},"preview_envs_idle_timeout_seconds":{"type":"integer","format":"int32","description":"Idle timeout (seconds) for on-demand preview environments."},"preview_envs_on_demand":{"type":"boolean","description":"When true, newly-created preview environments default to on-demand mode\n(containers stop after the configured idle timeout to save resources)."},"preview_envs_wake_timeout_seconds":{"type":"integer","format":"int32","description":"Wake timeout (seconds) for on-demand preview environments."},"repo_name":{"type":["string","null"]},"repo_owner":{"type":["string","null"]},"slug":{"type":"string"},"source_type":{"$ref":"#/components/schemas/SourceType","description":"Source type for deployments (git, docker_image, or static_files)"},"updated_at":{"type":"integer","format":"int64"}}},"ProjectSecretEnvironmentInfo":{"type":"object","required":["id","name","main_url"],"properties":{"id":{"type":"integer","format":"int32"},"main_url":{"type":"string"},"name":{"type":"string"}}},"ProjectSecretResponse":{"type":"object","description":"Project secret metadata. There is deliberately no `value` field — secret\nplaintext is never returned after creation. Callers that need the value\nmust read it from the mounted file inside the container.","required":["id","project_id","key","include_in_preview","created_at","updated_at","environments"],"properties":{"created_at":{"type":"integer","format":"int64"},"environments":{"type":"array","items":{"$ref":"#/components/schemas/ProjectSecretEnvironmentInfo"}},"id":{"type":"integer","format":"int32"},"include_in_preview":{"type":"boolean"},"key":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"updated_at":{"type":"integer","format":"int64"}}},"ProjectServiceInfo":{"type":"object","required":["id","project","service"],"properties":{"id":{"type":"integer","format":"int32"},"project":{"$ref":"#/components/schemas/ProjectInfo"},"service":{"$ref":"#/components/schemas/ExternalServiceInfo"}}},"ProjectStatisticsResponse":{"type":"object","required":["total_count"],"properties":{"total_count":{"type":"integer","format":"int64"}}},"ProjectStatsBreakdown":{"type":"object","required":["project_id","unique_visitors","total_visits","total_page_views","bounce_rate","engagement_rate"],"properties":{"bounce_rate":{"type":"number","format":"double"},"engagement_rate":{"type":"number","format":"double"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":["string","null"]},"total_page_views":{"type":"integer","format":"int64"},"total_visits":{"type":"integer","format":"int64"},"unique_visitors":{"type":"integer","format":"int64"}}},"ProjectType":{"type":"string","description":"Project type enumeration","enum":["static","docker","buildpack","git"]},"ProjectUsageInfoResponse":{"type":"object","required":["id","name","slug","connection_id","connection_name"],"properties":{"connection_id":{"type":"integer","format":"int32"},"connection_name":{"type":"string"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"slug":{"type":"string"}}},"ProjectsHealthResponse":{"type":"object","description":"Batch health summary response","required":["projects"],"properties":{"projects":{"type":"object","description":"Health summaries keyed by project ID","additionalProperties":{"$ref":"#/components/schemas/ProjectHealthSummary"},"propertyNames":{"type":"string"}}}},"ProjectsMonitorHealthResponse":{"type":"object","description":"Batch response for projects health","required":["projects"],"properties":{"projects":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/ProjectMonitorHealth"},"propertyNames":{"type":"string"}}}},"PromoteDeploymentRequest":{"type":"object","required":["target_environment_id"],"properties":{"target_environment_id":{"type":"integer","format":"int32","description":"Target environment ID to promote the deployment to"}}},"PropertyBreakdownItem":{"type":"object","required":["value","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"percentage":{"type":"number","format":"double"},"value":{"type":"string"}}},"PropertyBreakdownQuery":{"type":"object","description":"Query parameters for property breakdown (group by column)","required":["start_date","end_date","group_by"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level"},"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment filter"},"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment filter"},"event_name":{"type":["string","null"],"description":"Optional event name filter (e.g., \"page_view\", \"click\")"},"filter_browser":{"type":["string","null"],"description":"Filter by browser name (for browser version drill-downs)"},"filter_channel":{"type":["string","null"],"description":"Filter by channel name (for channel -> referrer drill-downs)"},"filter_country":{"type":["string","null"],"description":"Filter by country (for region/city drill-downs). Requires geolocation join."},"filter_os":{"type":["string","null"],"description":"Filter by operating system name (for OS version drill-downs)"},"filter_referrer":{"type":["string","null"],"description":"Filter by referrer hostname (for referrer -> pages drill-downs)"},"filter_region":{"type":["string","null"],"description":"Filter by region (for city drill-downs). Requires geolocation join."},"group_by":{"$ref":"#/components/schemas/PropertyColumn","description":"Property column to group by"},"limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of results to return (default: 20, max: 100)"},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"PropertyBreakdownResponse":{"type":"object","required":["property","items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/PropertyBreakdownItem"}},"property":{"type":"string"},"total":{"type":"integer","format":"int64"}}},"PropertyColumn":{"type":"string","enum":["channel","device_type","browser","browser_version","operating_system","operating_system_version","utm_source","utm_medium","utm_campaign","utm_term","utm_content","referrer_hostname","language","event_type","event_name","page_path","pathname","country","region","city"]},"PropertyTimelineItem":{"type":"object","required":["timestamp","value","count"],"properties":{"count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"},"value":{"type":"string"}}},"PropertyTimelineQuery":{"type":"object","description":"Query parameters for property timeline (group by column over time)","required":["start_date","end_date","group_by"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level"},"bucket_size":{"type":["string","null"],"description":"Time bucket size: \"hour\", \"day\", \"week\", \"month\" (default: auto-detect)"},"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment filter"},"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment filter"},"event_name":{"type":["string","null"],"description":"Optional event name filter"},"group_by":{"$ref":"#/components/schemas/PropertyColumn","description":"Property column to group by"},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"PropertyTimelineResponse":{"type":"object","required":["property","bucket_size","items"],"properties":{"bucket_size":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/PropertyTimelineItem"}},"property":{"type":"string"}}},"Protocol":{"type":"string","description":"Network protocol","enum":["tcp","udp"]},"ProviderCatalogDto":{"type":"object","description":"One catalog entry rendered for the settings UI.","required":["id","name","install_command","auth_command","auth_flavors","models","credential_saved","supports_max_turns"],"properties":{"auth_command":{"type":"string"},"auth_flavors":{"type":"array","items":{"$ref":"#/components/schemas/AuthFlavorDto"}},"credential_saved":{"type":"boolean","description":"True when a credential is currently saved for this provider in the\nsettings JSON. Lets the UI render \"Configured\" badges without the\nfrontend having to inspect the encrypted blob."},"current_auth_type":{"type":["string","null"],"description":"Currently saved auth flavor id (when `credential_saved` is true).\n`None` when no credential is saved yet."},"default_model":{"type":["string","null"],"description":"Currently saved default model id for this provider, if one was\npicked. `None` means \"use the CLI's own default\" — the UI renders\nthat as \"Use provider default\"."},"id":{"type":"string"},"install_command":{"type":"string"},"max_turns_analysis":{"type":["integer","null"],"format":"int32","description":"Default max turns for the autofixer analysis phase. `None` = built-in\ndefault (10). Only enforced for CLIs with a turn flag (Claude Code)."},"max_turns_feedback":{"type":["integer","null"],"format":"int32","description":"Default max turns for autofixer feedback rounds. `None` = built-in\ndefault (10)."},"max_turns_fix":{"type":["integer","null"],"format":"int32","description":"Default max turns for the autofixer fix phase. `None` = built-in\ndefault (20)."},"models":{"type":"array","items":{"type":"string"},"description":"Model ids this provider accepts, in display order. The first entry is\nthe recommended default. Empty when the provider doesn't expose model\nselection (e.g. OpenCode), which the UI uses to hide the dropdown."},"name":{"type":"string"},"supports_max_turns":{"type":"boolean","description":"True when this provider's CLI supports enforcing a turn cap. False\nfor Codex/OpenCode, which run to completion — the UI labels their\nmax-turns inputs accordingly."}}},"ProviderCatalogResponse":{"type":"object","required":["default_provider","providers"],"properties":{"default_provider":{"type":"string","description":"Active provider id from `agent_sandbox.default_provider`. The settings\nUI uses this to highlight which card is the active one."},"providers":{"type":"array","items":{"$ref":"#/components/schemas/ProviderCatalogDto"}}}},"ProviderConfig":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/StripeConfig"},{"type":"object","required":["provider"],"properties":{"provider":{"type":"string","enum":["stripe"]}}}]},{"allOf":[{"$ref":"#/components/schemas/LemonSqueezyConfig"},{"type":"object","required":["provider"],"properties":{"provider":{"type":"string","enum":["lemon_squeezy"]}}}]}],"description":"Provider-specific integration settings persisted in\n`revenue_integrations.config`.\n\nThe tag is the lowercase provider name, so adding a new provider\nmeans adding a new variant and the existing rows are untouched.\nOld rows (pre-config) and rows with `NULL` config are treated as\n\"accept all events, no filtering\" via [`ProviderConfig::default_for`]."},"ProviderConfigMasked":{"type":"object","required":["auth_type","credential_saved","extra"],"properties":{"auth_type":{"type":"string"},"credential_saved":{"type":"boolean","description":"True if a credential is stored for this provider. The encrypted blob\nis never returned over HTTP."},"default_model":{"type":["string","null"]},"extra":{}}},"ProviderDeletionCheckResponse":{"type":"object","required":["can_delete","projects_in_use","message"],"properties":{"can_delete":{"type":"boolean"},"message":{"type":"string"},"projects_in_use":{"type":"array","items":{"$ref":"#/components/schemas/ProjectUsageInfoResponse"}}}},"ProviderDescriptor":{"type":"object","required":["name","display_name","recommended_events"],"properties":{"display_name":{"type":"string"},"name":{"type":"string"},"recommended_events":{"type":"array","items":{"type":"string"}}}},"ProviderKeyResponse":{"type":"object","required":["id","provider","display_name","api_key_masked","is_active","created_at","updated_at"],"properties":{"api_key_masked":{"type":"string","description":"Masked API key (only last 4 chars visible)"},"base_url":{"type":["string","null"]},"created_at":{"type":"string"},"default_model":{"type":["string","null"],"description":"Model id this provider serves (NULL → per-provider default)."},"display_name":{"type":"string"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"provider":{"type":"string"},"updated_at":{"type":"string"}}},"ProviderMetadata":{"type":"object","required":["service_type","display_name","description","icon_url","color"],"properties":{"color":{"type":"string","example":"#336791"},"description":{"type":"string","example":"Relational database management system"},"display_name":{"type":"string","example":"PostgreSQL"},"icon_url":{"type":"string","example":"https://cdn.simpleicons.org/postgresql"},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute"}}},"ProviderResponse":{"type":"object","required":["id","name","provider_type","auth_method","is_active","is_default","created_at","updated_at"],"properties":{"auth_method":{"type":"string"},"base_url":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"is_default":{"type":"boolean"},"name":{"type":"string"},"provider_type":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}},"ProviderUsage":{"type":"object","required":["provider","request_count","input_tokens","output_tokens","avg_latency_ms","error_count"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"error_count":{"type":"integer","format":"int64"},"input_tokens":{"type":"integer","format":"int64"},"output_tokens":{"type":"integer","format":"int64"},"provider":{"type":"string"},"request_count":{"type":"integer","format":"int64"}}},"ProvisionResponse":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/DomainError"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["error"]}}}]},{"allOf":[{"$ref":"#/components/schemas/DomainResponse"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["complete"]}}}]},{"allOf":[{"$ref":"#/components/schemas/DomainChallengeResponse"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["pending"]}}}]}]},"ProxyLogResponse":{"type":"object","description":"Response model for proxy logs","required":["id","timestamp","method","path","host","status_code","request_source","is_system_request","routing_status","request_id"],"properties":{"bot_name":{"type":["string","null"]},"browser":{"type":["string","null"]},"browser_version":{"type":["string","null"]},"cache_status":{"type":["string","null"]},"client_ip":{"type":["string","null"]},"container_id":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"device_type":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"error_message":{"type":["string","null"]},"host":{"type":"string"},"id":{"type":"integer","format":"int32"},"ip_geolocation_id":{"type":["integer","null"],"format":"int32"},"is_bot":{"type":["boolean","null"]},"is_system_request":{"type":"boolean"},"method":{"type":"string"},"operating_system":{"type":["string","null"]},"path":{"type":"string"},"project_id":{"type":["integer","null"],"format":"int32"},"query_string":{"type":["string","null"]},"referrer":{"type":["string","null"]},"request_id":{"type":"string"},"request_size_bytes":{"type":["integer","null"],"format":"int64"},"request_source":{"type":"string"},"response_size_bytes":{"type":["integer","null"],"format":"int64"},"response_time_ms":{"type":["integer","null"],"format":"int32"},"routing_status":{"type":"string"},"session_id":{"type":["integer","null"],"format":"int32"},"status_code":{"type":"integer","format":"int32"},"timestamp":{"type":"string"},"upstream_host":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":["integer","null"],"format":"int32"}}},"ProxyLogsPaginatedResponse":{"type":"object","description":"Paginated response for proxy logs","required":["logs","total","page","page_size","total_pages"],"properties":{"logs":{"type":"array","items":{"$ref":"#/components/schemas/ProxyLogResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0},"total_pages":{"type":"integer","format":"int64","minimum":0}}},"PublicHostnameStrategy":{"type":"string","description":"Public hostname generation mode for Temps-managed preview routes.\n\nThe mode is stored per managed domain (`dns_managed_domains.generated_hostname_mode`)\nrather than globally, so a provider such as Cloudflare can offer the flat layout\nrequired by its Universal SSL wildcard cert without changing every domain's behaviour.","enum":["standard","flat"]},"PublicPresetResponse":{"type":"object","description":"Response for preset detection","required":["branch","presets"],"properties":{"branch":{"type":"string","description":"Branch name where presets were detected"},"presets":{"type":"array","items":{"$ref":"#/components/schemas/PresetInfo"},"description":"List of detected presets"}}},"PublicRepositoryInfo":{"type":"object","description":"Public repository information","required":["owner","name","full_name","default_branch","stars","forks"],"properties":{"default_branch":{"type":"string","description":"Default branch name"},"description":{"type":["string","null"],"description":"Repository description"},"forks":{"type":"integer","format":"int32","description":"Fork count"},"full_name":{"type":"string","description":"Full repository name (owner/repo)"},"language":{"type":["string","null"],"description":"Primary programming language"},"name":{"type":"string","description":"Repository name"},"owner":{"type":"string","description":"Repository owner"},"stars":{"type":"integer","format":"int32","description":"Star count"}}},"PurgeLogsRequest":{"type":"object","required":["before"],"properties":{"before":{"type":"string","description":"Delete all logs before this timestamp (ISO 8601)"}}},"PushImageRequest":{"type":"object","description":"Request to push an external image","required":["image_ref"],"properties":{"image_ref":{"type":"string"},"metadata":{}}},"PushedExternalImageResponse":{"type":"object","description":"Response for in-memory external image operations (legacy push flow).\n\nRenamed to avoid shadowing the richer database-backed `ExternalImageResponse`\nin `handlers/remote_deployments.rs`. The two types serve different routes\n(`/images` ephemeral push vs `/external-images` registered images).","required":["id","image_ref","pushed_at"],"properties":{"digest":{"type":["string","null"]},"id":{"type":"string"},"image_ref":{"type":"string"},"pushed_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"size":{"type":["integer","null"],"format":"int64","minimum":0}}},"QueryDataRequest":{"type":"object","properties":{"filters":{"description":"JSON filters (backend-specific format)"},"limit":{"type":"integer","description":"Maximum number of rows to return","example":100,"minimum":0},"offset":{"type":"integer","description":"Number of rows to skip","example":0,"minimum":0},"sort_by":{"type":["string","null"],"description":"Sort by field name"},"sort_order":{"type":["string","null"],"description":"Sort order (asc/desc)"}}},"QueryDataResponse":{"type":"object","required":["fields","rows","total_count","returned_count","execution_time_ms"],"properties":{"execution_time_ms":{"type":"integer","format":"int64","description":"Query execution time in milliseconds","example":45,"minimum":0},"fields":{"type":"array","items":{"$ref":"#/components/schemas/FieldResponse"},"description":"Field definitions"},"returned_count":{"type":"integer","description":"Number of rows returned in this response","example":100,"minimum":0},"rows":{"type":"array","items":{},"description":"Data rows (array of JSON objects)"},"total_count":{"type":"integer","format":"int64","description":"Total number of rows matching the query (before limit/offset)","example":1234,"minimum":0}}},"QuotaResponse":{"type":"object","required":["quota"],"properties":{"quota":{"$ref":"#/components/schemas/StorageQuota"}}},"RateLimitConfig":{"type":"object","description":"Rate limiting configuration (subset of global RateLimitSettings)","properties":{"blacklistIps":{"type":"array","items":{"type":"string"},"description":"Blacklist specific IPs for this project/environment"},"maxRequestsPerHour":{"type":["integer","null"],"format":"int32","description":"Override rate limit per hour","minimum":0},"maxRequestsPerMinute":{"type":["integer","null"],"format":"int32","description":"Override rate limit per minute","minimum":0},"whitelistIps":{"type":"array","items":{"type":"string"},"description":"Whitelist specific IPs for this project/environment"}}},"RateLimitSettings":{"type":"object","properties":{"blacklist_ips":{"type":"array","items":{"type":"string"},"default":[]},"enabled":{"type":"boolean","default":false},"max_requests_per_hour":{"type":"integer","format":"int32","default":1000,"minimum":0},"max_requests_per_minute":{"type":"integer","format":"int32","default":60,"minimum":0},"whitelist_ips":{"type":"array","items":{"type":"string"},"default":[]}}},"ReachabilityStatus":{"type":"string","description":"Email reachability status","enum":["safe","risky","invalid","unknown"]},"ReadFileResponse":{"type":"object","required":["path","contents_b64","size"],"properties":{"contents_b64":{"type":"string","description":"File contents, base64-encoded. Symmetric with `WriteFileBody`."},"path":{"type":"string"},"size":{"type":"integer","format":"int64","minimum":0}}},"RecentActivityQuery":{"type":"object","description":"Query parameters for recent activity endpoint","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32","description":"Environment ID (optional)"},"limit":{"type":["integer","null"],"format":"int32","description":"Max number of events to return (default: 50, max: 100)"},"project_id":{"type":"integer","format":"int32","description":"Project ID"},"since_id":{"type":["integer","null"],"format":"int64","description":"Return events with ID greater than this (for cursor-based polling)"}}},"RecentActivityResponse":{"type":"object","description":"Response for recent activity events endpoint","required":["events","count"],"properties":{"count":{"type":"integer","description":"Total events returned","minimum":0},"events":{"type":"array","items":{"$ref":"#/components/schemas/ActivityEvent"},"description":"Recent events, newest first"}}},"RecentEventResponse":{"type":"object","required":["occurred_at","event_type"],"properties":{"amount_minor":{"type":["integer","null"],"format":"int64"},"currency":{"type":["string","null"]},"customer_ref":{"type":["string","null"]},"event_type":{"type":"string"},"mrr_minor":{"type":["integer","null"],"format":"int64"},"occurred_at":{"type":"string","format":"date-time"}}},"RecentQueryParams":{"type":"object","properties":{"conversation_id":{"type":["string","null"],"description":"Filter by conversation ID"},"cost_gt":{"type":["integer","null"],"format":"int64","description":"Cost strictly greater-than, in microcents"},"cost_gte":{"type":["integer","null"],"format":"int64","description":"Cost greater-than-or-equal, in microcents"},"cost_lt":{"type":["integer","null"],"format":"int64","description":"Cost strictly less-than, in microcents"},"cost_lte":{"type":["integer","null"],"format":"int64","description":"Cost less-than-or-equal, in microcents"},"limit":{"type":["integer","null"],"format":"int64","description":"Page size (defaults to 20, max 50)","minimum":0},"model":{"type":["string","null"],"description":"Filter by model name"},"offset":{"type":["integer","null"],"format":"int64","description":"Number of results to skip for pagination (defaults to 0)","minimum":0},"provider":{"type":["string","null"],"description":"Filter by provider name"},"status":{"type":["integer","null"],"format":"int32","description":"Filter by HTTP status code (exact match)"},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"tokens_gt":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) strictly greater-than"},"tokens_gte":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) greater-than-or-equal"},"tokens_lt":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) strictly less-than"},"tokens_lte":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) less-than-or-equal"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"RecordExposureRequest":{"type":"object","description":"Keys a running app actually evaluated since its last report.","required":["keys"],"properties":{"keys":{"type":"array","items":{"type":"string"},"description":"Flag keys evaluated since the last report. Unknown keys are ignored.","example":["checkout.v2","api.rate_limit"]}}},"RecordExposureResponse":{"type":"object","required":["recorded"],"properties":{"recorded":{"type":"integer","format":"int64","description":"How many keys were accepted for processing.\n\nDeliberately not the number of rows updated: echoing that back would\nlet a caller post a single candidate key and read the result as \"this\nflag exists\", turning the endpoint into an existence oracle.","minimum":0}}},"RecordListResponse":{"type":"object","description":"Record list response","required":["records"],"properties":{"records":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecord"}}}},"RecoveryTarget":{"oneOf":[{"type":"object","description":"Recover to a specific timestamp.","required":["time","kind"],"properties":{"kind":{"type":"string","enum":["time"]},"time":{"type":"string","format":"date-time"}}},{"type":"object","description":"Recover to a specific transaction id (Postgres).","required":["xid","kind"],"properties":{"kind":{"type":"string","enum":["xid"]},"xid":{"type":"string"}}},{"type":"object","description":"Recover to a specific log sequence number (Postgres).","required":["lsn","kind"],"properties":{"kind":{"type":"string","enum":["lsn"]},"lsn":{"type":"string"}}},{"type":"object","description":"Recover to a named restore point created via `pg_create_restore_point` (Postgres).","required":["name","kind"],"properties":{"kind":{"type":"string","enum":["name"]},"name":{"type":"string"}}}],"description":"Engine-specific recovery target for PITR.\n\nPostgres honors all variants; Redis/Mongo/S3 will likely reject non-Time\nvariants or define their own semantics when they grow PITR support."},"ReferrerCount":{"type":"object","required":["referrer","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"percentage":{"type":"number","format":"double"},"referrer":{"type":"string"}}},"ReferrersAnalyticsQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"RegenerateDSNRequest":{"type":"object","properties":{"base_url":{"type":["string","null"]}}},"RegisterImageRequest":{"type":"object","required":["image_ref"],"properties":{"digest":{"type":["string","null"],"description":"Image digest (sha256:...)","example":"sha256:abc123def456"},"image_ref":{"type":"string","description":"Docker image reference (e.g., \"ghcr.io/org/app:v1.0\")","example":"ghcr.io/myorg/myapp:v1.0"},"metadata":{"description":"Additional metadata"},"tag":{"type":["string","null"],"description":"Image tag","example":"v1.0"}}},"RegisterNodeApiRequest":{"type":"object","required":["name","token","address","private_address"],"properties":{"address":{"type":"string","description":"Node's reachable address (e.g., \"10.100.0.2\" or \"192.168.1.50\")"},"architecture":{"type":["string","null"],"description":"Container platform of this node's Docker daemon (`linux/amd64`,\n`linux/arm64`). Optional: agents older than multi-arch support omit it\nand the value is learned from the first heartbeat instead."},"csr_pem":{"type":["string","null"],"description":"Node-generated certificate signing request (PEM) for multi-node mTLS\n(ADR-020 WS-2.1). When present, the control plane signs it with the\ncluster CA and returns the leaf + CA cert. Optional — token-only nodes\n(legacy / edge) still register without one."},"edge_public_key":{"type":["string","null"],"description":"X25519 public key for ECIES certificate encryption (base64-encoded, edge nodes only)"},"join_token":{"type":["string","null"],"description":"Join token to authorize this registration (must match the token generated in Settings)"},"labels":{"description":"Labels for scheduling (e.g., {\"region\": \"us-east\", \"gpu\": \"true\"})"},"name":{"type":"string","description":"Unique name for this node"},"prior_token":{"type":["string","null"],"description":"The node's *current* token, supplied to prove possession when\nre-registering (changing the identity of) a node that already exists.\nOptional; only needed to rebind a still-live node. (ADR-020 WS-1.2.)"},"private_address":{"type":"string","description":"Private/WireGuard address for inter-node communication"},"public_endpoint":{"type":["string","null"],"description":"Public endpoint for WireGuard (e.g., \"203.0.113.1:51820\")"},"role":{"type":["string","null"],"description":"Node role (default: \"worker\")"},"token":{"type":"string","description":"Registration token (plaintext, will be hashed before storage)"},"wg_public_key":{"type":["string","null"],"description":"WireGuard public key"}}},"RegisterNodeResponse":{"type":"object","required":["id","name","status","message"],"properties":{"ca_cert_pem":{"type":["string","null"],"description":"The cluster CA certificate (PEM) the node pins as its trust root.\nPresent only when a `csr_pem` was supplied. (ADR-020 WS-2.1.)"},"cert_pem":{"type":["string","null"],"description":"The signed per-node leaf certificate (PEM) the agent serves as its TLS\nserver cert. Present only when a `csr_pem` was supplied. (ADR-020 WS-2.1.)"},"id":{"type":"integer","format":"int32"},"message":{"type":"string"},"name":{"type":"string"},"status":{"type":"string"}}},"RegisterRequest":{"type":"object","required":["email","password","name"],"properties":{"email":{"type":"string"},"name":{"type":"string"},"password":{"type":"string"}}},"ReinstallWebhookResponse":{"type":"object","description":"Response for `POST /projects/{project_id}/gitlab/reinstall-webhook`","required":["hook_id","message"],"properties":{"hook_id":{"type":"integer","format":"int32","description":"The new GitLab hook ID that was installed."},"message":{"type":"string","description":"Human-readable status message."}}},"ReleaseListResponse":{"type":"object","required":["releases"],"properties":{"releases":{"type":"array","items":{"type":"string"}}}},"ReloadResponse":{"type":"object","description":"Response from the reload endpoint.","required":["loaded","plugins","message"],"properties":{"loaded":{"type":"integer","description":"Number of plugins successfully loaded after reload","minimum":0},"message":{"type":"string","description":"Human-readable status message"},"plugins":{"type":"array","items":{"type":"string"},"description":"Names of loaded plugins"}}},"RemoteDeploymentResponse":{"type":"object","required":["id","project_id","environment_id","slug","state","source_type","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"environment_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"slug":{"type":"string"},"source_type":{"type":"string"},"state":{"type":"string"}}},"RemoveNodeResponse":{"type":"object","required":["id","message"],"properties":{"id":{"type":"integer","format":"int32"},"message":{"type":"string"}}},"RenameConversationRequest":{"type":"object","required":["title"],"properties":{"title":{"type":"string","description":"New human-facing title. Trimmed; must be non-empty after trimming."}}},"RepositoryListQuery":{"type":"object","properties":{"direction":{"type":["string","null"]},"language":{"type":["string","null"]},"owner":{"type":["string","null"]},"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0},"private":{"type":["boolean","null"]},"search":{"type":["string","null"]},"sort":{"type":["string","null"]}}},"RepositoryListResponse":{"type":"object","required":["repositories","total_count"],"properties":{"repositories":{"type":"array","items":{"$ref":"#/components/schemas/RepositoryResponse"}},"total_count":{"type":"integer","minimum":0}}},"RepositoryPresetResponse":{"type":"object","required":["repository_id","owner","name","presets","calculated_at"],"properties":{"calculated_at":{"type":"string","format":"date-time"},"name":{"type":"string"},"owner":{"type":"string"},"presets":{"type":"array","items":{"$ref":"#/components/schemas/ProjectPresetResponse"}},"repository_id":{"type":"integer","format":"int32"}}},"RepositoryResponse":{"type":"object","required":["id","owner","name","full_name","private","default_branch","created_at","updated_at","pushed_at","git_provider_connection_id"],"properties":{"clone_url":{"type":["string","null"],"description":"HTTPS clone URL (e.g., https://github.com/owner/repo.git)"},"created_at":{"type":"string","format":"date-time"},"default_branch":{"type":"string"},"description":{"type":["string","null"]},"full_name":{"type":"string"},"git_provider_connection_id":{"type":"integer","format":"int32","description":"ID of the git provider connection this repository was synced from."},"id":{"type":"integer","format":"int32"},"language":{"type":["string","null"]},"name":{"type":"string"},"owner":{"type":"string"},"preset":{"type":["array","null"],"items":{"$ref":"#/components/schemas/ProjectPresetResponse"}},"private":{"type":"boolean"},"pushed_at":{"type":"string","format":"date-time"},"ssh_url":{"type":["string","null"],"description":"SSH clone URL (e.g., git@github.com:owner/repo.git)"},"updated_at":{"type":"string","format":"date-time"}}},"RepositorySyncStartedResponse":{"type":"object","description":"Returned by `POST /git-connections/{id}/sync` to acknowledge that a\nsync has been kicked off in the background. Clients should poll the\nconnection's `syncing` and `synced_repository_count` fields to track\nprogress rather than waiting on this response.","required":["connection_id","syncing","started_at"],"properties":{"connection_id":{"type":"integer","format":"int32"},"started_at":{"type":"string","format":"date-time"},"syncing":{"type":"boolean"}}},"RequestRow":{"type":"object","required":["id","ts","method","host","path","status","request_headers","response_headers","headers_truncated"],"properties":{"client_ip":{"type":["string","null"]},"country":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_group_id":{"type":["integer","null"],"format":"int32"},"headers_truncated":{"type":"boolean"},"host":{"type":"string"},"id":{"type":"string","description":"The request's unique `request_id` (assigned by the proxy). Used as the\nrow identity instead of the storage PK because the ClickHouse backend\nhas no serial id (rows come back with `id = 0`) while `request_id` is\nunique and present on both backends."},"latency_ms":{"type":["integer","null"],"format":"int32"},"method":{"type":"string"},"path":{"type":"string"},"query_string":{"type":["string","null"]},"referrer":{"type":["string","null"]},"request_headers":{},"response_headers":{},"status":{"type":"integer","format":"int32"},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"},"user_agent":{"type":["string","null"]}}},"ResetPasswordRequest":{"type":"object","required":["token","new_password"],"properties":{"new_password":{"type":"string"},"token":{"type":"string"}}},"ResetPgStatStatementsRequest":{"type":"object","description":"Explicit confirmation required for the destructive statistics reset.\n\nRequiring JSON makes the endpoint non-simple for browsers, preventing a\ndeployed same-site application from triggering it with a plain HTML form.","required":["confirm"],"properties":{"confirm":{"type":"boolean","description":"Must be `true` to acknowledge the global, irreversible reset."}}},"ResetPgStatStatementsResponse":{"type":"object","description":"Response for the pg_stat_statements reset endpoint.","required":["message"],"properties":{"message":{"type":"string","description":"Human-readable message confirming the destructive action."}}},"ResizeSandboxBody":{"type":"object","required":["disk_size_mb"],"properties":{"disk_size_mb":{"type":"integer","format":"int64","description":"New root disk size in MB. Grow-only; must exceed the current size.","minimum":0}},"additionalProperties":false},"ResolvedEnvVarResponse":{"type":"object","description":"One entry in the computed env-var view that merges manual and integration\nsources and tags each result with its origin. `value_preview` is always\nmasked — plaintext must be fetched per-key via the existing reveal endpoint,\nwhich is audit-logged.","required":["key","value_preview","source","environments","include_in_preview"],"properties":{"environments":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentInfo"},"description":"Environments this var applies to. For integration-sourced vars this\nreflects every environment of the project (integrations are global)."},"include_in_preview":{"type":"boolean","description":"Whether the var would be auto-applied to preview environments.\nIntegration vars always surface in preview; manual vars follow the flag."},"key":{"type":"string"},"source":{"$ref":"#/components/schemas/ResolvedEnvVarSource"},"value_preview":{"type":"string","description":"Masked or truncated preview. Never the raw value."}}},"ResolvedEnvVarSource":{"oneOf":[{"type":"object","description":"Manually-defined env var. If `overrides_service` is set, this key would\notherwise have been supplied by an integration — the UI should show the\nintegration icon plus an \"overridden\" indicator.","required":["var_id","type"],"properties":{"overrides_service":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/EnvVarIntegrationInfo"}]},"type":{"type":"string","enum":["manual"]},"var_id":{"type":"integer","format":"int32"}}},{"type":"object","description":"Supplied by a linked external service (Postgres, Redis, S3, etc.).","required":["service","type"],"properties":{"service":{"$ref":"#/components/schemas/EnvVarIntegrationInfo"},"type":{"type":"string","enum":["integration"]}}}],"description":"Where a resolved env var comes from. Integration-sourced vars may be\n\"shadowed\" by a manual entry with the same key, in which case the response\ncarries `Manual` with `overrides_service` populated so the UI can still show\nthe integration icon."},"ResourceCounts":{"type":"object","description":"Quick count of resources involved in the migration","required":["projects","environments","deployments","environment_variables","services","domains"],"properties":{"deployments":{"type":"integer","minimum":0},"domains":{"type":"integer","minimum":0},"environment_variables":{"type":"integer","minimum":0},"environments":{"type":"integer","minimum":0},"projects":{"type":"integer","minimum":0},"services":{"type":"integer","minimum":0}}},"ResourceFootprint":{"type":"object","description":"A CPU + memory footprint (requests or measured usage)","required":["cpu_millis","memory_mb"],"properties":{"cpu_millis":{"type":"integer","format":"int64","description":"CPU in millicores"},"memory_mb":{"type":"integer","format":"int64","description":"Memory in MB"}}},"ResourceInfo":{"type":"object","description":"Resource attributes extracted from OTel resource descriptors.","required":["service_name","attributes"],"properties":{"attributes":{"type":"object"},"deployment_environment":{"type":["string","null"]},"service_name":{"type":"string"},"service_version":{"type":["string","null"]}}},"ResourceLimitApplyResult":{"type":"object","description":"Per-container outcome of a live `docker update` call. Surfaced from the\nPATCH /resources endpoint so the UI can tell the operator whether the\nnew caps are already in effect or whether they only apply on next\nrecreate (e.g., container was missing).","required":["role","container_name","outcome"],"properties":{"container_name":{"type":"string"},"error":{"type":["string","null"],"description":"Populated only when `outcome == \"failed\"`."},"outcome":{"type":"string","description":"One of:\n- \"applied\" — Docker accepted the update; caps are live now.\n- \"missing\" — container does not exist; caps stored, will apply on next start.\n- \"stopped\" — container exists but isn't running; Docker still\n accepts the update (the new caps apply on next start).\n- \"failed\" — `docker update` returned an error (see `error`)."},"role":{"type":"string","description":"`service_members.role` for cluster members; \"standalone\" otherwise."}}},"ResourceLimits":{"type":"object","description":"Resource limits and requests","properties":{"cpu_limit":{"type":["integer","null"],"format":"int32","description":"CPU limit (millicores)"},"cpu_request":{"type":["integer","null"],"format":"int32","description":"CPU request (millicores)"},"memory_limit":{"type":["integer","null"],"format":"int32","description":"Memory limit (MB)"},"memory_request":{"type":["integer","null"],"format":"int32","description":"Memory request (MB)"}}},"ResourceLimitsResponse":{"type":"object","description":"Container resource limits","properties":{"cpu_limit":{"type":["integer","null"],"format":"int32"},"cpu_request":{"type":["integer","null"],"format":"int32"},"memory_limit":{"type":["integer","null"],"format":"int32"},"memory_request":{"type":["integer","null"],"format":"int32"}}},"ResourceLimitsUpdateResponse":{"type":"object","description":"Response from PATCH /external-services/{id}/resources.","required":["limits","applied"],"properties":{"applied":{"type":"array","items":{"$ref":"#/components/schemas/ResourceLimitApplyResult"},"description":"Per-container result of trying to apply the limits live."},"limits":{"$ref":"#/components/schemas/ServiceResourceLimits","description":"The limits that were persisted to the encrypted config."}}},"ResourcesBody":{"type":"object","description":"Nested `resources: { memory, vcpus }` as sent by `@vercel/sandbox`.\n`memory` is in MB, `vcpus` is fractional CPU count.","properties":{"memory":{"type":["integer","null"],"format":"int64","minimum":0},"vcpus":{"type":["number","null"],"format":"double"}}},"RestoreCapabilities":{"type":"object","description":"Capabilities a service exposes for the generic restore framework.\n\nEach engine overrides `ExternalService::restore_capabilities` to declare\nwhat it supports. The handler layer uses this to validate requests and\nthe UI uses it to conditionally show options (e.g., PITR picker).","required":["restore_in_place","restore_to_new_service","pitr"],"properties":{"earliest_pitr_time":{"type":["string","null"],"format":"date-time","description":"Earliest recoverable timestamp, if `pitr` is true. Derived from\nengine-specific archive metadata (e.g., `pg_stat_archiver`)."},"latest_pitr_time":{"type":["string","null"],"format":"date-time","description":"Latest recoverable timestamp, if `pitr` is true."},"pitr":{"type":"boolean","description":"Point-in-time recovery using engine-specific continuous archives\n(WAL for Postgres, AOF for Redis, oplog for MongoDB, object versions for S3)."},"restore_in_place":{"type":"boolean","description":"Restore a backup onto the same running service (destructive)."},"restore_to_new_service":{"type":"boolean","description":"Restore a backup into a freshly provisioned service."}}},"RestoreCapabilitiesResponse":{"allOf":[{"$ref":"#/components/schemas/RestoreCapabilities","description":"Trait-declared capabilities."},{"type":"object","required":["suggested_new_service_name"],"properties":{"suggested_new_service_name":{"type":"string","description":"Suggested name for the new service when creating a clone. Safe to\npre-fill into the UI dialog; the user can edit before submitting."}}}]},"RestorePlan":{"type":"object","description":"Preview of a restore operation. Answers \"what will happen if I click\nstart?\" with engine-level specificity so the user can confirm before\ncommitting to a destructive action.","required":["engine","target_service","source_backup","strategy","steps","warnings","errors","destructive","mode"],"properties":{"destructive":{"type":"boolean","description":"Whether any step overwrites existing data on the target service."},"engine":{"type":"string","description":"Target engine (\"postgres\", etc.)."},"errors":{"type":"array","items":{"type":"string"},"description":"Blocking problems. The UI disables the Start button when non-empty."},"mode":{"type":"string","description":"Echo of the requested mode for the UI."},"source_backup":{"$ref":"#/components/schemas/PlanSourceBackup","description":"Backup we'll read from."},"steps":{"type":"array","items":{"type":"string"},"description":"Ordered list of human-readable actions the orchestrator will take."},"strategy":{"type":"string","description":"How the restore will be performed: \"walg_restore\", \"pg_dump_restore\",\nor \"unsupported\"."},"target_service":{"$ref":"#/components/schemas/PlanTarget","description":"Service we'll operate on (or provision a sibling of)."},"warnings":{"type":"array","items":{"type":"string"},"description":"Non-blocking caveats the user should see (cross-service, empty\nlocation that will be auto-resolved, missing engine metadata, ...)."}}},"RestoreRequestMode":{"oneOf":[{"type":"object","description":"Restore the backup onto the existing service (destructive).","required":["mode"],"properties":{"mode":{"type":"string","enum":["in_place"]}}},{"type":"object","description":"Provision a new service and restore into it.","required":["name","mode"],"properties":{"mode":{"type":"string","enum":["new_service"]},"name":{"type":"string","description":"Name for the new service. Orchestrator auto-suggests\n`{source}-restore-{yyyymmdd-hhmm}` if caller omits, but we require\nan explicit value at the API boundary."},"parameter_overrides":{"description":"Optional parameter overrides (port, docker_image, database)."}}},{"type":"object","description":"Point-in-time recovery. Only valid on WAL-G backups (Postgres).","required":["to_new_service","target","mode"],"properties":{"mode":{"type":"string","enum":["pitr"]},"new_service_name":{"type":["string","null"],"description":"Required when `to_new_service` is true."},"target":{"$ref":"#/components/schemas/RecoveryTarget","description":"Recovery target kind + value."},"to_new_service":{"type":"boolean","description":"Whether PITR restores in place or creates a new service."}}}],"description":"What the caller wants to do. Mirrors `externalsvc::RestoreMode` but\nflattened for JSON over the wire."},"RestoreRunView":{"type":"object","required":["id","source_backup_id","source_service_id","mode","status","phase","created_at"],"properties":{"created_at":{"type":"string"},"error_message":{"type":["string","null"]},"finished_at":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"mode":{"type":"string"},"phase":{"type":"string"},"recovery_target":{},"source_backup_id":{"type":"integer","format":"int32"},"source_service_id":{"type":"integer","format":"int32"},"started_at":{"type":["string","null"]},"status":{"type":"string"},"target_service_id":{"type":["integer","null"],"format":"int32"},"target_service_name":{"type":["string","null"]}}},"RetentionCleanupFailure":{"type":"object","required":["backup_id","reason","partial","deleted_objects"],"properties":{"backup_id":{"type":"string"},"deleted_objects":{"type":"integer","format":"int64","minimum":0},"partial":{"type":"boolean"},"reason":{"type":"string"}}},"RetentionCleanupReport":{"type":"object","required":["dry_run","expired","deleted","failed","failures","deleted_backup_ids","deleted_backup_ids_truncated","partially_deleted_backup_ids","partially_deleted_backup_ids_truncated","candidate_backup_ids","candidate_backup_ids_truncated"],"properties":{"candidate_backup_ids":{"type":"array","items":{"type":"string"},"description":"Capped sample of backups selected by the retention policy."},"candidate_backup_ids_truncated":{"type":"boolean"},"deleted":{"type":"integer","format":"int64","minimum":0},"deleted_backup_ids":{"type":"array","items":{"type":"string"},"description":"Capped sample of deleted backup UUIDs for audit attribution."},"deleted_backup_ids_truncated":{"type":"boolean"},"dry_run":{"type":"boolean","description":"True when this report is a non-destructive preview."},"expired":{"type":"integer","format":"int64","minimum":0},"failed":{"type":"integer","format":"int64","minimum":0},"failures":{"type":"array","items":{"$ref":"#/components/schemas/RetentionCleanupFailure"},"description":"Capped diagnostic sample; `failed` remains the authoritative total."},"partially_deleted_backup_ids":{"type":"array","items":{"type":"string"}},"partially_deleted_backup_ids_truncated":{"type":"boolean"},"schedule_id":{"type":["integer","null"],"format":"int32","description":"Schedule scope, or `None` when every schedule was considered."}}},"RetryClusterRequest":{"type":"object","description":"Request body for retrying a failed cluster initialization.","properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/ClusterMemberRequest"},"description":"Cluster member specifications (same format as create).\nIf omitted, the original member configuration is reconstructed from\nthe preserved service_members records."}}},"RevenueRow":{"type":"object","required":["id","ts","provider","event_type"],"properties":{"amount_minor":{"type":["integer","null"],"format":"int64"},"currency":{"type":["string","null"]},"customer_ref":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_type":{"type":"string"},"id":{"type":"integer","format":"int64"},"provider":{"type":"string"},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"}}},"RiskLevel":{"type":"string","description":"Risk level for a migration step","enum":["none","low","medium","high","critical"]},"RoleInfo":{"type":"object","description":"Information about a role","required":["name","description","permissions"],"properties":{"description":{"type":"string","description":"Human-readable description of the role"},"name":{"type":"string","description":"The role identifier (e.g., \"admin\")"},"permissions":{"type":"array","items":{"type":"string"},"description":"Permissions included in this role"}}},"RootfsCacheEntry":{"type":"object","description":"A cached rootfs image (Firecracker backend). Digest-keyed build artifact\nshared by all VMs created from the same image.","required":["digest","bytes","referenced_by"],"properties":{"bytes":{"type":"integer","format":"int64","description":"Actual on-disk size in bytes (sparse-aware).","minimum":0},"digest":{"type":"string","description":"Image digest this rootfs was built from (the cache key)."},"referenced_by":{"type":"array","items":{"type":"string"},"description":"IDs of live sandboxes whose per-VM disk was cloned from this entry.\nEmpty means the entry is reclaimable — no sandbox needs it."}}},"RootfsGcReport":{"type":"object","description":"Outcome of a rootfs garbage-collection pass.","required":["removed_digests","freed_bytes"],"properties":{"freed_bytes":{"type":"integer","format":"int64","minimum":0},"removed_digests":{"type":"array","items":{"type":"string"},"description":"Digests of cache entries removed because no sandbox referenced them."}}},"RootfsReport":{"type":"object","description":"Snapshot of a backend's rootfs storage for the management API. Backends\nwithout a rootfs concept (Docker, local) return an empty report.","required":["cache_bytes","cache","vm_bytes","vms"],"properties":{"cache":{"type":"array","items":{"$ref":"#/components/schemas/RootfsCacheEntry"}},"cache_bytes":{"type":"integer","format":"int64","minimum":0},"vm_bytes":{"type":"integer","format":"int64","minimum":0},"vms":{"type":"array","items":{"$ref":"#/components/schemas/RootfsVmEntry"}}}},"RootfsVmEntry":{"type":"object","description":"A per-sandbox rootfs disk (Firecracker backend). One per non-destroyed\nsandbox — the authoritative storage, independent of the cache.","required":["sandbox_name","bytes","running"],"properties":{"bytes":{"type":"integer","format":"int64","minimum":0},"running":{"type":"boolean"},"sandbox_name":{"type":"string"}}},"RouteRefreshResponse":{"type":"object","required":["route_count","message"],"properties":{"message":{"type":"string","description":"Human-readable message"},"route_count":{"type":"integer","description":"Number of routes loaded","minimum":0}}},"RouteResponse":{"type":"object","required":["id","domain","host","port","enabled","route_type","created_at","updated_at"],"properties":{"created_at":{"type":"integer","format":"int64"},"domain":{"type":"string"},"enabled":{"type":"boolean"},"host":{"type":"string"},"id":{"type":"integer","format":"int32"},"port":{"type":"integer","format":"int32"},"route_type":{"type":"string","description":"Route type: \"http\" or \"tls\""},"updated_at":{"type":"integer","format":"int64"}}},"RouteRole":{"type":"object","required":["id","name","created_at","updated_at"],"properties":{"created_at":{"type":"integer","format":"int64","example":"1683900000000"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"updated_at":{"type":"integer","format":"int64","example":"1683900000000"}}},"RouteUser":{"type":"object","required":["id","name","username","email","image","mfa_enabled","email_verified","created_at","updated_at"],"properties":{"created_at":{"type":"integer","format":"int64","example":"1683900000000"},"deleted_at":{"type":["integer","null"],"format":"int64"},"email":{"type":"string"},"email_verified":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"image":{"type":"string"},"mfa_enabled":{"type":"boolean"},"name":{"type":"string"},"updated_at":{"type":"integer","format":"int64","example":"1683900000000"},"username":{"type":"string"}}},"RouteUserWithRoles":{"type":"object","required":["user","roles"],"properties":{"roles":{"type":"array","items":{"$ref":"#/components/schemas/RouteRole"}},"user":{"$ref":"#/components/schemas/RouteUser"}}},"RunBackupRequest":{"type":"object","required":["backup_type"],"properties":{"backup_type":{"type":"string","description":"Type of backup to perform","example":"full"}}},"RunExternalServiceBackupRequest":{"type":"object","properties":{"backup_type":{"type":["string","null"],"description":"Type of backup to perform (e.g., \"full\", \"incremental\")","example":"full"},"s3_source_id":{"type":["integer","null"],"format":"int32","description":"ID of the S3 source to store the backup. If omitted, the current default S3 source is used.","example":1}}},"S3ConnectionTestResponse":{"type":"object","description":"Response body for an S3 connection test.","required":["ok","message"],"properties":{"message":{"type":"string","description":"Human-readable message (success confirmation or error detail)."},"ok":{"type":"boolean","description":"Whether the connection and credentials worked."}}},"S3CredentialsResponse":{"type":"object","description":"S3 credentials distributed to agents for backup/restore operations.","required":["access_key_id","secret_key","region","bucket_name","force_path_style"],"properties":{"access_key_id":{"type":"string"},"bucket_name":{"type":"string"},"endpoint":{"type":["string","null"]},"force_path_style":{"type":"boolean"},"region":{"type":"string"},"secret_key":{"type":"string"}}},"S3SourceResponse":{"type":"object","description":"Response type for S3 source","required":["id","name","bucket_name","bucket_path","access_key_id","secret_key","region","is_default","created_at","updated_at"],"properties":{"access_key_id":{"type":"string","example":"AKIAXXXXXXXXXXXXXXXX"},"bucket_name":{"type":"string"},"bucket_path":{"type":"string"},"created_at":{"type":"integer","format":"int64"},"endpoint":{"type":["string","null"],"example":"http://minio.example.com:9000"},"force_path_style":{"type":["boolean","null"]},"id":{"type":"integer","format":"int32"},"is_default":{"type":"boolean"},"name":{"type":"string"},"region":{"type":"string"},"secret_key":{"type":"string","writeOnly":true},"updated_at":{"type":"integer","format":"int64"}}},"SandboxDomainResponse":{"type":"object","required":["url"],"properties":{"url":{"type":"string"}}},"SandboxEvent":{"type":"object","description":"One entry in a sandbox's operations timeline.","required":["event_type","at"],"properties":{"at":{"type":"integer","format":"int64","description":"Unix epoch milliseconds."},"detail":{"description":"Optional structured context (shape depends on `event_type`)."},"event_type":{"type":"string","description":"Machine-readable operation (`created`, `stopped`, `resumed`,\n`restarted`, `timeout_extended`, `resized`, `preview_password_set`,\n`preview_password_cleared`, `preview_share_link_created`, `source_seeded`,\n`destroyed`)."}}},"SandboxEventsResponse":{"type":"object","required":["events"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/SandboxEvent"}}}},"SandboxInner":{"type":"object","description":"Inner `sandbox` object in `@vercel/sandbox` responses. Strict shape —\nthe SDK's zod validator rejects missing required fields.","required":["id","memory","vcpus","region","runtime","timeout","status","requestedAt","createdAt","updatedAt","cwd","name","preview_url_template"],"properties":{"agent_run_id":{"type":["integer","null"],"format":"int32","description":"Agent run this sandbox executes (autofixer / workflow agent).\n`None` for sandboxes created via this API."},"backend":{"type":["string","null"],"description":"Isolation backend: \"docker\" | \"firecracker\". `None` on legacy rows\ncreated before the backend was recorded."},"createdAt":{"type":"integer","format":"int64"},"cwd":{"type":"string"},"disk_size_mb":{"type":["integer","null"],"format":"int64","description":"Configured root disk size in MB (Firecracker). `None` when unknown or\nthe default.","minimum":0},"id":{"type":"string"},"image":{"type":["string","null"]},"memory":{"type":"integer","format":"int64","minimum":0},"name":{"type":"string"},"preview_password_hint":{"type":["string","null"]},"preview_url_template":{"type":"string"},"region":{"type":"string"},"requestedAt":{"type":"integer","format":"int64","description":"Creation time as Unix epoch milliseconds."},"runtime":{"type":"string"},"status":{"type":"string"},"timeout":{"type":"integer","format":"int64","description":"Idle timeout in milliseconds (SDK convention).","minimum":0},"updatedAt":{"type":"integer","format":"int64"},"vcpus":{"type":"number","format":"double"}}},"SandboxResponse":{"type":"object","description":"`@vercel/sandbox` wraps every single-sandbox response as\n`{ sandbox: {...}, routes: [...] }`. The SDK reads both.","required":["sandbox","routes"],"properties":{"routes":{"type":"array","items":{"$ref":"#/components/schemas/SandboxRoute"}},"sandbox":{"$ref":"#/components/schemas/SandboxInner"}}},"SandboxRoute":{"type":"object","description":"A single preview route, one per declared port. We don't know ports\nupfront, so we surface an empty array by default — SDK clients use\ntheir own port when calling `sandbox.domain(port)`.","required":["url","subdomain","port"],"properties":{"port":{"type":"integer","format":"int32","minimum":0},"subdomain":{"type":"string"},"url":{"type":"string"}}},"SandboxStatusResponse":{"type":"object","required":["docker_available","image_ready","image_name","firecracker_available"],"properties":{"docker_available":{"type":"boolean"},"error":{"type":["string","null"]},"firecracker_available":{"type":"boolean"},"image_name":{"type":"string"},"image_ready":{"type":"boolean"}}},"SaveAgentTokenRequest":{"type":"object","required":["token"],"properties":{"token":{"type":"string","description":"The OAuth token from `claude setup-token` or an API key.\nWill be encrypted before storage."}}},"SaveAgentTokenResponse":{"type":"object","required":["saved"],"properties":{"saved":{"type":"boolean"}}},"SaveCredentialRequest":{"type":"object","required":["auth_type","credential"],"properties":{"auth_type":{"type":"string","description":"Auth flavor id (must match one of the provider's catalog entries)."},"credential":{"type":"string","description":"Plaintext credential body (API key, OAuth token, or full config file\ncontents). Encrypted with `EncryptionService` before being persisted\ninside the `agent_sandbox.providers` JSON map."}}},"SaveCredentialResponse":{"type":"object","required":["saved","provider_id","auth_type"],"properties":{"auth_type":{"type":"string"},"provider_id":{"type":"string"},"saved":{"type":"boolean"}}},"ScalewayCredentialsRequest":{"type":"object","required":["api_key","project_id"],"properties":{"api_key":{"type":"string","example":"scw-secret-key-12345"},"project_id":{"type":"string","example":"12345678-1234-1234-1234-123456789012"}}},"ScanResponse":{"type":"object","required":["id","project_id","scanner_type","status","total_count","critical_count","high_count","medium_count","low_count","unknown_count","started_at","created_at","updated_at"],"properties":{"branch":{"type":["string","null"]},"commit_hash":{"type":["string","null"]},"completed_at":{"type":["string","null"],"example":"2025-12-08T12:15:47.609192Z"},"created_at":{"type":"string","example":"2025-12-08T12:15:47.609192Z"},"critical_count":{"type":"integer","format":"int32"},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_message":{"type":["string","null"]},"high_count":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"low_count":{"type":"integer","format":"int32"},"medium_count":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"scanner_type":{"type":"string"},"scanner_version":{"type":["string","null"]},"started_at":{"type":"string","example":"2025-12-08T12:15:47.609192Z"},"status":{"type":"string"},"total_count":{"type":"integer","format":"int32"},"unknown_count":{"type":"integer","format":"int32"},"updated_at":{"type":"string","example":"2025-12-08T12:15:47.609192Z"}}},"ScheduleRunEntry":{"type":"object","description":"A single run-history entry for the schedule detail page (deliverable 1).\n\nCombines one `backups` row with the most-recent `backup_jobs` row for that\nbackup via a lateral JOIN. Fields from `backup_jobs` are `None` for legacy\nbackup rows that pre-date ADR-014.","required":["backup_id","backup_uuid","state","started_at","s3_location"],"properties":{"attempts":{"type":["integer","null"],"format":"int32","description":"Number of claim-and-run attempts so far. `None` for legacy rows."},"backup_id":{"type":"integer","format":"int32","description":"DB id of the `backups` row."},"backup_uuid":{"type":"string","description":"UUID string (`backups.backup_id`)."},"current_step":{"type":["string","null"],"description":"Last completed step reported by the engine (e.g. `\"upload\"`).\n`None` when no step has been persisted yet."},"error_message":{"type":["string","null"],"description":"Engine-reported error message when `state = \"failed\"`."},"finished_at":{"type":["string","null"],"description":"When the backup finished, if known."},"job_id":{"type":["integer","null"],"format":"int64","description":"Most recent `backup_jobs.id` for this backup. `None` for legacy rows."},"s3_location":{"type":"string","description":"S3 object key or URL where the backup data lives."},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Final size in bytes once completed. `None` while running."},"started_at":{"type":"string","description":"When the backup was started (ISO 8601 / RFC 3339)."},"state":{"type":"string","description":"Current state: `\"pending\"`, `\"running\"`, `\"completed\"`, `\"failed\"`."}}},"ScheduleRunJobEntry":{"type":"object","description":"A single job entry inside an expanded schedule run, returned by\n[`BackupService::list_schedule_run_jobs`].","required":["backup_id","backup_uuid","engine","service_name","state","started_at","s3_source_id"],"properties":{"backup_id":{"type":"integer","format":"int32","description":"`backups.id` for this job."},"backup_uuid":{"type":"string","description":"`backups.backup_id` UUID string."},"engine":{"type":"string","description":"Engine key (e.g. `\"control_plane\"`, `\"redis\"`)."},"error_message":{"type":["string","null"],"description":"Engine-reported error message when `state = \"failed\"`."},"finished_at":{"type":["string","null"],"description":"When this child backup finished, if known."},"s3_source_id":{"type":"integer","format":"int32","description":"FK to `s3_sources.id` — needed for the backup detail link."},"service_id":{"type":["integer","null"],"format":"int32","description":"`external_services.id` — `NULL` for the control-plane job."},"service_name":{"type":"string","description":"Name of the external service, or `\"control plane\"` for the\ncontrol-plane job."},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size in bytes once completed; `None` while running."},"started_at":{"type":"string","description":"When this child backup started (ISO 8601 / RFC 3339)."},"state":{"type":"string","description":"Current state of this child backup."}}},"ScheduleRunListResponse":{"type":"object","description":"Paginated run-history response for a backup schedule (deliverable 1).","required":["runs","total","page","page_size"],"properties":{"page":{"type":"integer","format":"int64","description":"Current page (1-based)."},"page_size":{"type":"integer","format":"int64","description":"Number of items per page (clamped to 1–100)."},"runs":{"type":"array","items":{"$ref":"#/components/schemas/ScheduleRunEntry"},"description":"Run entries, newest first."},"total":{"type":"integer","format":"int64","description":"Total number of runs across all pages."}}},"ScheduleRunResponse":{"type":"object","description":"HTTP response body for `POST /api/backups/schedules/{id}/run` (fan-out).","required":["schedule_run_id","jobs"],"properties":{"jobs":{"type":"array","items":{"$ref":"#/components/schemas/EnqueuedJob"},"description":"All jobs that were enqueued in this fan-out."},"schedule_run_id":{"type":"integer","format":"int64","description":"The `schedule_runs.id` of the newly created run."}}},"ScheduleRunSummary":{"type":"object","description":"Summary of one scheduler tick (or one \"Run now\" click), returned by\n[`BackupService::list_schedule_runs`].\n\nThe `aggregate_state` is computed at read time from child backup counts:\n- `\"running\"` — at least one child is `\"pending\"` or `\"running\"`.\n- `\"failed\"` — at least one child is `\"failed\"` and none are running.\n- `\"completed\"` — all children are `\"completed\"`.","required":["run_id","schedule_id","triggered_by","started_at","aggregate_state","total_jobs","completed_jobs","failed_jobs","running_jobs","pending_jobs"],"properties":{"aggregate_state":{"type":"string","description":"Aggregate state computed from child counts (see struct docs)."},"completed_jobs":{"type":"integer","format":"int64","description":"Number of children in `state = \"completed\"`."},"failed_jobs":{"type":"integer","format":"int64","description":"Number of children in `state = \"failed\"`."},"finished_at":{"type":["string","null"],"description":"When all children reached a terminal state. `None` while any child is\nstill `\"pending\"` or `\"running\"`."},"pending_jobs":{"type":"integer","format":"int64","description":"Number of children in `state = \"pending\"`."},"run_id":{"type":"integer","format":"int64","description":"`schedule_runs.id` for this tick."},"running_jobs":{"type":"integer","format":"int64","description":"Number of children in `state = \"running\"`."},"schedule_id":{"type":"integer","format":"int32","description":"FK to `backup_schedules.id`."},"started_at":{"type":"string","description":"When the fan-out started (ISO 8601 / RFC 3339)."},"total_jobs":{"type":"integer","format":"int64","description":"Total number of child backup jobs in this run."},"triggered_by":{"type":"string","description":"How the run was triggered: `\"cron\"` or `\"manual\"`."}}},"ScheduleRunSummaryList":{"type":"object","description":"Paginated list of schedule run summaries returned by the new\n[`BackupService::list_schedule_runs`].","required":["runs","total","page","page_size"],"properties":{"page":{"type":"integer","format":"int64","description":"Current page (1-based)."},"page_size":{"type":"integer","format":"int64","description":"Number of items per page."},"runs":{"type":"array","items":{"$ref":"#/components/schemas/ScheduleRunSummary"},"description":"Run summaries, newest first. Includes synthetic single-job rows for\nlegacy `backups` rows that have `schedule_id` set but no\n`schedule_run_id` (pre-fan-out history)."},"total":{"type":"integer","format":"int64","description":"Total number of run entries across all pages."}}},"ScreenshotSettings":{"type":"object","properties":{"enabled":{"type":"boolean","default":false},"provider":{"type":"string","default":"local"},"url":{"type":"string","default":""}}},"SearchLogsRequest":{"type":"object","required":["project_id"],"properties":{"container_ids":{"type":"array","items":{"type":"string"},"description":"Filter to specific containers (Docker container IDs). Empty = all\ncontainers. Drives \"filter by container / show all\" in a project's\nhistory, which spans multiple deployments and containers."},"context_lines":{"type":["integer","null"],"format":"int32","description":"grep -C: number of raw context lines to include before and after each\nmatch (0 = none, default). Clamped to 50 server-side. The surrounding\nlines ignore the level/text filters — they are the actual adjacent log\nlines, merged across overlapping matches.","minimum":0},"cursor":{"type":["string","null"],"description":"Pagination cursor"},"deploy_id":{"type":["integer","null"],"format":"int32","description":"Filter by deployment ID (deployments.id)"},"end_time":{"type":["string","null"],"description":"End of time range (ISO 8601). Defaults to now."},"envs":{"type":"array","items":{"type":"string"},"description":"Filter by environments"},"external_service_id":{"type":["integer","null"],"format":"int32","description":"When set, search an imported/managed external service's logs instead\nof a project's. `project_id` is ignored in this mode."},"levels":{"type":"array","items":{"type":"string"},"description":"Filter by log levels"},"node_ids":{"type":"array","items":{"type":"integer","format":"int32"},"description":"Filter to specific worker nodes (node_id). Empty = all nodes, including\ncontrol-plane-local logs."},"page_size":{"type":["integer","null"],"format":"int32","description":"Page size (default: 100, max: 500)","minimum":0},"project_id":{"type":"integer","format":"int32","description":"Project ID (integer, as used by the rest of the platform)"},"services":{"type":"array","items":{"type":"string"},"description":"Filter by services"},"start_time":{"type":["string","null"],"description":"Start of time range (ISO 8601). Defaults to 1 hour ago."},"text":{"type":["string","null"],"description":"Full text search query"}}},"SearchLogsResponse":{"type":"object","required":["lines","search_mode","total_scanned"],"properties":{"available_sources":{"type":"array","items":{"$ref":"#/components/schemas/LogSource"},"description":"Distinct containers/nodes/services available in the queried scope, for\nthe filter dropdowns. Populated on the first page (no cursor)."},"lines":{"type":"array","items":{"$ref":"#/components/schemas/LogSearchLine"}},"next_cursor":{"type":["string","null"]},"search_mode":{"$ref":"#/components/schemas/SearchMode"},"total_scanned":{"type":"integer","format":"int64","minimum":0}}},"SearchMode":{"type":"string","description":"Search execution mode","enum":["index","archive"]},"Seasonality":{"type":"string","description":"Seasonality model for an anomaly baseline.","enum":["none","hourly","daily","weekly"]},"SecretResponse":{"type":"object","required":["id","name","secret_type","value","created_at","updated_at"],"properties":{"created_at":{"type":"string"},"description":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"mount_path":{"type":["string","null"]},"name":{"type":"string"},"secret_type":{"type":"string"},"updated_at":{"type":"string"},"value":{"type":"string","description":"Always masked in responses"}}},"SecurityConfig":{"type":"object","description":"Security configuration for projects and environments\n\nThis configuration can be set at three levels:\n1. Global (in settings table) - applies to all projects\n2. Project level - overrides global settings for specific project\n3. Environment level - overrides project settings for specific environment\n\nThe inheritance chain: Environment > Project > Global","properties":{"attackMode":{"type":["string","null"],"description":"Attack mode configuration (future: \"off\", \"challenge\", \"block\")\nPlaceholder for DDoS protection, bot detection, etc."},"challengeConfig":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ChallengeConfig","description":"Challenge configuration (future: CAPTCHA, JS challenge, etc.)"}]},"enabled":{"type":["boolean","null"],"description":"Enable/disable security features at this level\nIf None, inherits from parent level"},"geoRestrictions":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/GeoRestrictionsConfig","description":"Geographic restrictions (future: country blocking, etc.)"}]},"headers":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SecurityHeadersConfig","description":"Security headers configuration"}]},"passwordProtection":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PasswordProtectionConfig","description":"Password protection: shows an HTML password form before allowing access"}]},"rateLimiting":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/RateLimitConfig","description":"Rate limiting configuration"}]}}},"SecurityHeadersConfig":{"type":"object","description":"Security headers configuration (subset of global SecurityHeadersSettings)","properties":{"contentSecurityPolicy":{"type":["string","null"],"description":"Custom CSP (only used if preset is \"custom\")"},"preset":{"type":["string","null"],"description":"Use a preset: \"strict\", \"moderate\", \"permissive\", \"disabled\", \"custom\""},"referrerPolicy":{"type":["string","null"],"description":"Referrer-Policy override"},"strictTransportSecurity":{"type":["string","null"],"description":"HSTS override"},"xFrameOptions":{"type":["string","null"],"description":"X-Frame-Options override"}}},"SecurityHeadersSettings":{"type":"object","properties":{"content_security_policy":{"type":["string","null"],"default":"default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'self'"},"enabled":{"type":"boolean","default":false},"permissions_policy":{"type":["string","null"],"default":"geolocation=(), microphone=(), camera=()"},"preset":{"type":"string","default":"moderate"},"referrer_policy":{"type":"string","default":"strict-origin-when-cross-origin"},"strict_transport_security":{"type":"string","default":"max-age=31536000; includeSubDomains"},"x_content_type_options":{"type":"string","default":"nosniff"},"x_frame_options":{"type":"string","default":"SAMEORIGIN"},"x_xss_protection":{"type":"string","default":"1; mode=block"}}},"SendEmailRequestBody":{"type":"object","required":["from","to","subject"],"properties":{"bcc":{"type":["array","null"],"items":{"type":"string"},"description":"BCC recipients"},"cc":{"type":["array","null"],"items":{"type":"string"},"description":"CC recipients"},"from":{"type":"string","description":"Sender email address (domain will be auto-extracted for lookup)","example":"hello@updates.example.com"},"from_name":{"type":["string","null"],"description":"Sender display name","example":"My App"},"headers":{"type":["object","null"],"description":"Custom headers","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"html":{"type":["string","null"],"description":"HTML body content","example":"

Hello World

"},"reply_to":{"type":["string","null"],"description":"Reply-to address"},"subject":{"type":"string","description":"Email subject","example":"Welcome to our platform!"},"tags":{"type":["array","null"],"items":{"type":"string"},"description":"Tags for categorization","example":["welcome","onboarding"]},"text":{"type":["string","null"],"description":"Plain text body content","example":"Hello World"},"to":{"type":"array","items":{"type":"string"},"description":"Recipient email addresses","example":["user@example.com"]},"track_clicks":{"type":["boolean","null"],"description":"Enable click tracking (link rewriting). Defaults to false."},"track_opens":{"type":["boolean","null"],"description":"Enable open tracking (tracking pixel injection). Defaults to false."}}},"SendEmailResponseBody":{"type":"object","required":["id","status"],"properties":{"id":{"type":"string","description":"Email ID","example":"550e8400-e29b-41d4-a716-446655440000"},"provider_message_id":{"type":["string","null"],"description":"Provider message ID"},"status":{"type":"string","description":"Email status","example":"sent"}}},"SendMessageRequest":{"type":"object","required":["content"],"properties":{"content":{"type":"string"},"page_context":{"type":["string","null"],"description":"Optional, client-supplied description of the page/entity the user is\ncurrently viewing (e.g. a trace in a project). Injected into the model's\nview of this turn only — never stored or shown in history. Capped server\nside; oversized values are ignored rather than rejected."}}},"SensitiveConfigValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"SensitiveMcpConfigValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"SensitiveValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"SentryChunkUploadResponse":{"type":"object","required":["url","chunkSize","chunksPerRequest","maxFileSize","maxRequestSize","concurrency","hashAlgorithm","compression","accept"],"properties":{"accept":{"type":"array","items":{"type":"string"}},"chunkSize":{"type":"integer","format":"int64","minimum":0},"chunksPerRequest":{"type":"integer","format":"int32","minimum":0},"compression":{"type":"array","items":{"type":"string"}},"concurrency":{"type":"integer","format":"int32","minimum":0},"hashAlgorithm":{"type":"string"},"maxFileSize":{"type":"integer","format":"int64","minimum":0},"maxRequestSize":{"type":"integer","format":"int64","minimum":0},"url":{"type":"string"}}},"SentryCreateReleaseRequest":{"type":"object","required":["version"],"properties":{"projects":{"type":"array","items":{"type":"string"},"description":"Project slugs this release belongs to"},"version":{"type":"string","description":"Release version identifier"}}},"SentryEventRequest":{"type":"object","properties":{"event_id":{"type":["string","null"]},"message":{"type":["string","null"]},"platform":{"type":["string","null"]},"timestamp":{"type":["string","null"]}}},"SentryEventResponse":{"type":"object","required":["id"],"properties":{"id":{"type":"string"}}},"SentryReleaseFileResponse":{"type":"object","required":["id","name","headers","size","sha1","dateCreated"],"properties":{"dateCreated":{"type":"string"},"dist":{"type":["string","null"]},"headers":{},"id":{"type":"string"},"name":{"type":"string"},"sha1":{"type":"string"},"size":{"type":"integer","format":"int64"}}},"SentryReleaseProjectRef":{"type":"object","required":["name","slug"],"properties":{"name":{"type":"string"},"slug":{"type":"string"}}},"SentryReleaseResponse":{"type":"object","required":["version","dateCreated","shortVersion","projects"],"properties":{"dateCreated":{"type":"string"},"dateReleased":{"type":["string","null"]},"projects":{"type":"array","items":{"$ref":"#/components/schemas/SentryReleaseProjectRef"}},"shortVersion":{"type":"string"},"version":{"type":"string"}}},"SeriesStateEntry":{"type":"object","description":"One series' persisted state snapshot for a dynamic rule (ADR-026 follow-up):\nthe state after the latest tick, the value evaluated this tick, and the open\nalarm id (when firing). Serialized into the `series_states` jsonb column keyed\nby the human-readable [`series_label`]; the alert response decodes it back.","required":["state","value"],"properties":{"alarm_id":{"type":["integer","null"],"format":"int32","description":"The open alarm's id when the series is firing; `null` when ok."},"state":{"type":"string","description":"`firing` or `ok` for this series after the latest tick."},"value":{"type":"number","format":"double","description":"The value the rule evaluated for this series this tick."}}},"ServiceAccessInfo":{"type":"object","description":"Response containing information about how the service is being accessed","required":["access_mode","can_create_domains"],"properties":{"access_mode":{"type":"string","description":"Mode of access: \"local\", \"direct\", \"nat\", or \"cloudflare_tunnel\""},"can_create_domains":{"type":"boolean","description":"Whether domain creation is allowed in this mode"},"domain_creation_error":{"type":["string","null"],"description":"Error message if domain creation is not allowed"},"private_ip":{"type":["string","null"],"description":"Server's private/local IP address (always returned if available)"},"public_ip":{"type":["string","null"],"description":"Server's public IP address (always returned if available)"}}},"ServiceAction":{"type":"string","description":"What to do with a service during migration","enum":["create","link-external","skip"]},"ServiceAlertRuleResponse":{"type":"object","description":"Wire representation of a monitoring alert rule.\n\nRegistered under a domain-prefixed OpenAPI schema name to avoid colliding\nwith `temps-error-tracking`'s unrelated `AlertRuleResponse` (utoipa keys\nschemas by their bare struct name, so without `as = ...` the last crate to\nregister would silently shadow this one in the merged spec / generated SDK).","required":["id","name","metric_name","threshold","comparator","severity","for_duration_secs","enabled"],"properties":{"comparator":{"type":"string"},"deployment_id":{"type":["integer","null"],"format":"int32"},"enabled":{"type":"boolean"},"for_duration_secs":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"metric_name":{"type":"string"},"name":{"type":"string"},"service_id":{"type":["integer","null"],"format":"int32"},"severity":{"type":"string"},"silenced_until":{"type":["string","null"]},"threshold":{"type":"number","format":"double"}}},"ServiceBackupEntryResponse":{"type":"object","description":"A single backup entry in the per-service backup list.","required":["id","backup_id","name","state","backup_type","started_at","s3_location","compression_type","s3_source_id","s3_source_name","external_service_backup_id"],"properties":{"backup_id":{"type":"string","description":"UUID string assigned at backup creation time."},"backup_type":{"type":"string","description":"Backup variant (e.g. \"full\", \"incremental\")."},"compression_type":{"type":"string","description":"Compression algorithm used (e.g. \"gzip\")."},"error_message":{"type":["string","null"],"description":"Engine-reported error message, populated when `state = \"failed\"`."},"external_service_backup_id":{"type":"integer","format":"int32","description":"Row ID from `external_service_backups`."},"finished_at":{"type":["string","null"],"description":"ISO 8601 timestamp when the backup finished, if known.","example":"2025-01-15T14:35:00Z"},"id":{"type":"integer","format":"int32","description":"Row ID from the `backups` table."},"name":{"type":"string","description":"Human-friendly display name."},"s3_location":{"type":"string","description":"Object key or `s3://` URL for the backup data."},"s3_source_id":{"type":"integer","format":"int32","description":"FK to `s3_sources.id`."},"s3_source_name":{"type":"string","description":"Human-readable name of the S3 source."},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size of the backup in bytes, if available."},"started_at":{"type":"string","description":"ISO 8601 timestamp when the backup started.","example":"2025-01-15T14:30:00Z"},"state":{"type":"string","description":"Current state: \"completed\", \"running\", \"failed\"."}}},"ServiceBackupListResponse":{"type":"object","description":"Paginated list of backups for a specific external service.\n\nReturned by `GET /backups/external-services/{service_id}/backups`.","required":["backups","total","page","page_size"],"properties":{"backups":{"type":"array","items":{"$ref":"#/components/schemas/ServiceBackupEntryResponse"},"description":"Backups belonging to this service, newest first."},"page":{"type":"integer","format":"int64","description":"Current page (1-based)."},"page_size":{"type":"integer","format":"int64","description":"Number of items per page."},"total":{"type":"integer","format":"int64","description":"Total number of backups for this service across all pages."}}},"ServiceCreateAlertRuleRequest":{"type":"object","description":"Request body for creating an alert rule on an external service.\n\nDomain-prefixed schema name — see [`AlertRuleResponse`] for why.","required":["name","metric_name","threshold","comparator","severity"],"properties":{"comparator":{"type":"string","description":"One of `>`, `<`, `>=`, `<=`."},"enabled":{"type":"boolean"},"for_duration_secs":{"type":"integer","format":"int32","description":"Seconds the breach must persist before the alarm fires (0 = immediate)."},"metric_name":{"type":"string"},"name":{"type":"string"},"severity":{"type":"string","description":"`\"warning\"` or `\"critical\"`."},"threshold":{"type":"number","format":"double"}}},"ServiceHealthResponse":{"type":"object","required":["service_id","consecutive_failures","recent_checks"],"properties":{"consecutive_failures":{"type":"integer","format":"int32","description":"Consecutive failed probes. Alert fires at 3."},"last_checked_at":{"type":["string","null"]},"last_error":{"type":["string","null"]},"recent_checks":{"type":"array","items":{"$ref":"#/components/schemas/HealthCheckEntryResponse"},"description":"Most recent checks, newest-first (capped at `limit`)."},"response_time_ms":{"type":["integer","null"],"format":"int32"},"service_id":{"type":"integer","format":"int32"},"status":{"type":["string","null"],"description":"Current health. `null` if the service has not been probed yet.","example":"operational"},"uptime_24h_percent":{"type":["number","null"],"format":"double","description":"Uptime percentage over the last 24 hours (0.0 — 100.0).\n`null` when there is not enough history."}}},"ServiceHealthStatusBatchResponse":{"type":"object","required":["statuses"],"properties":{"statuses":{"type":"array","items":{"$ref":"#/components/schemas/ServiceHealthStatusEntryResponse"}}}},"ServiceHealthStatusEntryResponse":{"type":"object","required":["service_id","consecutive_failures"],"properties":{"consecutive_failures":{"type":"integer","format":"int32"},"last_checked_at":{"type":["string","null"]},"service_id":{"type":"integer","format":"int32"},"status":{"type":["string","null"],"description":"\"operational\" | \"degraded\" | \"down\". `null` when the service has not\nbeen probed yet.","example":"operational"}}},"ServiceMemberInfo":{"type":"object","description":"Public info about a cluster member.","required":["id","role","container_name","status","ordinal"],"properties":{"compute_ip":{"type":["string","null"],"description":"Container's IP on the `temps-overlay` multi-host network. Populated\nby the lifecycle hook (ADR-011 Phase 3); `None` on single-host\nclusters where the overlay isn't attached."},"container_name":{"type":"string"},"hostname":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"live_state":{"type":["string","null"],"description":"Live FSM state from the pg_auto_failover monitor (`primary`,\n`secondary`, `catchingup`, `report_lsn`, …). `None` when the\nmonitor is unreachable, the service is not a cluster, or the row\nis the monitor itself.\n\n**The UI must render the role badge from this field**, falling\nback to `role` only when `live_state` is null. `role` is now\nconfig-only (`monitor` or `replica`); flipping the badge to\n\"primary\" when the monitor elects a new one used to require a\nreconciler that lagged ~5s behind real failovers — and during\nthat window the UI showed two primaries. `live_state` is read\ndirectly from the monitor on every list, so it can never lag."},"node_id":{"type":["integer","null"],"format":"int32"},"ordinal":{"type":"integer","format":"int32"},"port":{"type":["integer","null"],"format":"int32"},"provisioning_error":{"type":["string","null"],"description":"Most recent provisioning failure message, when `status='failed'`.\nSet by the background task so the UI can show *why* the new\nreplica didn't come up."},"provisioning_step":{"type":["string","null"],"description":"Last-attempted phase of the async `add_cluster_member` background\ntask (e.g. `validating`, `provisioning_container`, `done`,\n`failed`). `None` for members not created through that flow —\nthe UI falls back to the `status` column for those."},"role":{"type":"string"},"status":{"type":"string"}}},"ServiceParameter":{"type":"object","required":["name","required","encrypted","description"],"properties":{"choices":{"type":["array","null"],"items":{"type":"string"}},"default_value":{"type":["string","null"]},"description":{"type":"string"},"encrypted":{"type":"boolean"},"name":{"type":"string"},"required":{"type":"boolean"},"validation_pattern":{"type":["string","null"]}}},"ServicePlan":{"type":"object","description":"Plan for migrating a single service (database, cache, etc.)","required":["name","service_type","action","action_description"],"properties":{"action":{"$ref":"#/components/schemas/ServiceAction","description":"What to do with this service"},"action_description":{"type":"string","description":"Human-readable explanation of what this action means"},"data_implications":{"type":"array","items":{"$ref":"#/components/schemas/DataImplication"},"description":"Data implications specific to this service"},"env_var_mappings":{"type":"object","description":"Environment variable key mappings: source_key -> temps_key\n\nFor example, Vercel's `POSTGRES_URL` might map to Temps' `DATABASE_URL`.\nBoth keys will be set during migration so the app works with either.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":"string","description":"Human-readable service name"},"parameters":{"type":"object","description":"Parameters for creating the service in Temps","additionalProperties":{},"propertyNames":{"type":"string"}},"service_type":{"type":"string","description":"Service type (maps to temps-providers ServiceType)"},"version":{"type":["string","null"],"description":"Service version to create (e.g., \"16\" for Postgres 16)"}}},"ServiceResourceLimits":{"type":"object","description":"Optional cgroup resource limits applied to a service container.\n\nAll fields are `Option`: `None` means \"no limit\" (the kernel default),\nmatching Docker's behavior when the corresponding `HostConfig` field is\nleft at zero. Operators opt in to limits explicitly through the\n`PATCH /external-services/{id}/resources` endpoint or by writing the\n`resources` block into `ServiceConfig::parameters` at create time.\n\nThese map directly onto bollard fields:\n- `memory_mb` → `HostConfig.memory` (bytes)\n- `memory_swap_mb`→ `HostConfig.memory_swap` (bytes; ≥ memory)\n- `nano_cpus` → `HostConfig.nano_cpus` (1e9 = 1 full CPU)\n- `cpu_shares` → `HostConfig.cpu_shares` (relative weight, default 1024)\n- `shm_size_mb` → `HostConfig.shm_size` (bytes; default 64 MiB)\n\nIMPORTANT: enabling hard memory limits causes the kernel OOM killer to\nterminate the container when the working set exceeds the limit. The\ncontainer will restart (RestartPolicy::ALWAYS) but in-flight queries\nfail. Surface this clearly in any UI that lets users set limits.","properties":{"cpu_shares":{"type":["integer","null"],"format":"int64","description":"Relative CPU weight (default 1024). Only used when `nano_cpus` is None."},"memory_mb":{"type":["integer","null"],"format":"int64","description":"Hard memory limit in MiB. None = unlimited."},"memory_swap_mb":{"type":["integer","null"],"format":"int64","description":"Memory + swap limit in MiB. None = unlimited.\nMUST be >= memory_mb when both are set; Docker rejects the request otherwise.\nSet equal to `memory_mb` to disable swap entirely."},"nano_cpus":{"type":["integer","null"],"format":"int64","description":"CPU quota in nano-cpus. 1_000_000_000 = 1 full CPU core. None = unlimited."},"shm_size_mb":{"type":["integer","null"],"format":"int64","description":"Shared memory (/dev/shm) size in MiB. None = Docker default (64 MiB).\nMaps to HostConfig.shm_size (bytes). PostgreSQL uses /dev/shm for parallel\nquery workers and large work_mem; the 64 MiB default causes \"could not\nresize shared memory segment ... No space left on device\" under load.\nNOTE: shm_size is fixed at container-create time — Docker's live update\nAPI cannot change it, so changing this value recreates the container."}}},"ServiceRuntimeReport":{"type":"object","description":"Aggregate runtime info for an external service. For standalone services,\n`members` has exactly one entry. For clusters, one entry per member.","required":["service_id","topology","members"],"properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/ContainerRuntimeInfo"}},"service_id":{"type":"integer","format":"int32"},"topology":{"type":"string"}}},"ServiceStatsReport":{"type":"object","required":["service_id","topology","members"],"properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/ContainerStatsSample"}},"service_id":{"type":"integer","format":"int32"},"topology":{"type":"string"}}},"ServiceTypeInfo":{"type":"object","required":["service_type","parameters"],"properties":{"parameters":{"type":"array","items":{"$ref":"#/components/schemas/ServiceParameter"},"example":"[{\"name\": \"host\", \"required\": true, \"encrypted\": false, \"description\": \"Database host\"}]"},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute"}}},"ServiceTypeRoute":{"type":"string","enum":["mariadb","mongodb","postgres","redis","s3","kv","blob","rustfs","minio"]},"ServiceUpdateAlertRuleRequest":{"type":"object","description":"Request body for updating an existing alert rule.\n\nDomain-prefixed schema name — see [`AlertRuleResponse`] for why.","properties":{"comparator":{"type":["string","null"]},"enabled":{"type":["boolean","null"]},"for_duration_secs":{"type":["integer","null"],"format":"int32"},"metric_name":{"type":["string","null"]},"name":{"type":["string","null"]},"severity":{"type":["string","null"]},"threshold":{"type":["number","null"],"format":"double"}}},"SesCredentialsRequest":{"type":"object","required":["access_key_id","secret_access_key"],"properties":{"access_key_id":{"type":"string","example":"AKIAIOSFODNN7EXAMPLE"},"secret_access_key":{"type":"string","example":"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"}}},"SessionDetails":{"type":"object","required":["session_id","visitor_id","started_at","duration_seconds","is_bounced","is_engaged","page_views"],"properties":{"duration_seconds":{"type":"integer","format":"int64"},"ended_at":{"type":["string","null"],"format":"date-time","example":"2024-01-01T00:00:00"},"entry_path":{"type":["string","null"]},"exit_path":{"type":["string","null"]},"is_bounced":{"type":"boolean"},"is_engaged":{"type":"boolean"},"page_views":{"type":"integer","format":"int64"},"referrer":{"type":["string","null"]},"session_id":{"type":"integer","format":"int32"},"started_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"visitor_id":{"type":"string"}}},"SessionDetailsQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"SessionEvent":{"type":"object","required":["id","timestamp"],"properties":{"event_data":{},"event_name":{"type":["string","null"]},"event_type":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"page_title":{"type":["string","null"]},"page_url":{"type":["string","null"]},"timestamp":{"type":"string"}}},"SessionEventDto":{"type":"object","required":["id","session_id","data","timestamp"],"properties":{"data":{},"event_type":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"session_id":{"type":"integer","format":"int32"},"timestamp":{"type":"integer","format":"int64"}}},"SessionEventsQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"SessionEventsResponse":{"type":"object","required":["session_id","events","total_count","offset","limit"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/SessionEvent"}},"limit":{"type":"integer","format":"int32"},"offset":{"type":"integer","format":"int32"},"session_id":{"type":"integer","format":"int32"},"total_count":{"type":"integer","format":"int64"}}},"SessionLogsQuery":{"type":"object","required":["project_id"],"properties":{"end_date":{"type":["string","null"],"format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"offset":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"sort_order":{"type":["string","null"]},"start_date":{"type":["string","null"],"format":"date-time"},"visitor_id":{"type":["integer","null"],"format":"int32"}}},"SessionLogsResponse":{"type":"object","required":["session_id","logs","total_count","offset","limit"],"properties":{"limit":{"type":"integer","format":"int32"},"logs":{"type":"array","items":{"$ref":"#/components/schemas/SessionRequestLog"}},"offset":{"type":"integer","format":"int32"},"session_id":{"type":"integer","format":"int32"},"total_count":{"type":"integer","format":"int64"}}},"SessionReplayEventsRequest":{"type":"object","required":["sessionId","events"],"properties":{"events":{"type":"string"},"sessionId":{"type":"string"}}},"SessionReplayInfoDto":{"type":"object","required":["id","visitor_id"],"properties":{"created_at":{"type":["string","null"]},"duration":{"type":["integer","null"],"format":"int32"},"id":{"type":"string"},"language":{"type":["string","null"]},"screen_height":{"type":["integer","null"],"format":"int32"},"screen_width":{"type":["integer","null"],"format":"int32"},"timezone":{"type":["string","null"]},"url":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"viewport_height":{"type":["integer","null"],"format":"int32"},"viewport_width":{"type":["integer","null"],"format":"int32"},"visitor_id":{"type":"integer","format":"int32"}}},"SessionReplayInitRequest":{"type":"object","required":["sessionId"],"properties":{"colorDepth":{"type":["integer","null"],"format":"int32","minimum":0},"language":{"type":["string","null"]},"screenHeight":{"type":["integer","null"],"format":"int32","minimum":0},"screenWidth":{"type":["integer","null"],"format":"int32","minimum":0},"sessionId":{"type":"string"},"timestamp":{"type":["string","null"]},"timezone":{"type":["string","null"]},"url":{"type":["string","null"]},"userAgent":{"type":["string","null"]},"viewportHeight":{"type":["integer","null"],"format":"int32","minimum":0},"viewportWidth":{"type":["integer","null"],"format":"int32","minimum":0}}},"SessionReplayInitResponse":{"type":"object","required":["session_id","message"],"properties":{"message":{"type":"string"},"session_id":{"type":"string"}}},"SessionReplayWithEventsDto":{"type":"object","required":["session","events"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/SessionEventDto"}},"session":{"$ref":"#/components/schemas/SessionReplayWithVisitorDto"}}},"SessionReplayWithVisitorDto":{"type":"object","required":["id","session_replay_id","visitor_id","visitor_uuid","visitor_project_id","visitor_environment_id","visitor_first_seen","visitor_last_seen","visitor_is_crawler"],"properties":{"browser":{"type":["string","null"]},"browser_version":{"type":["string","null"]},"created_at":{"type":["string","null"]},"device_type":{"type":["string","null"]},"duration":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"language":{"type":["string","null"]},"operating_system":{"type":["string","null"]},"operating_system_version":{"type":["string","null"]},"screen_height":{"type":["integer","null"],"format":"int32"},"screen_width":{"type":["integer","null"],"format":"int32"},"session_replay_id":{"type":"string"},"timezone":{"type":["string","null"]},"url":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"viewport_height":{"type":["integer","null"],"format":"int32"},"viewport_width":{"type":["integer","null"],"format":"int32"},"visitor_city":{"type":["string","null"]},"visitor_country":{"type":["string","null"]},"visitor_country_code":{"type":["string","null"]},"visitor_crawler_name":{"type":["string","null"]},"visitor_custom_data":{},"visitor_environment_id":{"type":"integer","format":"int32"},"visitor_first_seen":{"type":"string"},"visitor_id":{"type":"integer","format":"int32"},"visitor_is_crawler":{"type":"boolean"},"visitor_last_seen":{"type":"string"},"visitor_project_id":{"type":"integer","format":"int32"},"visitor_region":{"type":["string","null"]},"visitor_uuid":{"type":"string"}}},"SessionRequestLog":{"type":"object","required":["id","method","path","status_code","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"method":{"type":"string"},"path":{"type":"string"},"referrer":{"type":["string","null"]},"request_headers":{"type":["string","null"]},"response_headers":{"type":["string","null"]},"response_time_ms":{"type":["integer","null"],"format":"int32"},"status_code":{"type":"integer","format":"int32"},"user_agent":{"type":["string","null"]}}},"SessionSummary":{"type":"object","required":["session_id","started_at","duration_seconds","page_views","events_count","requests_count","is_bounced","is_engaged"],"properties":{"duration_seconds":{"type":"integer","format":"int64"},"ended_at":{"type":["string","null"],"format":"date-time","example":"2024-01-01T00:00:00"},"entry_path":{"type":["string","null"]},"events_count":{"type":"integer","format":"int64"},"exit_path":{"type":["string","null"]},"is_bounced":{"type":"boolean"},"is_engaged":{"type":"boolean"},"page_views":{"type":"integer","format":"int64"},"referrer":{"type":["string","null"]},"requests_count":{"type":"integer","format":"int64"},"session_id":{"type":"integer","format":"int32"},"started_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"}}},"SetFlagEnvironmentRequest":{"type":"object","properties":{"enabled":{"type":["boolean","null"],"description":"The kill switch. `false` makes the flag serve its default regardless of\nany override — and, once targeting exists, regardless of any rule."},"value":{"description":"Tri-state: absent leaves the override, `null` clears it (inherit the\nflag default), anything else sets it. Must match `value_type`."}}},"SetPreviewPasswordBody":{"type":"object","required":["password"],"properties":{"password":{"type":"string","description":"Plaintext password to protect the sandbox's preview URLs. Hashed\nserver-side with argon2id — we never persist or echo this back.\nMust be between 8 and 256 characters."}}},"SetPreviewPasswordResponse":{"type":"object","required":["preview_password_hint"],"properties":{"preview_password_hint":{"type":"string","description":"Last 4 chars of the password we just stored. Surface in the UI so\nusers can confirm which password is live without re-entering it."}}},"SetRequest":{"type":"object","description":"Request to set a value","required":["key","value"],"properties":{"ex":{"type":["integer","null"],"format":"int64","description":"Expire in seconds","example":3600},"key":{"type":"string","description":"The key to set","example":"user:123"},"nx":{"type":"boolean","description":"Only set if key does not exist"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1},"px":{"type":["integer","null"],"format":"int64","description":"Expire in milliseconds"},"value":{"description":"The value to store (can be any JSON value)"},"xx":{"type":"boolean","description":"Only set if key exists"}}},"SetResponse":{"type":"object","description":"Response for set operation","required":["result"],"properties":{"result":{"type":"string","description":"Always \"OK\" on success","example":"OK"}}},"SettingsUpdateResponse":{"type":"object","description":"Response for successful settings update","required":["message"],"properties":{"message":{"type":"string"}}},"SetupDnsChallengeRequest":{"type":"object","description":"Request to setup DNS challenge records using a configured DNS provider","required":["dns_provider_id"],"properties":{"dns_provider_id":{"type":"integer","format":"int32","description":"The ID of the DNS provider to use for creating the TXT records"}}},"SetupDnsChallengeResponse":{"type":"object","description":"Response from DNS challenge setup operation","required":["success","records_created","total_records","results","message"],"properties":{"message":{"type":"string","description":"Human-readable summary message"},"records_created":{"type":"integer","format":"int32","description":"Number of TXT records that were successfully created","minimum":0},"results":{"type":"array","items":{"$ref":"#/components/schemas/DnsChallengeRecordResult"},"description":"Results for each individual TXT record"},"success":{"type":"boolean","description":"Overall success status (true if all records were created)"},"total_records":{"type":"integer","format":"int32","description":"Total number of TXT records required for the challenge","minimum":0}}},"SetupDnsRequest":{"type":"object","description":"Request to setup DNS records using a configured DNS provider","required":["dns_provider_id"],"properties":{"dns_provider_id":{"type":"integer","format":"int32","description":"The ID of the DNS provider to use for creating records"}}},"SetupDnsResponse":{"type":"object","description":"Response from DNS setup operation","required":["success","records_created","total_records","results","message"],"properties":{"message":{"type":"string","description":"Human-readable summary message"},"records_created":{"type":"integer","format":"int32","description":"Number of records that were successfully created","minimum":0},"results":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecordSetupResult"},"description":"Results for each individual record"},"success":{"type":"boolean","description":"Overall success status"},"total_records":{"type":"integer","format":"int32","description":"Total number of records attempted","minimum":0}}},"SiblingRef":{"type":"object","description":"A sibling project that shares the same `trace_id` and has opted in to\ncross-project trace sharing (`cross_project_trace_sharing = TRUE`).\n\nReturned by `CrossProjectTraceService::find_sibling_projects` and exposed\nby the Phase 1 `GET /otel/traces/cross-project/{trace_id}` endpoint.","required":["project_id","project_name","project_slug","first_seen"],"properties":{"first_seen":{"type":"string","format":"date-time"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"project_slug":{"type":"string","description":"URL slug used to link into the sibling project's single-project trace view."}}},"SkillDefinitionResponse":{"type":"object","required":["id","slug","name","content","has_archive","created_at","updated_at"],"properties":{"content":{"type":"string"},"created_at":{"type":"string"},"description":{"type":["string","null"]},"has_archive":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"project_id":{"type":["integer","null"],"format":"int32"},"slug":{"type":"string"},"updated_at":{"type":"string"}}},"SlackConfig":{"type":"object","required":["webhook_url"],"properties":{"channel":{"type":["string","null"]},"webhook_url":{"type":"string"}}},"SlowQueriesResponse":{"type":"object","description":"Response envelope for the slow-queries list endpoint.","required":["queries","page","page_size","total_count"],"properties":{"page":{"type":"integer","format":"int32","description":"Current page number (1-based).","minimum":0},"page_size":{"type":"integer","format":"int32","description":"Number of rows per page used for this request.","minimum":0},"queries":{"type":"array","items":{"$ref":"#/components/schemas/SlowQueryRow"},"description":"Ordered list of query stats, slowest first by mean_exec_time_ms."},"total_count":{"type":"integer","format":"int64","description":"Total number of qualifying rows across all pages.","minimum":0}}},"SlowQueryRow":{"type":"object","description":"A single entry from `pg_stat_statements`, representing one normalized\nquery fingerprint and its aggregate execution stats.","required":["query","database","calls","total_exec_time_ms","mean_exec_time_ms","rows"],"properties":{"cache_hit_ratio":{"type":["number","null"],"format":"double","description":"Shared block cache hit ratio (0.0–1.0).\n`None` when total block accesses are zero (e.g. function-only queries)."},"calls":{"type":"integer","format":"int64","description":"Number of times this query was executed."},"database":{"type":"string","description":"Name of the database this query ran against. `(dropped database)`\nwhen the originating database no longer exists but\n`pg_stat_statements` still holds stats for it."},"mean_exec_time_ms":{"type":"number","format":"double","description":"Average wall-clock time per execution, in milliseconds."},"query":{"type":"string","description":"Normalized query text (parameter literals replaced with `$N`)."},"rows":{"type":"integer","format":"int64","description":"Total number of rows returned or affected."},"total_exec_time_ms":{"type":"number","format":"double","description":"Total wall-clock time spent executing this query, in milliseconds."}}},"SmartFilter":{"oneOf":[{"type":"object","description":"Match specific page path","required":["value","type"],"properties":{"type":{"type":"string","enum":["page_path"]},"value":{"type":"string","description":"Match specific page path"}}},{"type":"object","description":"Match specific hostname","required":["value","type"],"properties":{"type":{"type":"string","enum":["hostname"]},"value":{"type":"string","description":"Match specific hostname"}}},{"type":"object","description":"Match UTM source","required":["value","type"],"properties":{"type":{"type":"string","enum":["utm_source"]},"value":{"type":"string","description":"Match UTM source"}}},{"type":"object","description":"Match UTM campaign","required":["value","type"],"properties":{"type":{"type":"string","enum":["utm_campaign"]},"value":{"type":"string","description":"Match UTM campaign"}}},{"type":"object","description":"Match UTM medium","required":["value","type"],"properties":{"type":{"type":"string","enum":["utm_medium"]},"value":{"type":"string","description":"Match UTM medium"}}},{"type":"object","description":"Match referrer hostname","required":["value","type"],"properties":{"type":{"type":"string","enum":["referrer_hostname"]},"value":{"type":"string","description":"Match referrer hostname"}}},{"type":"object","description":"Match specific channel (organic, paid, direct, referral, etc.)","required":["value","type"],"properties":{"type":{"type":"string","enum":["channel"]},"value":{"type":"string","description":"Match specific channel (organic, paid, direct, referral, etc.)"}}},{"type":"object","description":"Match device type (mobile, desktop, tablet)","required":["value","type"],"properties":{"type":{"type":"string","enum":["device_type"]},"value":{"type":"string","description":"Match device type (mobile, desktop, tablet)"}}},{"type":"object","description":"Match browser","required":["value","type"],"properties":{"type":{"type":"string","enum":["browser"]},"value":{"type":"string","description":"Match browser"}}},{"type":"object","description":"Match operating system","required":["value","type"],"properties":{"type":{"type":"string","enum":["operating_system"]},"value":{"type":"string","description":"Match operating system"}}},{"type":"object","description":"Match language","required":["value","type"],"properties":{"type":{"type":"string","enum":["language"]},"value":{"type":"string","description":"Match language"}}},{"type":"object","description":"Match custom event_data by JSON path\nFormat: {\"path\": \"user.plan\", \"value\": \"premium\"}\nThis will match events where event_data->'user'->>'plan' = 'premium'","required":["value","type"],"properties":{"type":{"type":"string","enum":["custom_data"]},"value":{"type":"object","description":"Match custom event_data by JSON path\nFormat: {\"path\": \"user.plan\", \"value\": \"premium\"}\nThis will match events where event_data->'user'->>'plan' = 'premium'","required":["path","value"],"properties":{"path":{"type":"string"},"value":{"type":"string"}}}}}],"description":"Smart filter presets for common funnel patterns"},"SmokeTestResponse":{"type":"object","required":["passed","environment","cli_installed","cli_authenticated"],"properties":{"auth_info":{"type":["string","null"],"description":"Auth email / method"},"cli_authenticated":{"type":"boolean","description":"Claude CLI authenticated?"},"cli_installed":{"type":"boolean","description":"Claude CLI installed?"},"cli_version":{"type":["string","null"],"description":"Claude CLI version"},"detail":{"type":["string","null"],"description":"Full output for debugging"},"environment":{"type":"string","description":"Where the test ran: \"host\" or \"sandbox\""},"passed":{"type":"boolean","description":"Whether the smoke test passed"},"setup_hint":{"type":["string","null"],"description":"What the user needs to do if the test failed"}}},"SmtpCredentialsRequest":{"type":"object","description":"Generic SMTP credentials request body.\n\nWorks with any SMTP relay — AWS SES SMTP endpoints, Sendgrid, Mailgun,\nPostmark, or a self-hosted Postfix. Use this when you only have SMTP\ncredentials (i.e. you cannot create identities via the upstream API).","required":["host","port"],"properties":{"accept_invalid_certs":{"type":"boolean","description":"Accept self-signed certificates. Only safe for local testing."},"encryption":{"$ref":"#/components/schemas/SmtpEncryptionRoute","description":"TLS mode. Defaults to STARTTLS."},"host":{"type":"string","description":"SMTP host, e.g. `email-smtp.eu-west-1.amazonaws.com`.","example":"email-smtp.eu-west-1.amazonaws.com"},"password":{"type":["string","null"],"description":"SMTP password / API token. Required when `username` is set."},"port":{"type":"integer","format":"int32","description":"SMTP port (587 for STARTTLS, 465 for implicit TLS, 25/1025 for plain).","example":587,"minimum":0},"username":{"type":["string","null"],"description":"SMTP username. Leave empty for unauthenticated relays.","example":"AKIAIOSFODNN7EXAMPLE"}}},"SmtpEncryptionRoute":{"type":"string","description":"TLS mode for the SMTP relay.","enum":["starttls","tls","none"]},"SmtpResult":{"type":"object","description":"SMTP validation result","required":["can_connect_smtp","has_full_inbox","is_catch_all","is_deliverable","is_disabled"],"properties":{"can_connect_smtp":{"type":"boolean","description":"Whether we could connect to the SMTP server"},"error":{"type":["string","null"],"description":"Error message if SMTP check failed"},"has_full_inbox":{"type":"boolean","description":"Whether the mailbox appears to have a full inbox"},"is_catch_all":{"type":"boolean","description":"Whether this is a catch-all domain"},"is_deliverable":{"type":"boolean","description":"Whether the email is deliverable"},"is_disabled":{"type":"boolean","description":"Whether the mailbox is disabled"}}},"SourceArchiveUpload":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary"}}},"SourceBackupEntry":{"type":"object","description":"Entry in the source backup index. Covers both DB-tracked backups\n(have a row in `backups`) and S3-scan discoveries (raw S3 objects with\nno DB row — used for disaster-recovery from another Temps instance).","required":["id","backup_id","name","backup_type","created_at","location","metadata_location","source","state"],"properties":{"backup_id":{"type":"string","description":"UUID identifier from the DB row. Empty for S3-scan entries.","example":"550e8400-e29b-41d4-a716-446655440000"},"backup_type":{"type":"string","description":"Backup variant as recorded by the backup pipeline (e.g. \"full\").","example":"full"},"created_at":{"type":"string","description":"When the backup was created. For S3-scan entries this is the\nobject's LastModified time.","example":"2024-01-15T14:30:00.123Z"},"engine":{"type":["string","null"],"description":"Engine that produced the backup (\"postgres\", \"redis\", \"mongodb\",\n\"s3\", \"rustfs\"). Used by the UI to mark engine-compat with the\ntarget service.","example":"postgres"},"format":{"type":["string","null"],"description":"Storage format: \"walg\" for continuous-archive (PITR-capable),\n\"pg_dump\" for point-in-time dumps, \"\" for non-postgres.","example":"walg"},"id":{"type":"integer","format":"int32","description":"DB row id. Zero for S3-scan entries that have no DB row.","example":1},"location":{"type":"string","description":"Raw S3 URL / key where the backup sits. For Postgres WAL-G backups\nthis starts with `s3://`; for pg_dump-style backups it's the\nrelative object key.","example":"s3://bucket/external_services/postgres/svc-name/walg"},"metadata_location":{"type":"string","description":"Sidecar metadata.json location, if any. Empty when none.","example":""},"name":{"type":"string","description":"Human-friendly display name (\"postgres backup (svc-name)\" for DB\nrows, or a synthesized label derived from the S3 path for scans).","example":"postgres backup (postgres-n4ea)"},"origin_service_name":{"type":["string","null"],"description":"Name of the service that produced the backup. For S3-scan entries\nthis is parsed from the S3 path.","example":"postgres-n4ea"},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size of the backup in bytes, if known.","example":1024000},"source":{"type":"string","description":"Provenance: \"db\" for rows in this Temps, \"s3_scan\" for objects\ndiscovered by the S3 bucket walk (e.g., backups made by another\nTemps instance).","example":"db"},"state":{"type":"string","description":"Observed state (\"completed\", \"running\", \"failed\") — DB only.\nEmpty string for S3-scan entries.","example":"completed"}}},"SourceBackupIndexResponse":{"type":"object","description":"Response type for source backup index","required":["backups","last_updated"],"properties":{"backups":{"type":"array","items":{"$ref":"#/components/schemas/SourceBackupEntry"},"description":"List of backups in the source"},"last_updated":{"type":"string","description":"When the index was last updated","example":"2024-01-15T14:30:00.123Z"}}},"SourceBody":{"oneOf":[{"type":"object","required":["url","type"],"properties":{"depth":{"type":["integer","null"],"format":"int32","minimum":0},"git_connection_id":{"type":["integer","null"],"format":"int32"},"password":{"type":["string","null"]},"revision":{"type":["string","null"]},"type":{"type":"string","enum":["git"]},"url":{"type":"string"},"username":{"type":["string","null"]}}},{"type":"object","required":["url","type"],"properties":{"type":{"type":"string","enum":["tarball"]},"url":{"type":"string"}}}],"description":"Initial content to seed into the sandbox work dir. Mirrors the\n`@vercel/sandbox` `source` option. `type` is one of:\n- `git` — clone `url`; optionally check out `revision`\n- `tarball` — download `url` (must be tar or tar.gz) and extract\n\nFor private git repos, pass credentials one of two ways:\n1. **Inline (SDK-compatible):** `username` + `password`. GitHub\n tokens use `username: \"x-access-token\"`.\n2. **Stored connection (temps-native):** `git_connection_id`\n references a row in the caller's git provider connections. Temps\n resolves the token server-side and injects it safely.\n\n`git_connection_id` is mutually exclusive with `username`/`password`."},"SourceFileListResponse":{"type":"object","required":["source_files","total"],"properties":{"source_files":{"type":"array","items":{"$ref":"#/components/schemas/SourceFileResponse"}},"total":{"type":"integer","minimum":0}}},"SourceFileResponse":{"type":"object","required":["id","project_id","release","file_path","size_bytes","created_at"],"properties":{"checksum":{"type":["string","null"]},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"file_path":{"type":"string"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"release":{"type":"string"},"size_bytes":{"type":"integer","format":"int64"}}},"SourceMapListResponse":{"type":"object","required":["source_maps","total"],"properties":{"source_maps":{"type":"array","items":{"$ref":"#/components/schemas/SourceMapResponse"}},"total":{"type":"integer","minimum":0}}},"SourceMapResponse":{"type":"object","required":["id","project_id","release","file_path","size_bytes","created_at"],"properties":{"checksum":{"type":["string","null"]},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"dist":{"type":["string","null"]},"file_path":{"type":"string"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"release":{"type":"string"},"size_bytes":{"type":"integer","format":"int64"}}},"SourceType":{"type":"string","description":"Source type for project deployments\n\nDetermines where the deployment artifacts come from:\n- `Git`: Source code from a Git repository (traditional flow)\n- `DockerImage`: Pre-built Docker image from external registry\n- `StaticFiles`: Pre-built static files uploaded as a bundle\n- `UploadedSource`: Source archive uploaded without a Git repository\n- `Manual`: Flexible type that accepts any deployment method","enum":["git","docker_image","static_files","uploaded_source","manual"]},"SpanEvent":{"type":"object","description":"A span event (log-like annotation on a span).","required":["timestamp","name","attributes"],"properties":{"attributes":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":"string"},"timestamp":{"type":"string","format":"date-time"}}},"SpanKind":{"type":"string","description":"Span kind.","enum":["UNSPECIFIED","INTERNAL","SERVER","CLIENT","PRODUCER","CONSUMER"]},"SpanRecord":{"type":"object","description":"A single trace span ready for storage.","required":["project_id","resource","trace_id","span_id","name","kind","start_time","end_time","duration_ms","status_code","status_message","attributes","events"],"properties":{"attributes":{"type":"object","description":"Raw key/value pairs exactly as reported by the instrumenting library.\nNumeric values are NOT guaranteed to share `duration_ms`'s unit — they\nmay be seconds, milliseconds, microseconds, or nanoseconds depending on\nthe exporter's own convention, and the unit is not labeled here.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"deployment_id":{"type":["integer","null"],"format":"int32"},"duration_ms":{"type":"number","format":"double","description":"Span duration in milliseconds. The only field on this struct guaranteed\nto be in milliseconds."},"end_time":{"type":"string","format":"date-time"},"events":{"type":"array","items":{"$ref":"#/components/schemas/SpanEvent"}},"kind":{"$ref":"#/components/schemas/SpanKind"},"name":{"type":"string"},"parent_span_id":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"resource":{"$ref":"#/components/schemas/ResourceInfo"},"span_id":{"type":"string"},"start_time":{"type":"string","format":"date-time"},"status_code":{"$ref":"#/components/schemas/SpanStatusCode"},"status_message":{"type":"string"},"trace_id":{"type":"string"}}},"SpanRow":{"type":"object","required":["id","ts","trace_id","span_id","service","operation","attributes","attributes_truncated"],"properties":{"attributes":{},"attributes_truncated":{"type":"boolean"},"deployment_id":{"type":["integer","null"],"format":"int32"},"duration_ms":{"type":["number","null"],"format":"double"},"environment_id":{"type":["integer","null"],"format":"int32"},"id":{"type":"string"},"operation":{"type":"string"},"parent_span_id":{"type":["string","null"]},"service":{"type":"string"},"span_id":{"type":"string"},"status":{"type":["string","null"]},"trace_id":{"type":"string"},"ts":{"type":"string","format":"date-time"}}},"SpanStatusCode":{"type":"string","description":"Span status code.","enum":["UNSET","OK","ERROR"]},"SpeedMetricsPayload":{"type":"object","description":"Speed metrics payload for recording web vitals","properties":{"cls":{"type":["number","null"],"format":"float","description":"Cumulative Layout Shift (score)"},"fcp":{"type":["number","null"],"format":"float","description":"First Contentful Paint (milliseconds)"},"fid":{"type":["number","null"],"format":"float","description":"First Input Delay (milliseconds)"},"inp":{"type":["number","null"],"format":"float","description":"Interaction to Next Paint (milliseconds)"},"language":{"type":["string","null"],"description":"Browser language"},"lcp":{"type":["number","null"],"format":"float","description":"Largest Contentful Paint (milliseconds)"},"pathname":{"type":["string","null"],"description":"Page pathname"},"query":{"type":["string","null"],"description":"Query string"},"screenHeight":{"type":["integer","null"],"format":"int32","description":"Screen height in pixels"},"screenWidth":{"type":["integer","null"],"format":"int32","description":"Screen width in pixels"},"ttfb":{"type":["number","null"],"format":"float","description":"Time to First Byte (milliseconds)"},"viewportHeight":{"type":["integer","null"],"format":"int32","description":"Viewport height in pixels"},"viewportWidth":{"type":["integer","null"],"format":"int32","description":"Viewport width in pixels"}}},"SpeedSegmentFilters":{"type":"object","description":"Optional segment filters for the performance read endpoints, mirroring\nanalytics' `VisitorSegmentFilters`. Each filter narrows results to samples\nmatching the dimension value, so metrics can be scoped to e.g. one page,\none browser, or one country. Geographic filters resolve via\n`ip_geolocations`; the rest live directly on `performance_metrics`.","properties":{"filter_browser":{"type":["string","null"],"description":"Browser name (matches `performance_metrics.browser`)"},"filter_city":{"type":["string","null"],"description":"Geolocation city (matches `ip_geolocations.city`)"},"filter_country":{"type":["string","null"],"description":"Geolocation country (matches `ip_geolocations.country`)"},"filter_operating_system":{"type":["string","null"],"description":"Operating system (matches `performance_metrics.operating_system`)"},"filter_path":{"type":["string","null"],"description":"Page pathname (matches `performance_metrics.pathname`)"},"filter_region":{"type":["string","null"],"description":"Geolocation region (matches `ip_geolocations.region`)"}}},"StaleSlot":{"type":"object","required":["slot_name","active","retained_bytes"],"properties":{"active":{"type":"boolean"},"retained_bytes":{"type":"integer","format":"int64"},"slot_name":{"type":"string"}}},"StartAnalysisRequest":{"type":"object","required":["error_group_id"],"properties":{"branch":{"type":["string","null"],"description":"Branch to clone instead of the project's main branch."},"error_group_id":{"type":"integer","format":"int32"},"max_turns":{"type":["integer","null"],"format":"int32","description":"Per-run turn cap applied to every phase (1–200). Only enforced for\nCLIs with a turn flag (Claude Code). `None` uses the provider's\nconfigured defaults."},"model":{"type":["string","null"],"description":"Model id for the chosen provider. `None` uses the provider's saved\ndefault model."},"provider":{"type":["string","null"],"description":"AI provider id (\"claude_cli\", \"codex_cli\", \"opencode\"). `None` uses\nthe platform default provider."},"user_context":{"type":["string","null"],"description":"Free-text notes for the model (extra context about the error, retry\nguidance, constraints). Included verbatim in the analysis prompt."}}},"StartPgUpgradeRequest":{"type":"object","required":["from_version","to_version","from_image","to_image"],"properties":{"from_image":{"type":"string","example":"postgres:16-bookworm"},"from_version":{"type":"string","example":"16"},"to_image":{"type":"string","example":"postgres:17-bookworm"},"to_version":{"type":"string","example":"17"}}},"StartRestoreRequest":{"allOf":[{"$ref":"#/components/schemas/RestoreRequestMode","description":"Requested restore mode. See `RestoreRequestMode`."},{"type":"object","properties":{"backup_engine":{"type":["string","null"],"description":"Engine of the backup when specified by `backup_location`\n(\"postgres\", \"redis\", \"mongodb\", \"s3\"). Ignored when `backup_id`\nis used — we infer from the DB row."},"backup_id":{"type":["integer","null"],"format":"int32","description":"DB id of the backup to restore from. Either `backup_id` or\n`backup_location` MUST be provided. Use `backup_id` when restoring\na backup this Temps instance recorded."},"backup_location":{"type":["string","null"],"description":"Raw S3 URL / key of the backup — used when restoring a backup\ndiscovered by S3 scan (i.e., produced by another Temps instance).\nRequires `backup_engine` and `s3_source_id` to also be set."},"s3_source_id":{"type":["integer","null"],"format":"int32","description":"S3 source the `backup_location` lives in. Ignored when `backup_id`\nis used."}}}]},"StatResponse":{"type":"object","required":["path","exists","is_dir","is_file","size"],"properties":{"exists":{"type":"boolean"},"is_dir":{"type":"boolean"},"is_file":{"type":"boolean"},"path":{"type":"string"},"size":{"type":"integer","format":"int64","minimum":0}}},"StaticBundleResponse":{"type":"object","required":["id","project_id","blob_path","content_type","size_bytes","uploaded_at","created_at"],"properties":{"blob_path":{"type":"string"},"checksum":{"type":["string","null"]},"content_type":{"type":"string"},"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"format":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"metadata":{},"original_filename":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"size_bytes":{"type":"integer","format":"int64"},"uploaded_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"}}},"StaticParams":{"type":"object","description":"Static threshold detector: compare the aggregated `value` against `threshold`.","required":["comparator","threshold"],"properties":{"comparator":{"$ref":"#/components/schemas/Comparator","description":"How `value` is compared against `threshold`."},"threshold":{"type":"number","format":"double","description":"The threshold the aggregated value is compared against."}}},"StaticPresetConfig":{"type":"object","description":"Configuration for static site presets (Vite, Next.js, Docusaurus, etc.)\nThese presets build static sites that are served via a web server","properties":{"buildCommand":{"type":["string","null"],"description":"Custom build command (overrides preset default)","example":"npm run build:production"},"buildContext":{"type":["string","null"],"description":"Custom build context path (relative to repository root)\nUseful for monorepo setups where the app is in a subdirectory","example":"./apps/frontend"},"installCommand":{"type":["string","null"],"description":"Custom install command (overrides auto-detected package manager)","example":"npm ci"},"outputDir":{"type":["string","null"],"description":"Custom output directory (overrides preset default)\nCommon values: \"dist\", \"build\", \".next\", \"out\"","example":"dist"}}},"StatsFilters":{"type":"object","description":"Filters for statistics queries","properties":{"client_ip":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"device_type":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"has_project":{"type":["boolean","null"],"description":"When true, only count requests that matched a project (project_id IS NOT NULL).\nUsed by the health dashboard so totals match the per-project cards."},"host":{"type":["string","null"]},"is_bot":{"type":["boolean","null"]},"method":{"type":["string","null"]},"project_id":{"type":["integer","null"],"format":"int32"},"request_source":{"type":["string","null"]},"routing_status":{"type":["string","null"]},"status_code":{"type":["integer","null"],"format":"int32"},"status_code_class":{"type":["string","null"],"description":"Filter by status code class (e.g. \"2xx\", \"3xx\", \"4xx\", \"5xx\")"}}},"StatusBucket":{"type":"object","required":["bucket_start","status","total_checks","operational_count","degraded_count","down_count","uptime_percentage"],"properties":{"avg_response_time_ms":{"type":["number","null"],"format":"double"},"bucket_start":{"type":"string","format":"date-time"},"degraded_count":{"type":"integer","format":"int64"},"down_count":{"type":"integer","format":"int64"},"max_response_time_ms":{"type":["number","null"],"format":"double"},"min_response_time_ms":{"type":["number","null"],"format":"double"},"operational_count":{"type":"integer","format":"int64"},"p50_response_time_ms":{"type":["number","null"],"format":"double"},"p95_response_time_ms":{"type":["number","null"],"format":"double"},"p99_response_time_ms":{"type":["number","null"],"format":"double"},"status":{"type":"string"},"total_checks":{"type":"integer","format":"int64"},"uptime_percentage":{"type":"number","format":"double"}}},"StatusBucketedResponse":{"type":"object","required":["monitor_id","interval","buckets"],"properties":{"buckets":{"type":"array","items":{"$ref":"#/components/schemas/StatusBucket"}},"interval":{"type":"string"},"monitor_id":{"type":"integer","format":"int32"}}},"StatusCodeCount":{"type":"object","required":["status_code","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"percentage":{"type":"number","format":"double"},"status_code":{"type":"integer","format":"int32"}}},"StatusCodesQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"StatusPageOverview":{"type":"object","required":["status","monitors","recent_incidents"],"properties":{"monitors":{"type":"array","items":{"$ref":"#/components/schemas/MonitorStatus"}},"recent_incidents":{"type":"array","items":{"$ref":"#/components/schemas/IncidentResponse"}},"status":{"type":"string"}}},"StepConversionResponse":{"type":"object","required":["step_id","step_name","step_order","completions","conversion_rate","drop_off_rate","average_time_to_complete_seconds"],"properties":{"average_time_to_complete_seconds":{"type":"number","format":"double"},"completions":{"type":"integer","format":"int64","minimum":0},"conversion_rate":{"type":"number","format":"double"},"drop_off_rate":{"type":"number","format":"double"},"step_id":{"type":"integer","format":"int32"},"step_name":{"type":"string"},"step_order":{"type":"integer","format":"int32"}}},"StepResourceType":{"type":"string","description":"What kind of resource a migration step operates on","enum":["project","environment","deployment","environment-variable","service","domain","git-link","other"]},"StepResult":{"type":"object","description":"Result of executing a single migration step","required":["step_id","step_title","success","skipped","message","created_resources","duration_seconds"],"properties":{"created_resources":{"type":"array","items":{"$ref":"#/components/schemas/CreatedResource"},"description":"Resources created by this step"},"duration_seconds":{"type":"number","format":"double","description":"Duration of this step"},"message":{"type":"string","description":"Human-readable message about what happened"},"skipped":{"type":"boolean","description":"Whether this step was skipped"},"step_id":{"type":"string","description":"Step ID (matches `MigrationStep.id`)"},"step_title":{"type":"string","description":"Step title (for display)"},"success":{"type":"boolean","description":"Whether this step succeeded"}}},"StepUpResponse":{"type":"object","required":["expires_at"],"properties":{"expires_at":{"type":"string","format":"date-time","description":"ISO 8601 timestamp after which sensitive actions require verification\nagain."}}},"StopSequence":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"StorageQuota":{"type":"object","description":"Quota usage information for a project.","required":["project_id","metrics_bytes","traces_bytes","logs_bytes","total_bytes","limit_bytes","usage_pct"],"properties":{"limit_bytes":{"type":"integer","format":"int64","minimum":0},"logs_bytes":{"type":"integer","format":"int64","minimum":0},"metrics_bytes":{"type":"integer","format":"int64","minimum":0},"project_id":{"type":"integer","format":"int32"},"total_bytes":{"type":"integer","format":"int64","minimum":0},"traces_bytes":{"type":"integer","format":"int64","minimum":0},"usage_pct":{"type":"number","format":"double"}}},"StripeConfig":{"type":"object","properties":{"include_unpriced_charges":{"type":"boolean","description":"When an allowlist is set, should we still ingest charges that\nlack a price reference (e.g. standalone `charge.succeeded` without\na subscription)? Default true — charges don't belong to a SKU."},"metered_mode":{"$ref":"#/components/schemas/MeteredMode","description":"How to compute MRR for metered / tiered / hybrid subscriptions."},"price_allowlist":{"type":"array","items":{"type":"string"},"description":"Only events tagged with one of these Stripe price IDs are ingested.\nEmpty = accept all prices."},"product_allowlist":{"type":"array","items":{"type":"string"},"description":"Only events tagged with one of these Stripe product IDs are\ningested. Empty = accept all products. Combined with\n`price_allowlist` via OR — if either list has a match, accept."}}},"SyncedRepositoryListQuery":{"type":"object","properties":{"direction":{"type":["string","null"]},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"language":{"type":["string","null"]},"owner":{"type":["string","null"]},"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0},"private":{"type":["boolean","null"]},"search":{"type":["string","null"]},"sort":{"type":["string","null"]}}},"SyntaxResult":{"type":"object","description":"Syntax validation result","required":["is_valid_syntax"],"properties":{"domain":{"type":["string","null"],"description":"The domain part of the email","example":"gmail.com"},"is_valid_syntax":{"type":"boolean","description":"Whether the email syntax is valid"},"suggestion":{"type":["string","null"],"description":"Suggested email correction if available"},"username":{"type":["string","null"],"description":"The username part of the email","example":"someone"}}},"TagInfo":{"type":"object","required":["name","commit_sha"],"properties":{"commit_sha":{"type":"string"},"name":{"type":"string"}}},"TagListResponse":{"type":"object","required":["tags"],"properties":{"tags":{"type":"array","items":{"$ref":"#/components/schemas/TagInfo"}}}},"TailLogsRequest":{"type":"object","required":["project_id","service","env"],"properties":{"env":{"type":"string"},"external_service_id":{"type":["integer","null"],"format":"int32","description":"When set, tail an imported/managed external service's logs instead of\na project's (`project_id` is ignored in this mode)."},"levels":{"type":"array","items":{"type":"string"}},"project_id":{"type":"integer","format":"int32","description":"Project ID (integer, as used by the rest of the platform)"},"service":{"type":"string"},"text":{"type":["string","null"]}}},"TargetRecommendation":{"type":"object","description":"The temps/Hetzner target sizing and savings estimate","required":["server_type","vcpus","memory_gb","monthly_eur","fits_single_node","sizing_basis","rationale"],"properties":{"fits_single_node":{"type":"boolean","description":"Whether the workloads fit a single recommended server. When `false`,\nthe rationale explains the multi-node option (temps worker nodes)."},"memory_gb":{"type":"integer","format":"int32","description":"Memory (GB) of the recommended server"},"monthly_eur":{"type":"number","format":"double","description":"Estimated monthly price of the recommended server in EUR"},"monthly_savings_usd":{"type":["number","null"],"format":"double","description":"Estimated monthly savings in USD (current cost minus target cost,\ntreating EUR≈USD for the rough comparison — disclaimed in `notes`).\n`None` when the current cost is unknown."},"rationale":{"type":"string","description":"Human-readable recommendation summary"},"server_type":{"type":"string","description":"Recommended Hetzner server type (e.g. \"cpx32\")"},"sizing_basis":{"type":"string","description":"What the sizing was based on, e.g. \"2× measured usage + temps\nplatform overhead\" or \"resource requests (no metrics available)\""},"vcpus":{"type":"integer","format":"int32","description":"vCPUs of the recommended server"},"yearly_savings_usd":{"type":["number","null"],"format":"double","description":"`monthly_savings_usd × 12`"}}},"TeamListResponse":{"type":"object","required":["teams","total","page","page_size"],"properties":{"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"teams":{"type":"array","items":{"$ref":"#/components/schemas/TeamResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"TeamMemberResponse":{"type":"object","required":["id","team_id","user_id","role","added_by","created_at","updated_at"],"properties":{"added_by":{"type":"integer","format":"int32"},"created_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"},"id":{"type":"integer","format":"int32"},"role":{"$ref":"#/components/schemas/TeamRole","description":"The source of this member's project-scoped permissions, intersected\nwith `project_team_access.role`."},"team_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"},"user_email":{"type":["string","null"],"description":"The member's email, joined from `users`."},"user_id":{"type":"integer","format":"int32"},"user_name":{"type":["string","null"],"description":"The member's display name, joined from `users`. `None` if the\nreferenced user no longer exists."}}},"TeamResponse":{"type":"object","required":["id","name","slug","created_by","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"},"created_by":{"type":"integer","format":"int32"},"description":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"slug":{"type":"string"},"updated_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"}}},"TeamRole":{"type":"string","description":"Role a user holds within a team, or that a team holds on a project.\n\nNamed `TeamRole` rather than `Role` to keep it distinct from\n`temps_auth::permissions::Role`, which is the instance-wide role\n(Admin/User/…) attached to a session. The two are orthogonal: the\ninstance-wide role decides whether you may touch a resource *kind* at\nall, `TeamRole` decides what you may do *within a project* you have\nteam access to. See `temps_teams::fixed_role_permissions` for the\nproject-scoped permission set each variant maps to.\n\nStored as a `varchar(32)` rather than a Postgres enum so the role set\ncan evolve in pure migration code without a schema-level enum\nalteration blocking a downgrade.","enum":["owner","admin","deployer","viewer"]},"TemplateResponse":{"type":"object","description":"Response type for a single template","required":["slug","name","git","preset","tags","features","services","env_vars","is_featured"],"properties":{"description":{"type":["string","null"],"description":"Short description"},"env_vars":{"type":"array","items":{"$ref":"#/components/schemas/EnvVarTemplateResponse"},"description":"Environment variables template"},"exposed_port":{"type":["integer","null"],"format":"int32","description":"Container port the prebuilt image listens on (image deploys only)."},"features":{"type":"array","items":{"type":"string"},"description":"Feature highlights"},"git":{"$ref":"#/components/schemas/GitRefResponse","description":"Git repository reference"},"health_check_path":{"type":["string","null"],"description":"HTTP health-check path probed after the container starts (image deploys)."},"image":{"type":["string","null"],"description":"Prebuilt Docker image reference. When set, the one-click deploy pulls and\nruns this image directly (no build); when absent it builds from `git`."},"image_url":{"type":["string","null"],"description":"URL to template image/icon"},"is_featured":{"type":"boolean","description":"Whether the template is featured/promoted"},"name":{"type":"string","description":"Display name"},"preset":{"type":"string","description":"Framework/preset to use"},"screenshot_url":{"type":["string","null"],"description":"URL to a wide screenshot/banner preview of the deployed template.\nAbsent for templates that don't have one captured yet."},"services":{"type":"array","items":{"type":"string"},"description":"Required external services"},"slug":{"type":"string","description":"Unique identifier for the template (used in URLs)"},"tags":{"type":"array","items":{"type":"string"},"description":"Tags/categories for filtering"}}},"TestEmailRequest":{"type":"object","description":"Request body for testing an email provider","required":["from"],"properties":{"from":{"type":"string","description":"Sender email address (must be verified with the provider)","example":"test@example.com"},"from_name":{"type":["string","null"],"description":"Sender display name","example":"My App"}}},"TestEmailResponse":{"type":"object","description":"Response for test email endpoint","required":["success","sent_to"],"properties":{"error":{"type":["string","null"],"description":"Error message if the test failed"},"provider_message_id":{"type":["string","null"],"description":"Provider message ID if successful"},"sent_to":{"type":"string","description":"The email address the test was sent to","example":"user@example.com"},"success":{"type":"boolean","description":"Whether the test email was sent successfully"}}},"TestProviderKeyRequest":{"type":"object","required":["provider","api_key"],"properties":{"api_key":{"type":"string","description":"The raw API key to test"},"base_url":{"type":["string","null"],"description":"Optional custom base URL"},"provider":{"type":"string","description":"Provider ID: \"openai\", \"anthropic\", \"xai\", \"gemini\""}}},"TestProviderKeyResponse":{"type":"object","required":["success","provider","latency_ms"],"properties":{"error":{"type":["string","null"],"description":"Error message if the test failed"},"latency_ms":{"type":"integer","format":"int64","description":"Response time in milliseconds","minimum":0},"provider":{"type":"string"},"success":{"type":"boolean"}}},"TestProviderResponse":{"type":"object","required":["success"],"properties":{"message":{"type":["string","null"]},"success":{"type":"boolean"}}},"TimeBucketStats":{"type":"object","description":"Time bucket statistics response","required":["bucket","request_count","avg_response_time_ms","error_count","total_request_bytes","total_response_bytes"],"properties":{"avg_response_time_ms":{"type":"number","format":"double","description":"Average response time in milliseconds"},"bucket":{"type":"string","description":"Bucket timestamp in RFC3339 format","example":"2025-10-23T12:00:00Z"},"error_count":{"type":"integer","format":"int64","description":"Number of errors (status >= 400)"},"request_count":{"type":"integer","format":"int64","description":"Total number of requests in this bucket"},"total_request_bytes":{"type":"integer","format":"int64","description":"Total request bytes"},"total_response_bytes":{"type":"integer","format":"int64","description":"Total response bytes"}}},"TimeBucketStatsResponse":{"type":"object","description":"Response for time bucket stats","required":["stats","start_time","end_time","bucket_interval"],"properties":{"bucket_interval":{"type":"string"},"end_time":{"type":"string"},"start_time":{"type":"string"},"stats":{"type":"array","items":{"$ref":"#/components/schemas/TimeBucketStats"}}}},"TimeseriesBucket":{"type":"object","required":["bucket","request_count","input_tokens","output_tokens","avg_latency_ms"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"bucket":{"type":"string","description":"ISO 8601 timestamp"},"input_tokens":{"type":"integer","format":"int64"},"output_tokens":{"type":"integer","format":"int64"},"request_count":{"type":"integer","format":"int64"}}},"TimeseriesQueryParams":{"type":"object","properties":{"bucket":{"type":["string","null"],"description":"Bucket size: \"hour\", \"day\", \"week\" (defaults to \"day\")"},"conversation_id":{"type":["string","null"],"description":"Filter by conversation ID"},"from":{"type":["string","null"],"description":"ISO 8601 start time (defaults to 24h ago)"},"model":{"type":["string","null"],"description":"Filter by model name"},"provider":{"type":["string","null"],"description":"Filter by provider name"},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"to":{"type":["string","null"],"description":"ISO 8601 end time (defaults to now)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"TlsMode":{"type":"string","enum":["None","Starttls","Tls"]},"TodayStatsResponse":{"type":"object","description":"Today's stats response","required":["total_requests","date"],"properties":{"date":{"type":"string","description":"Date for which stats are returned","example":"2025-10-23"},"total_requests":{"type":"integer","format":"int64","description":"Total requests today"}}},"ToggleDeploymentMetricsRequest":{"type":"object","description":"Request body to toggle OTLP metric ingestion for a deployment.","required":["enabled"],"properties":{"enabled":{"type":"boolean","description":"Whether to enable (`true`) or disable (`false`) metric ingestion."},"path":{"type":["string","null"],"description":"Prometheus scrape path (optional, defaults to `/metrics`)."},"port":{"type":["integer","null"],"format":"int32","description":"Prometheus scrape port (optional).","minimum":0}}},"ToggleServiceMetricsRequest":{"type":"object","description":"Request body to toggle metric collection for an external service.","required":["enabled"],"properties":{"enabled":{"type":"boolean","description":"Whether to enable (`true`) or disable (`false`) metric collection."}}},"TokenRenewalRequest":{"type":"object","required":["refresh_token"],"properties":{"refresh_token":{"type":"string"}}},"ToolCallEvent":{"type":"object","description":"Payload for the `tool_call` SSE event: the model is about to run a tool.\nSerialized as compact single-line JSON onto one `data:` line.","required":["id","name","arguments"],"properties":{"arguments":{"type":"string","description":"The raw JSON-args string the model emitted."},"id":{"type":"string"},"name":{"type":"string"}}},"ToolInfo":{"type":"object","description":"One persisted tool invocation + its result, attached to an assistant message.","required":["id","name","arguments"],"properties":{"arguments":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"result":{"type":["string","null"]}}},"ToolResultEvent":{"type":"object","description":"Payload for the `tool_result` SSE event: a tool finished running. Serialized\nas compact single-line JSON; `content` is JSON-string-escaped so it stays on\none `data:` line even when long.","required":["id","name","content"],"properties":{"content":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"}}},"TopModelsQueryParams":{"type":"object","properties":{"from":{"type":["string","null"],"description":"ISO 8601 start time (defaults to 24h ago)"},"limit":{"type":["integer","null"],"format":"int64","description":"Max results (defaults to 10)","minimum":0},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"to":{"type":["string","null"],"description":"ISO 8601 end time (defaults to now)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"TraceProjectRef":{"type":"object","description":"All projects that contributed spans to a trace, including their sharing flag.\n\nReturned by `CrossProjectTraceService::find_trace_projects`.","required":["project_id","project_name","project_slug","first_seen","sharing"],"properties":{"first_seen":{"type":"string","format":"date-time"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"project_slug":{"type":"string","description":"URL slug used to link into the project's single-project trace view."},"sharing":{"type":"boolean","description":"Whether this project has `cross_project_trace_sharing = true`."}}},"TraceSummariesResponse":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TraceSummary"}},"total":{"type":["integer","null"],"format":"int64","description":"Total traces matching the filters, ignoring pagination. Omitted when\nthe request passed `include_total=false`, in which case the caller\nasked not to pay for the count — treat its absence as \"unknown\", not\nas zero.","minimum":0}}},"TraceSummary":{"type":"object","description":"A trace summary for the list view — one row per trace, aggregated from spans.","required":["trace_id","root_span_name","service_name","kind","status_code","start_time","duration_ms","span_count","error_count"],"properties":{"deployment_environment":{"type":["string","null"],"description":"The deployment environment from the root span's resource attributes (e.g. \"production\")."},"duration_ms":{"type":"number","format":"double"},"error_count":{"type":"integer","format":"int64"},"kind":{"$ref":"#/components/schemas/SpanKind"},"root_span_name":{"type":"string"},"service_name":{"type":"string"},"span_count":{"type":"integer","format":"int64"},"start_time":{"type":"string","format":"date-time"},"status_code":{"$ref":"#/components/schemas/SpanStatusCode"},"trace_id":{"type":"string"}}},"TracesResponse":{"type":"object","required":["data","count"],"properties":{"count":{"type":"integer","minimum":0},"data":{"type":"array","items":{"$ref":"#/components/schemas/SpanRecord"}}}},"TrackedLinkResponse":{"type":"object","description":"Tracked link with click count","required":["link_index","original_url","click_count"],"properties":{"click_count":{"type":"integer","format":"int32"},"link_index":{"type":"integer","format":"int32"},"original_url":{"type":"string"}}},"TrackingEventResponse":{"type":"object","description":"Email tracking event","required":["id","email_id","event_type","created_at"],"properties":{"created_at":{"type":"string"},"email_id":{"type":"string"},"event_type":{"type":"string"},"id":{"type":"integer","format":"int64"},"ip_address":{"type":["string","null"]},"link_index":{"type":["integer","null"],"format":"int32"},"link_url":{"type":["string","null"]},"user_agent":{"type":["string","null"]}}},"TriggerAgentRequest":{"type":"object","properties":{"trigger_source_id":{"type":["integer","null"],"format":"int32"},"trigger_source_type":{"type":["string","null"]},"user_context":{"type":["string","null"],"description":"Optional context from the user (e.g. a research topic, bug description, or instructions)."}}},"TriggerDigestResponse":{"type":"object","required":["success","message"],"properties":{"message":{"type":"string"},"success":{"type":"boolean"}}},"TriggerPipelinePayload":{"type":"object","properties":{"branch":{"type":["string","null"]},"commit":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment ID - if not provided, will use the project's preview environment"},"tag":{"type":["string","null"]}}},"TriggerPipelineResponse":{"type":"object","required":["message","project_id","environment_id"],"properties":{"branch":{"type":["string","null"]},"commit":{"type":["string","null"]},"environment_id":{"type":"integer","format":"int32"},"message":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"tag":{"type":["string","null"]}}},"TriggerScanRequest":{"type":"object","required":["environment_id"],"properties":{"environment_id":{"type":"integer","format":"int32","description":"Environment ID to scan (uses the current deployment for this environment)","example":1}}},"TriggerScanResponse":{"type":"object","required":["scan_id","status","message"],"properties":{"message":{"type":"string"},"scan_id":{"type":"integer","format":"int32"},"status":{"type":"string"}}},"TtlRequest":{"type":"object","description":"Request to get TTL for a key","required":["key"],"properties":{"key":{"type":"string","description":"The key to check TTL for","example":"session:abc"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"TtlResponse":{"type":"object","description":"Response for TTL operation","required":["ttl"],"properties":{"ttl":{"type":"integer","format":"int64","description":"TTL in seconds, -1 if no expiration, -2 if key doesn't exist","example":3600}}},"TxtRecord":{"type":"object","required":["name","value"],"properties":{"name":{"type":"string"},"value":{"type":"string"}}},"UiManifest":{"type":"object","description":"Describes the plugin's embedded UI bundle.","required":["entry_js"],"properties":{"css":{"type":"array","items":{"type":"string"},"description":"CSS files to load"},"entry_js":{"type":"string","description":"JavaScript entry point filename relative to the bundle root"},"routes":{"type":"array","items":{"$ref":"#/components/schemas/UiRoute"},"description":"Client-side routes the plugin handles"}}},"UiRoute":{"type":"object","description":"A client-side route provided by the plugin UI.","required":["path","title"],"properties":{"path":{"type":"string","description":"Route path pattern (e.g., \"/my-plugin\", \"/my-plugin/:id\")"},"title":{"type":"string","description":"Page title for breadcrumbs"}}},"UndrainNodeResponse":{"type":"object","description":"Response after undraining (reactivating) a node.","required":["id","name","status","message"],"properties":{"id":{"type":"integer","format":"int32"},"message":{"type":"string"},"name":{"type":"string"},"status":{"type":"string"}}},"UnifiedTrace":{"type":"object","description":"Merged cross-project trace result (Phase 2 unified waterfall).\n\nSpans are sorted by `start_time ASC`. At most 20 projects and 10,000\nspans total are included; `truncated` / `truncated_projects` signal when\nthe caps were hit.","required":["trace_id","projects","spans","start_time","end_time","total_duration_ms","span_count","error_count","has_redacted_spans","truncated","truncated_projects"],"properties":{"end_time":{"type":"string","format":"date-time"},"error_count":{"type":"integer","minimum":0},"has_redacted_spans":{"type":"boolean","description":"`true` when at least one project has `cross_project_trace_sharing = false`\nand its spans were therefore excluded from the result set."},"projects":{"type":"array","items":{"$ref":"#/components/schemas/ProjectRef"},"description":"Projects that contributed spans to this result set."},"span_count":{"type":"integer","minimum":0},"spans":{"type":"array","items":{"$ref":"#/components/schemas/AnnotatedSpan"},"description":"Annotated, merged span list sorted by `start_time ASC`."},"start_time":{"type":"string","format":"date-time"},"total_duration_ms":{"type":"number","format":"double","description":"Trace wall-clock duration in milliseconds (`end_time – start_time`)."},"trace_id":{"type":"string"},"truncated":{"type":"boolean","description":"`true` when the 20-project or 10,000-span cap was hit."},"truncated_projects":{"type":"array","items":{"type":"integer","format":"int32"},"description":"project_ids excluded due to truncation (most-recent first_seen dropped first)."}}},"UniqueCountsQuery":{"type":"object","description":"Query parameters for unique counts over time frame","required":["start_date","end_date"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment filter"},"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment filter"},"metric":{"type":"string","description":"Metric to count: \"sessions\" (unique sessions), \"visitors\" (unique visitors),\n\"returning_visitors\" (visitors seen before the range), or \"page_views\"\n(total page views) (default: \"sessions\")"},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"UniqueCountsResponse":{"type":"object","required":["count"],"properties":{"count":{"type":"integer","format":"int64"}}},"UnsupportedFeature":{"type":"object","description":"A feature from the source platform that cannot be migrated","required":["feature","reason"],"properties":{"alternative":{"type":["string","null"],"description":"Suggested alternative in Temps (if any)"},"feature":{"type":"string","description":"Feature name (e.g., \"Edge Middleware\", \"Serverless Functions\", \"Cron Jobs\")"},"reason":{"type":"string","description":"Why it can't be migrated"}}},"UpdateAdminGateRequest":{"type":"object","required":["allowed_ips","allowed_hosts","trust_forwarded_for"],"properties":{"allowed_hosts":{"type":"array","items":{"type":"string"}},"allowed_ips":{"type":"array","items":{"type":"string"}},"trust_forwarded_for":{"type":"boolean"}}},"UpdateAiProviderRequest":{"type":"object","description":"Body for `PATCH /settings/ai-providers/{provider_id}` — updates\nprovider-scoped settings (just the default model for now) without\ntouching the credential. Keeping credentials out of this shape means\nthe UI can auto-save model changes on select, without forcing the user\nto re-paste their token or config file.\nName-spaced schema name avoids an OpenAPI collision with\n`temps-notifications::UpdateProviderRequest`, which has different fields.\nBoth are exposed as `utoipa::ToSchema`; without the override the merged\nOpenAPI doc would silently shadow one struct with the other and break\ngenerated CLI/web clients.","properties":{"default_model":{"type":["string","null"],"description":"New default model id. `None` or an empty string clears the stored\nvalue so the CLI falls back to its own default."},"max_turns_analysis":{"type":["integer","null"],"format":"int32","description":"Default max turns for the autofixer analysis phase (1–200). `0`\nclears the stored value (built-in default applies); omitted/`None`\nleaves the current value unchanged — so a PATCH that only updates\n`default_model` doesn't wipe the turn settings."},"max_turns_feedback":{"type":["integer","null"],"format":"int32","description":"Default max turns for autofixer feedback rounds (1–200). `0` clears;\nomitted leaves unchanged."},"max_turns_fix":{"type":["integer","null"],"format":"int32","description":"Default max turns for the autofixer fix phase (1–200). `0` clears;\nomitted leaves unchanged."}}},"UpdateAiProviderResponse":{"type":"object","required":["provider_id"],"properties":{"default_model":{"type":["string","null"]},"max_turns_analysis":{"type":["integer","null"],"format":"int32"},"max_turns_feedback":{"type":["integer","null"],"format":"int32"},"max_turns_fix":{"type":["integer","null"],"format":"int32"},"provider_id":{"type":"string"}}},"UpdateAlertRuleRequest":{"type":"object","properties":{"cooldown_minutes":{"type":["integer","null"],"format":"int32"},"enabled":{"type":["boolean","null"]},"environment_filter":{"type":["integer","null"],"format":"int32"},"error_level_filter":{"type":["string","null"]},"name":{"type":["string","null"]},"notification_priority":{"type":["string","null"]},"trigger_config":{},"trigger_type":{"type":["string","null"]}}},"UpdateApiKeyRequest":{"type":"object","properties":{"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"is_active":{"type":["boolean","null"]},"name":{"type":["string","null"]},"permissions":{"type":["array","null"],"items":{"type":"string"},"example":["projects:read","deployments:read"]}}},"UpdateAutomaticDeployRequest":{"type":"object","required":["automatic_deploy"],"properties":{"automatic_deploy":{"type":"boolean"}}},"UpdateBackupScheduleRequest":{"type":"object","description":"Request body for updating an existing backup schedule via `PATCH /api/backups/schedules/{id}`.\n\nAll fields are optional; only present fields are updated. Absent fields\nleave the corresponding column unchanged.","properties":{"description":{"type":["string","null"],"description":"New human-readable description. Pass an empty string `\"\"` to clear."},"enabled":{"type":["boolean","null"],"description":"Enable or disable the schedule. Skipped when `None`."},"include_control_plane":{"type":["boolean","null"],"description":"Toggle whether the control-plane backup is produced on every run."},"max_runtime_secs":{"type":["integer","null"],"format":"int64","description":"Per-schedule wall-clock timeout override (seconds).\n\n- `None` (field absent) — leave current value unchanged\n- `Some(None)` (field present, JSON `null`) — clear override; fall back to engine default\n- `Some(Some(n))` — set to `n` seconds (must be >= 60)"},"name":{"type":["string","null"],"description":"New schedule name. Skipped when `None`. Must not be empty if provided."},"retention_period":{"type":["integer","null"],"format":"int32","description":"Days to retain backups produced by this schedule. Must be >= 1."},"schedule_expression":{"type":["string","null"],"description":"New cron expression. When changed, `next_run` is recomputed."},"tags":{"type":["array","null"],"items":{"type":"string"},"description":"Replace the full tag list. Skipped when `None`."},"target_all_services":{"type":["boolean","null"],"description":"Toggle between \"back up every database\" (`true`) and \"back up only\nthe explicit list\" (`false`). When set to `true`, the server clears\nthe explicit membership rows for this schedule."}}},"UpdateBlobRequest":{"type":"object","description":"Request to update Blob service configuration","properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use (e.g., \"rustfs/rustfs:1.0.0-alpha.98\")","example":"rustfs/rustfs:1.0.0-alpha.98"}}},"UpdateBlobResponse":{"type":"object","description":"Response after updating Blob service","required":["success","message","status"],"properties":{"message":{"type":"string","description":"Human-readable message","example":"Blob service updated successfully"},"status":{"$ref":"#/components/schemas/BlobStatusResponse","description":"Current status"},"success":{"type":"boolean","description":"Whether the operation succeeded","example":true}}},"UpdateCloudflareProviderRequest":{"type":"object","required":["config"],"properties":{"config":{"$ref":"#/components/schemas/CloudflareConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateConfigBody":{"type":"object","properties":{"config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ProviderConfig","description":"Typed provider configuration. Setting `config` to `null` clears\nthe stored config back to the accept-everything default. The\nconfig's `provider` tag must match the integration's provider."}]}}},"UpdateCustomDomainRequest":{"type":"object","properties":{"branch":{"type":["string","null"]},"domain":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"redirect_to":{"type":["string","null"]},"service_name":{"type":["string","null"],"description":"Docker Compose service name this domain routes to (empty string clears it)"},"status_code":{"type":["integer","null"],"format":"int32"}}},"UpdateDashboardRequest":{"type":"object","properties":{"layout":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DashboardLayout"}]},"name":{"type":["string","null"]}}},"UpdateDeploymentConfigRequest":{"type":"object","properties":{"automaticDeploy":{"type":["boolean","null"]},"cpuLimit":{"type":["integer","null"],"format":"int32"},"cpuRequest":{"type":["integer","null"],"format":"int32"},"crossArchitectureBuilds":{"type":["boolean","null"],"description":"Build one image per architecture the eligible nodes run. Off by\ndefault; environments inherit this and may override it. Cross-builds\nare emulated on the control plane and substantially slower, so they are\nopted into rather than triggered by cluster topology."},"exposedPort":{"type":["integer","null"],"format":"int32"},"memoryLimit":{"type":["integer","null"],"format":"int32"},"memoryRequest":{"type":["integer","null"],"format":"int32"},"performanceMetricsEnabled":{"type":["boolean","null"]},"replicas":{"type":["integer","null"],"format":"int32"},"security":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SecurityConfig"}]},"sessionRecordingEnabled":{"type":["boolean","null"]}}},"UpdateDeploymentTokenRequest":{"type":"object","properties":{"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"is_active":{"type":["boolean","null"]},"name":{"type":["string","null"]},"permissions":{"type":["array","null"],"items":{"type":"string"},"example":["visitors:enrich","emails:send"]}}},"UpdateDnsProviderRequest":{"type":"object","description":"Request to update a DNS provider","properties":{"credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DnsProviderCredentials","description":"New credentials"}]},"description":{"type":["string","null"],"description":"New description"},"is_active":{"type":["boolean","null"],"description":"Active status"},"name":{"type":["string","null"],"description":"New name"}}},"UpdateEmailProviderRequest":{"type":"object","description":"Request body for `PATCH /email-providers/{id}`.\n\nAll fields are optional. Omit any field to leave it unchanged. The\n`provider_type` is immutable — to switch providers, delete the row and\ncreate a new one. For credentials, supplying any credential variant\nre-encrypts the stored blob; omitting them preserves the existing secret\n(so operators can rename without re-typing passwords).","properties":{"is_active":{"type":["boolean","null"]},"name":{"type":["string","null"],"example":"My AWS SES"},"region":{"type":["string","null"],"example":"us-east-1"},"scaleway_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ScalewayCredentialsRequest"}]},"ses_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SesCredentialsRequest"}]},"smtp_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SmtpCredentialsRequest"}]},"sns_topic_arn":{"type":["string","null"],"description":"Rotate or clear the exact SNS topic allowed for this SES provider.\nOmit to preserve it, send `null` to clear it, or send a string to set it."}}},"UpdateEnvironmentSettingsRequest":{"type":"object","properties":{"anti_affinity":{"type":["boolean","null"],"description":"Anti-affinity: spread replicas across different nodes.\nWhen enabled, the scheduler avoids placing two replicas of the same\nenvironment on the same node. Defaults to `true`."},"attack_mode":{"type":["boolean","null"],"description":"Per-environment CAPTCHA attack-mode override (tri-state):\n- absent → leave the current override unchanged\n- JSON `null` → clear the override (inherit the project-level setting)\n- `true`/`false` → override the project setting for this environment"},"automatic_deploy":{"type":["boolean","null"],"description":"Enable/disable automatic deployments for this environment"},"branch":{"type":["string","null"]},"cpu_limit":{"type":["integer","null"],"format":"int32","description":"Maximum (limit) CPU in microcores. Send JSON `null` to clear → \"no limit\".\nAbsent leaves the current value unchanged."},"cpu_request":{"type":["integer","null"],"format":"int32","description":"Minimum (request) CPU in microcores. Send JSON `null` to clear (no request).\nAbsent leaves the current value unchanged."},"cross_architecture_builds":{"type":["boolean","null"],"description":"Build one image per architecture the eligible nodes run (overrides the\nproject-level setting). Off by default: cross-architecture builds are\nemulated on the control plane and substantially slower, so they are\nopted into per environment rather than triggered by cluster topology."},"exposed_port":{"type":["integer","null"],"format":"int32","description":"Port exposed by the container (overrides project-level port for this environment)\n\nPriority order for port resolution:\n1. Image EXPOSE directive (auto-detected from built image)\n2. This environment-level exposed_port (overrides project setting)\n3. Project-level exposed_port (fallback)\n4. Default: 3000","example":8080},"force_https":{"type":["boolean","null"],"description":"Per-environment HTTP→HTTPS redirect override (tri-state):\n- absent → leave the current override unchanged\n- JSON `null` → clear the override (inherit the proxy default, which\n redirects only when the host has an active TLS certificate)\n- `true` → always redirect plain HTTP to HTTPS for this environment,\n even when no local certificate exists (TLS terminated upstream)\n- `false` → never redirect this environment, even when a certificate does\n exist\n\nRequests under `/.well-known/acme-challenge/` are never redirected\nregardless of this setting, so ACME HTTP-01 validation always completes."},"idle_timeout_seconds":{"type":["integer","null"],"format":"int32","description":"Seconds of inactivity before stopping containers (60-86400). Default: 300."},"memory_limit":{"type":["integer","null"],"format":"int32","description":"Maximum (limit) memory in MB. Send JSON `null` to clear → \"no limit\".\nAbsent leaves the current value unchanged."},"memory_request":{"type":["integer","null"],"format":"int32","description":"Minimum (request) memory in MB. Send JSON `null` to clear (no request).\nAbsent leaves the current value unchanged."},"on_demand":{"type":["boolean","null"],"description":"Enable on-demand mode (scale-to-zero). Containers are stopped after\nidle_timeout_seconds of no traffic and started on the next request."},"password":{"type":["string","null"],"description":"Set a password to protect this environment. The proxy will show an HTML\npassword form before allowing access. The password is bcrypt-hashed\nserver-side and never stored in plaintext.\nSend an empty string to remove password protection."},"performance_metrics_enabled":{"type":["boolean","null"],"description":"Enable/disable performance metrics collection"},"protected":{"type":["boolean","null"],"description":"When true, git pushes do NOT auto-deploy to this environment.\nDeployments must be promoted from another environment."},"replicas":{"type":["integer","null"],"format":"int32"},"security":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SecurityConfig","description":"Security configuration for this environment (overrides project-level settings)"}]},"session_recording_enabled":{"type":["boolean","null"],"description":"Enable/disable session recording"},"target_labels":{"description":"Label selector for node-based scheduling (overrides project-level setting).\nSame key with array value -> OR, different keys -> AND.\nExample: `{\"region\": [\"us\", \"asia\"], \"gpu\": \"true\"}`"},"target_nodes":{"type":["array","null"],"items":{"type":"integer","format":"int32"},"description":"Optional list of node IDs to deploy to (overrides project-level setting)"},"wake_timeout_seconds":{"type":["integer","null"],"format":"int32","description":"Max seconds to wait for containers to start on wake (5-120). Default: 30."}}},"UpdateEnvironmentSubdomainRequest":{"type":"object","description":"Request to rename an environment's auto-managed subdomain.\n\nThe subdomain is the host label inserted in front of the platform's\npreview domain (e.g. `myapp` in `myapp.preview.temps.sh`). Renaming\nreplaces the previous subdomain entirely — the old hostname stops\nresolving immediately after this request succeeds.","required":["subdomain"],"properties":{"subdomain":{"type":"string","description":"New subdomain label. Must be a DNS-safe slug (lowercase letters,\ndigits, and hyphens, 1-63 characters). The value is slugified\nserver-side, so casing and disallowed characters are normalized.","example":"myapp"}}},"UpdateEnvironmentVariableRequest":{"type":"object","required":["key","environment_ids"],"properties":{"environment_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"include_in_preview":{"type":"boolean"},"is_secret":{"type":["boolean","null"],"description":"Optional secret-flag transition.\n- `Some(true)` promotes a regular var to a secret.\n- `Some(false)` is rejected if the row is already secret (one-way flag).\n- `None` (omitted) leaves the flag unchanged."},"key":{"type":"string"},"value":{"type":["string","null"],"description":"New plaintext value. `None` (omitted) keeps the existing ciphertext,\nwhich is the only way to edit a secret env var without re-typing its\nvalue (e.g. changing which environments it applies to)."}}},"UpdateErrorGroupRequest":{"type":"object","required":["status"],"properties":{"assigned_to":{"type":["string","null"]},"status":{"type":"string"}}},"UpdateExternalServiceRequest":{"type":"object","required":["parameters"],"properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use for the service (e.g., \"gotempsh/postgres-walg:18-bookworm\", \"timescale/timescaledb-ha:pg18\")\nWhen provided, the service will be recreated with the new image while preserving data"},"parameters":{"type":"object","additionalProperties":{},"propertyNames":{"type":"string"}}}},"UpdateFlagRequest":{"type":"object","properties":{"client_visible":{"type":["boolean","null"]},"default_value":{"description":"Must match the flag's existing `value_type`."},"description":{"type":["string","null"],"description":"Tri-state: absent leaves it, `null` clears it, a string sets it."}}},"UpdateGitSettingsRequest":{"type":"object","required":["main_branch","repo_owner","repo_name","directory"],"properties":{"directory":{"type":"string"},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"git_url":{"type":["string","null"],"description":"Git clone URL for public repositories"},"is_public_repo":{"type":["boolean","null"],"description":"Whether this is a public repository (no git provider connection needed)"},"main_branch":{"type":"string"},"preset":{"type":["string","null"]},"preset_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PresetConfigSchema","description":"Preset-specific configuration (e.g., Dockerfile path for Docker preset)\n\nExample for Dockerfile preset:\n```json\n{\n \"dockerfilePath\": \"docker/Dockerfile\",\n \"buildContext\": \"./api\"\n}\n```"}]},"repo_name":{"type":"string"},"repo_owner":{"type":"string"}}},"UpdateIncidentStatusRequest":{"type":"object","required":["status","message"],"properties":{"message":{"type":"string"},"status":{"type":"string"}}},"UpdateIpAccessControlRequest":{"type":"object","description":"Request to update an IP access control rule","properties":{"action":{"type":["string","null"],"description":"Optional new action"},"ip_address":{"type":["string","null"],"description":"Optional new IP address"},"reason":{"type":["string","null"],"description":"Optional new reason"}}},"UpdateKvRequest":{"type":"object","description":"Request to update KV service configuration","properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use (e.g., \"gotempsh/redis-walg:8-bookworm\")","example":"gotempsh/redis-walg:8-bookworm"}}},"UpdateKvResponse":{"type":"object","description":"Response after updating KV service","required":["success","message","status"],"properties":{"message":{"type":"string","description":"Status message","example":"KV service updated successfully"},"status":{"$ref":"#/components/schemas/KvStatusResponse","description":"Current service status"},"success":{"type":"boolean","description":"Whether the operation succeeded"}}},"UpdateManagedDomainApiRequest":{"type":"object","description":"Request to update a managed domain's settings.","properties":{"auto_manage":{"type":["boolean","null"],"description":"Toggle automatic DNS management for this domain."},"generated_hostname_mode":{"type":["string","null"],"description":"`\"standard\"` or `\"flat\"`. Persisted as-is; switching to `\"flat\"` does not\nrecompute existing hostnames — use the apply endpoint for that."},"sync_generated_records":{"type":["boolean","null"],"description":"Toggle DNS record sync for this domain."}}},"UpdateMcpRequest":{"type":"object","required":["config"],"properties":{"config":{"type":"object"},"description":{"type":["string","null"]},"name":{"type":["string","null"]}}},"UpdateMemberRoleRequest":{"type":"object","description":"The new fixed role for an existing membership.","required":["role"],"properties":{"role":{"$ref":"#/components/schemas/TeamRole"}}},"UpdateMetricAlertRequest":{"type":"object","properties":{"aggregation":{"type":["string","null"]},"detection_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DetectionConfig","description":"Replaces the detector wholesale when present (absent = leave unchanged)."}]},"dynamic_alerts":{"type":["boolean","null"],"description":"Toggles per-series (\"dynamic\") alerting (absent = leave unchanged)."},"enabled":{"type":["boolean","null"]},"for_duration_secs":{"type":["integer","null"],"format":"int32"},"group_by":{"type":["array","null"],"items":{"type":"string"},"description":"Replaces the group_by keys wholesale when present (absent = leave unchanged)."},"grouped_notification_threshold":{"type":["integer","null"],"format":"int32","description":"Updates the notification-grouping threshold (absent = leave unchanged)."},"label_filters":{"type":["array","null"],"items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"Replaces the label filters wholesale when present (absent = leave unchanged)."},"max_series":{"type":["integer","null"],"format":"int32","description":"Updates the dynamic-alerting cardinality cap (absent = leave unchanged)."},"metric_name":{"type":["string","null"]},"name":{"type":["string","null"]},"severity":{"type":["string","null"]},"window_secs":{"type":["integer","null"],"format":"int32"}}},"UpdateNotificationEmailProviderRequest":{"type":"object","required":["config"],"properties":{"config":{"$ref":"#/components/schemas/EmailConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateOidcProviderRequest":{"type":"object","properties":{"client_id":{"type":["string","null"]},"client_secret":{"type":["string","null"]},"default_role":{"type":["string","null"]},"enabled":{"type":["boolean","null"]},"group_claim":{"type":["string","null"]},"issuer_url":{"type":["string","null"]},"jit_provisioning":{"type":["boolean","null"]},"name":{"type":["string","null"]},"role_claim":{"type":["string","null"]},"scopes":{"type":["string","null"]},"template":{"type":["string","null"]},"trust_idp_email":{"type":["boolean","null"]}}},"UpdatePreferencesRequest":{"type":"object","required":["preferences"],"properties":{"preferences":{"$ref":"#/components/schemas/NotificationPreferencesResponse"}}},"UpdateProjectSecretRequest":{"type":"object","description":"Request to update a project secret. The `value` field is optional — omit it\nto rotate only the environment scoping / preview flag without touching the\nciphertext.","properties":{"environment_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"include_in_preview":{"type":"boolean"},"value":{"type":["string","null"],"description":"New plaintext value, <= 1 MiB. Omit to keep the existing value."}}},"UpdateProjectSettingsRequest":{"type":"object","properties":{"ai_alert_summaries_enabled":{"type":["boolean","null"],"description":"Opt in to AI summarization of metric alert notifications (ADR-021)."},"ai_debug_chat_enabled":{"type":["boolean","null"],"description":"Opt in to AI debugging chat, e.g. on deployment failures (ADR-023)."},"ai_write_actions_enabled":{"type":["boolean","null"],"description":"Opt in to AI propose-then-confirm write capability."},"attack_mode":{"type":["boolean","null"],"description":"Enable/disable attack mode (CAPTCHA protection) for all project environments"},"cross_project_trace_sharing":{"type":["boolean","null"],"description":"ADR-027 Phase 3 opt-out: set to false to suppress this project's traces\nfrom appearing in cross-project discovery results. Default true (consistent\nwith the OSS global-observability model). Omit to leave unchanged."},"directory":{"type":["string","null"]},"enable_preview_environments":{"type":["boolean","null"],"description":"Enable automatic preview environment creation for each branch"},"error_source_context_enabled":{"type":["boolean","null"],"description":"Opt in to native error-tracking source context (source-file upload +\nsource code shown in stack traces)."},"error_source_root":{"type":["string","null"],"description":"Set the auto-capture source root (relative to the checkout). Send an\nempty string to clear it back to the build-context default. Omit to\nleave unchanged."},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"main_branch":{"type":["string","null"]},"preset":{"type":["string","null"]},"preset_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PresetConfigSchema","description":"Preset-specific configuration (e.g., Dockerfile path for Docker preset)\n\nExample for Dockerfile preset:\n```json\n{\n \"dockerfilePath\": \"docker/Dockerfile\",\n \"buildContext\": \"./api\"\n}\n```"}]},"preview_envs_idle_timeout_seconds":{"type":["integer","null"],"format":"int32","description":"Idle timeout (seconds, 60..=86400) for on-demand preview environments."},"preview_envs_on_demand":{"type":["boolean","null"],"description":"When true, newly-created preview environments default to on-demand mode."},"preview_envs_wake_timeout_seconds":{"type":["integer","null"],"format":"int32","description":"Wake timeout (seconds, 5..=120) for on-demand preview environments."},"repo_name":{"type":["string","null"]},"repo_owner":{"type":["string","null"]},"slug":{"type":["string","null"]}}},"UpdateProviderCredentialsRequest":{"type":"object","description":"Partial-update payload for provider credentials. Every field is optional;\nonly the fields the user re-enters are applied. The server validates that\nthe fields supplied make sense for the provider's current auth_method\n(e.g. `app_id` + `private_key` only apply to GitHub Apps).","properties":{"app_id":{"type":["string","null"],"description":"Application ID (GitHub App integer as string; GitLab App string)."},"app_secret":{"type":["string","null"],"description":"GitLab App secret (not used by GitHub App — use `client_secret`)."},"client_id":{"type":["string","null"],"description":"OAuth client ID (GitLab OAuth, GitHub App)."},"client_secret":{"type":["string","null"],"description":"OAuth client secret (GitLab OAuth, GitHub App)."},"private_key":{"type":["string","null"],"description":"GitHub App private key (PEM)."},"redirect_uri":{"type":["string","null"],"description":"OAuth redirect URI (GitLab OAuth / GitLab App)."},"token":{"type":["string","null"],"description":"PAT for PAT-type providers."},"webhook_secret":{"type":["string","null"],"description":"GitHub App webhook secret."}}},"UpdateProviderKeyRequest":{"type":"object","properties":{"api_key":{"type":["string","null"]},"base_url":{"type":["string","null"],"description":"Double-Option: absent = leave unchanged, present-null = clear (revert to\nthe provider's default endpoint), present-value = set."},"default_model":{"type":["string","null"],"description":"Double-Option: absent = leave unchanged, present-null = clear the pinned\nmodel (revert to the per-provider default), present-value = set."},"display_name":{"type":["string","null"]},"is_active":{"type":["boolean","null"]}}},"UpdateProviderRequest":{"type":"object","properties":{"config":{},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateRouteRequest":{"type":"object","required":["host","port","enabled"],"properties":{"enabled":{"type":"boolean"},"host":{"type":"string"},"port":{"type":"integer","format":"int32"},"route_type":{"type":["string","null"],"description":"Route type: \"http\" (default) matches on HTTP Host header,\n\"tls\" matches on TLS SNI hostname for TCP passthrough"}}},"UpdateS3SourceRequest":{"type":"object","properties":{"access_key_id":{"type":["string","null"],"description":"Optional new access key ID","example":"AKIAXXXXXXXXXXXXXXXX"},"bucket_name":{"type":["string","null"],"description":"Optional new bucket name"},"bucket_path":{"type":["string","null"],"description":"Optional new bucket path"},"endpoint":{"type":["string","null"],"description":"Optional new endpoint URL for S3-compatible services","example":"http://minio.example.com:9000"},"force_path_style":{"type":["boolean","null"],"description":"Optional new path-style addressing setting","example":true},"name":{"type":["string","null"],"description":"Optional new name for the source"},"region":{"type":["string","null"],"description":"Optional new region"},"secret_key":{"type":["string","null"],"description":"Optional new secret key"}}},"UpdateSecretBody":{"type":"object","required":["signing_secret"],"properties":{"signing_secret":{"type":"string","description":"New signing secret from the provider's dashboard. Encrypted at\nrest; never returned in any API response."}}},"UpdateSelfRequest":{"type":"object","properties":{"email":{"type":["string","null"],"example":"john.doe@example.com"},"name":{"type":["string","null"],"example":"John Doe"}}},"UpdateSessionDurationRequest":{"type":"object","required":["duration"],"properties":{"duration":{"type":"integer","format":"int32"}}},"UpdateSessionDurationResponse":{"type":"object","required":["message"],"properties":{"message":{"type":"string"}}},"UpdateSkillRequest":{"type":"object","properties":{"content":{"type":["string","null"]},"description":{"type":["string","null"]},"name":{"type":["string","null"]}}},"UpdateSlackProviderRequest":{"type":"object","required":["config"],"properties":{"config":{"$ref":"#/components/schemas/SlackConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateSpeedMetricsPayload":{"type":"object","description":"Update speed metrics payload for late-loading metrics","properties":{"cls":{"type":["number","null"],"format":"float","description":"Cumulative Layout Shift (score)"},"inp":{"type":["number","null"],"format":"float","description":"Interaction to Next Paint (milliseconds)"}}},"UpdateStatusResponse":{"type":"object","description":"Result of the background release-update check, driving the web console's\nupgrade banner. All optional fields are set together iff\n`update_available` is true.","required":["update_available","docs_url"],"properties":{"channel":{"type":["string","null"],"description":"Channel the install tracks: `stable` or `beta`."},"checked_at":{"type":["string","null"],"description":"When the check that found the update ran (ISO 8601, UTC)."},"current_version":{"type":["string","null"],"description":"Version tag of the running binary, e.g. `v0.1.0-beta.45`."},"docs_url":{"type":"string","description":"Docs page with upgrade instructions. Always present so the UI links\nthe same page regardless of update state."},"latest_version":{"type":["string","null"],"description":"Newest published tag on this install's channel."},"release_url":{"type":["string","null"],"description":"Release-notes page (GitHub release) for the newer version."},"update_available":{"type":"boolean","description":"True when a newer release than the running binary has been published\non this install's channel."}}},"UpdateTeamRequest":{"type":"object","properties":{"description":{"type":["string","null"]},"name":{"type":["string","null"]}}},"UpdateTokenRequest":{"type":"object","required":["access_token"],"properties":{"access_token":{"type":"string"},"refresh_token":{"type":["string","null"]}}},"UpdateTokenResponse":{"type":"object","required":["connection_id","message","is_active"],"properties":{"connection_id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"message":{"type":"string"}}},"UpdateUserRequest":{"type":"object","properties":{"email":{"type":["string","null"],"example":"john.doe@example.com"},"name":{"type":["string","null"],"example":"John Doe"}}},"UpdateWebhookProviderRequest":{"type":"object","required":["config"],"properties":{"config":{"$ref":"#/components/schemas/WebhookConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateWebhookRequestBody":{"type":"object","properties":{"enabled":{"type":["boolean","null"],"description":"Whether the webhook is enabled"},"events":{"type":["array","null"],"items":{"type":"string"},"description":"Event types to subscribe to"},"secret":{"type":["string","null"],"description":"Secret for HMAC signature verification"},"url":{"type":["string","null"],"description":"Target URL for webhook delivery"}}},"UpgradeExternalServiceRequest":{"type":"object","required":["docker_image"],"properties":{"docker_image":{"type":"string","description":"Docker image to upgrade to (e.g., \"gotempsh/postgres-walg:18-bookworm\")\nThis will trigger pg_upgrade for PostgreSQL or equivalent upgrade procedures for other services","example":"gotempsh/postgres-walg:18-bookworm"}}},"UpgradeRequest":{"type":"object","required":["image"],"properties":{"image":{"type":"string","description":"Image reference to pull and run (e.g.\n`ghcr.io/gotempsh/temps-preview-gateway:latest`). Empty resets to default."}}},"UpsertAgentRequest":{"type":"object","properties":{"ai_model":{"type":["string","null"],"description":"Preferred model identifier for the CLI. `Some(\"\")` clears the stored value."},"ai_provider":{"type":["string","null"]},"ai_provider_key_id":{"type":["integer","null"],"format":"int32"},"api_key":{"type":["string","null"],"description":"Plain-text API key — will be encrypted before storage"},"branch_prefix":{"type":["string","null"]},"config_repo_branch":{"type":["string","null"],"description":"Branch of the config repo to use (default: \"main\")."},"config_repo_url":{"type":["string","null"],"description":"Private config repo containing .claude/ directory (skills, MCP, plugins)."},"cooldown_minutes":{"type":["integer","null"],"format":"int32"},"daily_budget_cents":{"type":["integer","null"],"format":"int32"},"deliverable":{"type":["string","null"]},"description":{"type":["string","null"]},"enabled":{"type":["boolean","null"]},"max_turns":{"type":["integer","null"],"format":"int32"},"mcp_servers_config":{"description":"MCP servers config (Claude Code settings.json mcpServers format).\nCredential-bearing legacy inline objects are write-only: normal reads\nmask them, and updates must omit this field to preserve existing values."},"name":{"type":["string","null"]},"prompt":{"type":["string","null"]},"sandbox_enabled":{"type":["boolean","null"]},"skills_config":{"description":"Skills config as JSON array."},"slug":{"type":["string","null"]},"timeout_seconds":{"type":["integer","null"],"format":"int32"},"tools_config":{"description":"Tools config as JSON array. Custom-tool webhook URLs and headers are\nwrite-only; omit this field on update to preserve them."},"trigger_config":{"description":"Trigger configuration JSON: { \"error\": { \"new_issue\": true, \"regression\": true }, \"manual\": true }"}}},"UpsertSecretRequest":{"type":"object","required":["name","value"],"properties":{"description":{"type":["string","null"]},"mount_path":{"type":["string","null"],"description":"Required for \"file\" type secrets — absolute path inside the sandbox"},"name":{"type":"string"},"secret_type":{"type":"string","description":"\"env\" (environment variable) or \"file\" (written to mount_path)"},"value":{"type":"string"}}},"UptimeDataPoint":{"type":"object","required":["timestamp","status"],"properties":{"error_message":{"type":["string","null"]},"response_time_ms":{"type":["integer","null"],"format":"int32"},"status":{"type":"string"},"timestamp":{"type":"string","format":"date-time"}}},"UptimeHistoryResponse":{"type":"object","required":["monitor_id","uptime_data"],"properties":{"monitor_id":{"type":"integer","format":"int32"},"uptime_data":{"type":"array","items":{"$ref":"#/components/schemas/UptimeDataPoint"}}}},"UsageFilter":{"type":"object","description":"Filters for querying AI usage data.\n\nCost bounds are expressed in microcents (the unit stored in\n`estimated_cost_microcents`). At most one of `gte`/`gt` and one of\n`lte`/`lt` is meaningful per query; if both are set the stricter wins\nnaturally because they are ANDead together.","properties":{"conversation_id":{"type":["string","null"]},"cost_gt":{"type":["integer","null"],"format":"int64","description":"Cost strictly greater-than, in microcents."},"cost_gte":{"type":["integer","null"],"format":"int64","description":"Cost greater-than-or-equal, in microcents."},"cost_lt":{"type":["integer","null"],"format":"int64","description":"Cost strictly less-than, in microcents."},"cost_lte":{"type":["integer","null"],"format":"int64","description":"Cost less-than-or-equal, in microcents."},"model":{"type":["string","null"]},"provider":{"type":["string","null"]},"status":{"type":["integer","null"],"format":"int32","description":"Filter by HTTP status code (exact match)."},"tags":{"type":["string","null"],"description":"Comma-separated tags to filter by (AND logic)."},"tokens_gt":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) strictly greater-than."},"tokens_gte":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) greater-than-or-equal."},"tokens_lt":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) strictly less-than."},"tokens_lte":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) less-than-or-equal."},"user_id":{"type":["integer","null"],"format":"int32"}}},"UsageInfo":{"type":"object","required":["prompt_tokens","completion_tokens","total_tokens"],"properties":{"completion_tokens":{"type":"integer","format":"int64"},"prompt_tokens":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"UsageLogEntry":{"type":"object","required":["id","timestamp","provider","model","input_tokens","output_tokens","latency_ms","estimated_cost_microcents","status","is_streaming","is_byok","tags"],"properties":{"conversation_id":{"type":["string","null"]},"estimated_cost_microcents":{"type":"integer","format":"int64"},"id":{"type":"integer","format":"int64"},"input_tokens":{"type":"integer","format":"int64"},"is_byok":{"type":"boolean"},"is_streaming":{"type":"boolean"},"latency_ms":{"type":"integer","format":"int32"},"model":{"type":"string"},"output_tokens":{"type":"integer","format":"int64"},"provider":{"type":"string"},"request_id":{"type":["string","null"]},"status":{"type":"integer","format":"int32"},"tags":{"type":"array","items":{"type":"string"}},"timestamp":{"type":"string"},"trace_id":{"type":["string","null"]}}},"UsageLogPage":{"type":"object","description":"A page of recent usage log entries plus the total count for pagination.","required":["entries","total"],"properties":{"entries":{"type":"array","items":{"$ref":"#/components/schemas/UsageLogEntry"},"description":"The usage log entries for the requested page."},"total":{"type":"integer","format":"int64","description":"Total number of entries matching the filter (across all pages)."}}},"UsageQueryParams":{"type":"object","properties":{"conversation_id":{"type":["string","null"],"description":"Filter by conversation ID"},"from":{"type":["string","null"],"description":"ISO 8601 start time (defaults to 24h ago)"},"model":{"type":["string","null"],"description":"Filter by model name"},"provider":{"type":["string","null"],"description":"Filter by provider name"},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"to":{"type":["string","null"],"description":"ISO 8601 end time (defaults to now)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"UsageSource":{"type":"string","description":"How the \"actual usage\" numbers were obtained","enum":["metrics-api","requests-only","unavailable"]},"UsageSummary":{"type":"object","required":["total_requests","total_input_tokens","total_output_tokens","total_tokens","avg_latency_ms","total_cost_microcents","error_count","streaming_count","byok_count"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"byok_count":{"type":"integer","format":"int64"},"error_count":{"type":"integer","format":"int64"},"streaming_count":{"type":"integer","format":"int64"},"total_cost_microcents":{"type":"integer","format":"int64"},"total_input_tokens":{"type":"integer","format":"int64"},"total_output_tokens":{"type":"integer","format":"int64"},"total_requests":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"UserResponse":{"type":"object","required":["id","username","name","avatar_url","mfa_enabled","role"],"properties":{"avatar_url":{"type":"string"},"email":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"mfa_enabled":{"type":"boolean"},"name":{"type":"string"},"role":{"type":"string","description":"User's role (e.g., \"admin\", \"user\", \"demo\")"},"username":{"type":"string"}}},"ValidateEmailRequest":{"type":"object","description":"Request body for validating an email address","required":["email"],"properties":{"email":{"type":"string","description":"Email address to validate","example":"someone@gmail.com"}},"additionalProperties":false},"ValidateEmailResponse":{"type":"object","description":"Complete email validation response","required":["email","is_reachable","syntax","mx","misc","smtp"],"properties":{"email":{"type":"string","description":"The email address that was validated","example":"someone@gmail.com"},"is_reachable":{"$ref":"#/components/schemas/ReachabilityStatus","description":"Overall reachability status: safe, risky, invalid, or unknown"},"misc":{"$ref":"#/components/schemas/MiscResult","description":"Miscellaneous validation result"},"mx":{"$ref":"#/components/schemas/MxResult","description":"MX record validation result"},"smtp":{"$ref":"#/components/schemas/SmtpResult","description":"SMTP validation result"},"syntax":{"$ref":"#/components/schemas/SyntaxResult","description":"Syntax validation result"}}},"ValidationLevel":{"type":"string","description":"Validation severity level","enum":["info","warning","error","critical"]},"ValidationReport":{"type":"object","description":"Complete validation report","required":["results","overall_status","summary"],"properties":{"overall_status":{"$ref":"#/components/schemas/ValidationStatus","description":"Overall status"},"results":{"type":"array","items":{"$ref":"#/components/schemas/ValidationResult"},"description":"All validation results"},"summary":{"$ref":"#/components/schemas/ValidationSummary","description":"Summary statistics"}}},"ValidationResponse":{"type":"object","required":["connection_id","is_valid","message"],"properties":{"connection_id":{"type":"integer","format":"int32"},"is_valid":{"type":"boolean"},"message":{"type":"string"}}},"ValidationResult":{"type":"object","description":"Result of a validation check","required":["rule_id","rule_name","level","passed","message","affected_resources"],"properties":{"affected_resources":{"type":"array","items":{"type":"string"},"description":"Affected resources/fields"},"level":{"$ref":"#/components/schemas/ValidationLevel","description":"Validation level"},"message":{"type":"string","description":"Message describing the result"},"passed":{"type":"boolean","description":"Whether the validation passed"},"remediation":{"type":["string","null"],"description":"Suggested remediation (if failed)"},"rule_id":{"type":"string","description":"Rule that was checked"},"rule_name":{"type":"string","description":"Human-readable rule name"}}},"ValidationStatus":{"type":"string","description":"Overall validation status","enum":["passed","passed-with-warnings","failed-with-warnings","failed"]},"ValidationSummary":{"type":"object","description":"Validation summary statistics","required":["total_count","passed_count","failed_count","info_count","warning_count","error_count","critical_count"],"properties":{"critical_count":{"type":"integer","description":"Critical-level results","minimum":0},"error_count":{"type":"integer","description":"Error-level results","minimum":0},"failed_count":{"type":"integer","description":"Validations that failed","minimum":0},"info_count":{"type":"integer","description":"Info-level results","minimum":0},"passed_count":{"type":"integer","description":"Validations that passed","minimum":0},"total_count":{"type":"integer","description":"Total validations run","minimum":0},"warning_count":{"type":"integer","description":"Warning-level results","minimum":0}}},"VerifyMfaRequest":{"type":"object","required":["code"],"properties":{"code":{"type":"string"}}},"VerifyStepUpRequest":{"type":"object","required":["code"],"properties":{"code":{"type":"string","description":"Current TOTP value or an unused recovery code."}}},"ViewItem":{"type":"object","required":["label","value"],"properties":{"label":{"type":"string","format":"date-time"},"value":{"type":"integer","format":"int64"}}},"ViewsOverTime":{"type":"object","required":["items","metric","present_index"],"properties":{"comparison_labels":{"type":["array","null"],"items":{"type":"string"}},"comparison_plot":{"type":["array","null"],"items":{"type":"integer","format":"int64"}},"full_intervals":{"type":["array","null"],"items":{"type":"string"}},"items":{"type":"array","items":{"$ref":"#/components/schemas/ViewItem"}},"metric":{"type":"string"},"present_index":{"type":"integer","minimum":0}}},"ViewsOverTimeQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"VisitorDetails":{"type":"object","required":["id","visitor_id","project_id","environment_id","first_seen","last_seen","is_crawler"],"properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"crawler_name":{"type":["string","null"]},"custom_data":{},"environment_id":{"type":"integer","format":"int32"},"first_channel":{"type":["string","null"],"description":"Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")"},"first_referrer":{"type":["string","null"],"description":"Full referrer URL from the visitor's first session"},"first_referrer_hostname":{"type":["string","null"],"description":"Hostname extracted from first_referrer"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":["string","null"]},"ip_address_id":{"type":["integer","null"],"format":"int32"},"is_crawler":{"type":"boolean"},"is_eu":{"type":["boolean","null"]},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"latitude":{"type":["number","null"],"format":"double"},"longitude":{"type":["number","null"],"format":"double"},"project_id":{"type":"integer","format":"int32"},"region":{"type":["string","null"]},"timezone":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":"string"}}},"VisitorFacetValue":{"type":"object","description":"A single facet value with its visitor count. Used to populate filter\ndropdowns on the visitors page (e.g. \"Germany — 1,234 visitors\").","required":["value","count"],"properties":{"code":{"type":["string","null"],"description":"Optional secondary code for the value. Currently only populated for\nthe `country` facet, where it carries the 2-letter ISO country code\nso the UI can render a flag without re-mapping."},"count":{"type":"integer","format":"int64","description":"Distinct visitor count matching this value in the current segment."},"value":{"type":"string","description":"The dimension value (e.g. \"United States\", \"Chrome\", \"google.com\").\n`None` is encoded as the literal string \"Direct\" for referrer and as\nthe empty string for the rest."}}},"VisitorFacets":{"type":"object","description":"All filter dropdown contents in one response. Each list is the top N\nvalues for that dimension within the current date range and segment\n(excluding the dimension being queried so the dropdown still shows\nalternatives when a value is already selected).","required":["country","region","city","channel","referrer"],"properties":{"channel":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}},"city":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}},"country":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}},"referrer":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}},"region":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}}}},"VisitorFacetsQuery":{"allOf":[{"$ref":"#/components/schemas/VisitorSegmentFilters"},{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"has_activity_only":{"type":["boolean","null"]},"include_crawlers":{"type":["boolean","null"]},"per_facet_limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of values returned per dimension (default: 50, max: 200)."},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}}],"description":"Query parameters for the visitor-facets endpoint. Mirrors the shape of\n`VisitorsListQuery` so the same segment filters apply — facet counts are\nalways computed against the *currently filtered* visitor pool, minus the\ndimension being aggregated."},"VisitorInfo":{"type":"object","required":["id","visitor_id","project_id","environment_id","first_seen","last_seen","is_crawler"],"properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"crawler_name":{"type":["string","null"]},"current_page":{"type":["string","null"],"description":"Most recent page path visited by this visitor"},"custom_data":{},"environment_id":{"type":"integer","format":"int32"},"first_channel":{"type":["string","null"],"description":"Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")"},"first_referrer":{"type":["string","null"],"description":"Full referrer URL from the visitor's first session"},"first_referrer_hostname":{"type":["string","null"],"description":"Hostname extracted from first_referrer"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":["string","null"]},"ip_address_id":{"type":["integer","null"],"format":"int32"},"is_crawler":{"type":"boolean"},"is_eu":{"type":["boolean","null"]},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"latitude":{"type":["number","null"],"format":"double"},"longitude":{"type":["number","null"],"format":"double"},"project_id":{"type":"integer","format":"int32"},"region":{"type":["string","null"]},"timezone":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":"string"}}},"VisitorJourneyQuery":{"type":"object","required":["project_id"],"properties":{"limit_sessions":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"VisitorJourneyResponse":{"type":"object","description":"Complete visitor journey response","required":["visitor_id","total_sessions","total_events","sessions"],"properties":{"sessions":{"type":"array","items":{"$ref":"#/components/schemas/JourneySession"},"description":"Sessions with their events, ordered newest first"},"total_events":{"type":"integer","format":"int64","description":"Total number of events across all sessions"},"total_sessions":{"type":"integer","format":"int64","description":"Total number of sessions"},"visitor_id":{"type":"integer","format":"int32","description":"Visitor internal ID"}}},"VisitorLocationsQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"granularity":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/LocationGranularity"}]},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"VisitorRecord":{"type":"object","required":["id","visitor_id","project_id","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"custom_data":{},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"visitor_id":{"type":"string"}}},"VisitorSegmentFilters":{"type":"object","description":"Optional segment filters for [`VisitorsListQuery`]. Each filter narrows the\nresult set to visitors who match the given dimension value within the date\nrange. All filters resolve against `visitor` / `ip_geolocations` — by\ndesign we never touch the events hypertable here so filtering stays fast\nregardless of event volume.","properties":{"filter_channel":{"type":["string","null"],"description":"First-touch marketing channel (matches `visitor.first_channel`)"},"filter_city":{"type":["string","null"],"description":"Geolocation city (matches `ip_geolocations.city`)"},"filter_country":{"type":["string","null"],"description":"Geolocation country (matches `ip_geolocations.country`)"},"filter_referrer":{"type":["string","null"],"description":"First-touch referrer hostname (matches `visitor.first_referrer_hostname`)"},"filter_region":{"type":["string","null"],"description":"Geolocation region (matches `ip_geolocations.region`)"}}},"VisitorSessionsQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"VisitorSessionsResponse":{"type":"object","required":["visitor_id","sessions","total_sessions"],"properties":{"sessions":{"type":"array","items":{"$ref":"#/components/schemas/SessionSummary"}},"total_sessions":{"type":"integer","format":"int64"},"visitor_id":{"type":"string"}}},"VisitorStats":{"type":"object","required":["visitor_id","first_seen","last_seen","total_sessions","total_page_views","total_events","average_session_duration","bounce_rate","engagement_rate","top_pages","top_referrers","devices_used","locations"],"properties":{"average_session_duration":{"type":"number","format":"double"},"bounce_rate":{"type":"number","format":"double"},"devices_used":{"type":"array","items":{"type":"string"}},"engagement_rate":{"type":"number","format":"double"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"locations":{"type":"array","items":{"$ref":"#/components/schemas/LocationInfo"}},"top_pages":{"type":"array","items":{"$ref":"#/components/schemas/PageVisit"}},"top_referrers":{"type":"array","items":{"type":"string"}},"total_events":{"type":"integer","format":"int64"},"total_page_views":{"type":"integer","format":"int64"},"total_sessions":{"type":"integer","format":"int64"},"visitor_id":{"type":"integer","format":"int32"}}},"VisitorWithGeolocation":{"type":"object","required":["id","visitor_id","project_id","environment_id","first_seen","last_seen","is_crawler"],"properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"crawler_name":{"type":["string","null"]},"custom_data":{},"environment_id":{"type":"integer","format":"int32"},"first_channel":{"type":["string","null"],"description":"Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")"},"first_referrer":{"type":["string","null"],"description":"Full referrer URL from the visitor's first session"},"first_referrer_hostname":{"type":["string","null"],"description":"Hostname extracted from first_referrer"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":["string","null"]},"is_crawler":{"type":"boolean"},"is_eu":{"type":["boolean","null"]},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"latitude":{"type":["number","null"],"format":"double"},"longitude":{"type":["number","null"],"format":"double"},"project_id":{"type":"integer","format":"int32"},"region":{"type":["string","null"]},"timezone":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":"string"}}},"VisitorsListQuery":{"allOf":[{"$ref":"#/components/schemas/VisitorSegmentFilters"},{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"has_activity_only":{"type":["boolean","null"],"description":"Filter to only include visitors with recorded activity (events/sessions).\nWhen true, excludes \"ghost\" visitors that have no events."},"include_crawlers":{"type":["boolean","null"]},"limit":{"type":["integer","null"],"format":"int32"},"offset":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}}]},"VisitorsResponse":{"type":"object","required":["visitors","total_count","filtered_count"],"properties":{"filtered_count":{"type":"integer","format":"int64"},"total_count":{"type":"integer","format":"int64"},"visitors":{"type":"array","items":{"$ref":"#/components/schemas/VisitorInfo"}}}},"VolumeMount":{"type":"object","description":"Volume mount in deployment","required":["source","destination","read_only","type"],"properties":{"destination":{"type":"string","description":"Destination path in container"},"read_only":{"type":"boolean","description":"Read-only flag"},"source":{"type":"string","description":"Source (volume name or path)"},"type":{"$ref":"#/components/schemas/VolumeType","description":"Volume type"}}},"VolumeType":{"type":"string","description":"Volume type","enum":["bind","volume","tmpfs"]},"VulnerabilityResponse":{"type":"object","required":["id","scan_id","vulnerability_id","package_name","installed_version","severity","title","created_at"],"properties":{"class":{"type":["string","null"],"example":"os-pkgs"},"created_at":{"type":"string","example":"2025-12-08T12:15:47.609192Z"},"cvss_score":{"type":["number","null"],"format":"float"},"description":{"type":["string","null"]},"fixed_version":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"installed_version":{"type":"string"},"last_modified_date":{"type":["string","null"],"example":"2025-12-08T12:15:47.609192Z"},"package_name":{"type":"string"},"primary_url":{"type":["string","null"]},"published_date":{"type":["string","null"],"example":"2025-12-08T12:15:47.609192Z"},"references":{},"scan_id":{"type":"integer","format":"int32"},"severity":{"type":"string"},"target":{"type":["string","null"],"example":"alpine:3.18 (alpine 3.18.0)"},"title":{"type":"string"},"type":{"type":["string","null"],"example":"alpine"},"vulnerability_id":{"type":"string"}}},"WalWarning":{"oneOf":[{"type":"object","description":"`pg_wal` is significantly larger than `max_wal_size`.","required":["pg_wal_bytes","max_wal_size_bytes","ratio","kind"],"properties":{"kind":{"type":"string","enum":["wal_bloat"]},"max_wal_size_bytes":{"type":"integer","format":"int64"},"pg_wal_bytes":{"type":"integer","format":"int64"},"ratio":{"type":"number","format":"double"}}},{"type":"object","description":"A replication slot is holding WAL it's not consuming.","required":["slot_name","retained_bytes","active","kind"],"properties":{"active":{"type":"boolean"},"kind":{"type":"string","enum":["stale_slot"]},"retained_bytes":{"type":"integer","format":"int64"},"slot_name":{"type":"string"}}},{"type":"object","description":"`archive_status/*.ready` count exceeds threshold — `archive_command`\nis either failing or running slower than WAL generation.","required":["ready_count","kind"],"properties":{"kind":{"type":"string","enum":["archive_backlog"]},"ready_count":{"type":"integer","format":"int64"}}},{"type":"object","description":"`archive_mode = on` but `archive_command` is empty / `/bin/true`.\nWAL accumulates forever waiting for a destination that never accepts.","required":["kind"],"properties":{"kind":{"type":"string","enum":["archive_mode_without_command"]}}},{"type":"object","description":"Oldest WAL segment is older than `WAL_NOT_RECYCLED_AGE_SECS`.\nIndependent signal: something is blocking recycling even if total\nsize hasn't exploded yet.","required":["oldest_age_secs","kind"],"properties":{"kind":{"type":"string","enum":["wal_not_recycled"]},"oldest_age_secs":{"type":"integer","format":"int64"}}}],"description":"One actionable warning surfaced to the UI.\n\nEach variant carries the data needed to render a remediation hint without\nthe frontend re-querying anything."},"WalWarningSeverity":{"type":"string","enum":["warning","critical"]},"WebhookConfig":{"type":"object","description":"Configuration for a generic webhook notification provider","required":["url"],"properties":{"headers":{"type":"object","description":"Custom headers to include in the request (e.g., for authentication tokens)","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"},"example":{"Authorization":"Bearer your-token","X-Custom-Header":"custom-value"}},"method":{"type":"string","description":"HTTP method to use (POST, PUT, PATCH). Defaults to POST.","example":"POST"},"timeout_secs":{"type":"integer","format":"int64","description":"Request timeout in seconds. Defaults to 30.","example":30,"minimum":0},"url":{"type":"string","description":"The URL to send webhook requests to","example":"https://api.example.com/notifications"}}},"WebhookDeliveryResponse":{"type":"object","required":["id","webhook_id","event_type","event_id","payload","success","attempt_number","created_at"],"properties":{"attempt_number":{"type":"integer","format":"int32"},"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"delivered_at":{"type":["string","null"],"format":"date-time"},"error_message":{"type":["string","null"]},"event_id":{"type":"string"},"event_type":{"type":"string"},"id":{"type":"integer","format":"int32"},"payload":{"type":"string","description":"JSON payload that was sent to the webhook endpoint","example":{"event_type":"deployment.succeeded","data":{"deployment_id":123}}},"status_code":{"type":["integer","null"],"format":"int32"},"success":{"type":"boolean"},"webhook_id":{"type":"integer","format":"int32"}}},"WebhookResponse":{"type":"object","required":["id","project_id","url","events","enabled","has_secret","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"enabled":{"type":"boolean"},"events":{"type":"array","items":{"type":"string"}},"has_secret":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"url":{"type":"string"}}},"WebhookTriggerRequest":{"allOf":[{"description":"Arbitrary JSON payload from the caller. Passed to the agent as user_context."}]},"WebhookTriggerResponse":{"type":"object","required":["run_id","status"],"properties":{"run_id":{"type":"integer","format":"int32"},"status":{"type":"string"}}},"WorkflowDryRunRequest":{"type":"object","required":["yaml"],"properties":{"cpu_limit":{"type":["number","null"],"format":"double","description":"Optional CPU override applied after parsing YAML (clamped server-side).\nWhen `Some`, this takes precedence over `cpu_limit` inside the YAML —\nlets the CLI pass `--cpu` without rewriting the YAML text."},"error_group_id":{"type":["integer","null"],"format":"int32","description":"Optional error group to link this dry-run to. When set, the executor's\n`load_error_context` path injects `{{error_type}}` / `{{error_message}}`\n/ `{{stack_trace}}` into the prompt — same behaviour as a committed\nworkflow triggered with `trigger_source_type = \"error_group\"`. Must\nbelong to `project_id` (handler enforces)."},"memory_limit_mb":{"type":["integer","null"],"format":"int64","description":"Optional memory override in MB (clamped server-side). Same precedence\nrule as `cpu_limit`.","minimum":0},"user_context":{"type":["string","null"],"description":"Optional context appended to the prompt (e.g. \"test against staging\nonly\"). Mirrors `TriggerAgentRequest.user_context`."},"yaml":{"type":"string","description":"Full WorkflowYamlConfig as YAML text. Server validates and re-serializes\nbefore storing on the run row."}}},"WorkloadDescriptor":{"type":"object","description":"Brief descriptor for discovered workloads (used in listing)","required":["id","workload_type","status","labels"],"properties":{"created_at":{"type":["string","null"],"format":"date-time","description":"Creation timestamp"},"id":{"$ref":"#/components/schemas/WorkloadId","description":"Unique ID in source system"},"image":{"type":["string","null"],"description":"Image/build reference (for containers)"},"labels":{"type":"object","description":"Labels/tags from source system","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":["string","null"],"description":"Workload name (if any)"},"status":{"$ref":"#/components/schemas/WorkloadStatus","description":"Current status"},"workload_type":{"$ref":"#/components/schemas/WorkloadType","description":"Workload type (container, function, static-site, etc.)"}}},"WorkloadId":{"type":"string","description":"Unique identifier for a workload in the source system"},"WorkloadStatus":{"type":"string","description":"Workload status in source system","enum":["running","paused","stopped","exited","failed","deployed","building","unknown"]},"WorkloadType":{"type":"string","description":"Workload type","enum":["container","function","static-site","server-side-app","worker","database","message-queue","cache","cron-job","other"]},"WriteFileBody":{"type":"object","required":["path","contents_b64"],"properties":{"contents_b64":{"type":"string","description":"File contents, base64-encoded. Required — lets callers ship binary\ndata over JSON without charset games."},"mode":{"type":["integer","null"],"format":"int32","description":"Unix permission mask (e.g. 0o644). Defaults to 0o644 when absent.","minimum":0},"path":{"type":"string","description":"Absolute path inside the sandbox. Must start with `/`."}},"additionalProperties":false},"WriteFilesBody":{"type":"object","required":["files"],"properties":{"files":{"type":"array","items":{"$ref":"#/components/schemas/WriteFileBody"},"description":"List of files to write. Each entry must include an absolute\n`path` and base64-encoded `contents_b64`. Empty list is a no-op."}},"additionalProperties":false},"WriteFilesResponse":{"type":"object","required":["written"],"properties":{"written":{"type":"integer","description":"Number of files successfully written before the first failure\n(if any). On full success this equals `files.len()`.","minimum":0}}},"ZoneListResponse":{"type":"object","description":"Zone list response","required":["zones"],"properties":{"zones":{"type":"array","items":{"$ref":"#/components/schemas/DnsZone"}}}}},"securitySchemes":{"bearer_auth":{"type":"http","scheme":"bearer","description":"Bearer token authentication. Use format: `Bearer `. Supports API keys (starting with `tk_`), CLI tokens, and session tokens."}}},"tags":[{"name":"Events","description":"Analytics events tracking endpoints"},{"name":"Metrics","description":"Analytics metrics collection endpoints including performance web vitals"},{"name":"Funnels","description":"Funnel management endpoints"},{"name":"Analytics","description":"Analytics and session replay management"},{"name":"Performance","description":"Performance metrics management"},{"name":"geo","description":"Geolocation API endpoints"},{"name":"Platform","description":"Platform information and compatibility"},{"name":"Teams","description":"Teams and project-scoped access"},{"name":"Git Providers","description":"Git provider management endpoints"},{"name":"Repositories","description":"Repository management endpoints"},{"name":"Public Repositories","description":"Endpoints for accessing public repositories without authentication. Supports GitHub and GitLab."},{"name":"Notification Providers","description":"Notification provider management endpoints"},{"name":"Notification Preferences","description":"User notification preferences and settings"},{"name":"DNS Providers","description":"DNS provider management endpoints"},{"name":"Internal DNS","description":"Per-node DNS resolver sync (ADR-011)"},{"name":"Domains","description":"Domain management endpoints"},{"name":"Email Providers","description":"Email provider management endpoints"},{"name":"Email Domains","description":"Email domain management and verification"},{"name":"Emails","description":"Email sending and retrieval"},{"name":"Email Tracking","description":"Email open and click tracking"},{"name":"Email Validation","description":"Email address validation and verification"},{"name":"Webhooks","description":"Webhook management endpoints"},{"name":"Webhook Deliveries","description":"Webhook delivery history and retry endpoints"},{"name":"External Services","description":"External service integration endpoints"},{"name":"External Services - Query","description":"Data querying and exploration endpoints"},{"name":"Metrics","description":"Time-series metrics and alert rule endpoints"},{"name":"KV Store","description":"Key-Value storage operations"},{"name":"KV Management","description":"KV service management operations"},{"name":"Blob","description":"Blob storage operations"},{"name":"Blob Management","description":"Blob service management operations"},{"name":"Feature Flags","description":"Runtime configuration that changes without a redeploy"},{"name":"Environments","description":"Environment management operations"},{"name":"Secrets","description":"File-mounted secrets (/run/secrets/)"},{"name":"Projects","description":"Project management endpoints"},{"name":"Presets","description":"Available deployment presets"},{"name":"Templates","description":"Project template endpoints"},{"name":"Custom Domains","description":"Custom domain management for projects"},{"name":"error-tracking","description":"Error tracking data fetching endpoints"},{"name":"Vulnerability Scans","description":"Vulnerability scan management endpoints"},{"name":"Agents","description":"Autonomous AI agents, autofixer (interactive AI debugging), skills/MCP definitions, and preview gateway management."},{"name":"Crons","description":"Cron jobs management API"},{"name":"Sandboxes","description":"Standalone sandbox API (`/v1/sandboxes/*`) for running isolated containers."},{"name":"Logs","description":"Log search, context, live tail, and retention management"},{"name":"Imports","description":"Import workloads from external sources"},{"name":"Status Page","description":"Status page and monitoring endpoints"},{"name":"OTel Ingest","description":"OTLP/HTTP ingest endpoints (protobuf)"},{"name":"OTel","description":"Query endpoints for the monitoring UI"},{"name":"GenAI","description":"GenAI agent activity tracing endpoints"},{"name":"Alarms","description":"Unified alarm history — list, summarise, acknowledge, resolve"},{"name":"Authentication","description":"Authentication and authorization endpoints"},{"name":"Users","description":"User management endpoints"},{"name":"Backups","description":"Backup management endpoints"},{"name":"Restore","description":"External service restore operations"},{"name":"Revenue","description":"Per-project revenue tracking integrations and analytics"},{"name":"Observability","description":"Unified observability event stream — runtime logs, requests, spans, errors, revenue"},{"name":"AI Gateway","description":"OpenAI-compatible chat, embeddings, and model endpoints"},{"name":"AI Gateway Admin","description":"Provider key management endpoints"},{"name":"AI Gateway Usage","description":"Usage analytics and reporting endpoints"},{"name":"AI Gateway Pricing","description":"Model pricing endpoints"},{"name":"API Keys","description":"API key management endpoints"},{"name":"Load Balancer","description":"Load balancer management endpoints"},{"name":"IP Access Control","description":"IP access control management endpoints"},{"name":"Files","description":"Static file serving endpoints"},{"name":"External Plugins","description":"External plugin management and discovery"}]} diff --git a/apps/temps-cli/src/api/index.ts b/apps/temps-cli/src/api/index.ts index f4db984ac..0aff502d9 100644 --- a/apps/temps-cli/src/api/index.ts +++ b/apps/temps-cli/src/api/index.ts @@ -1,4 +1,4 @@ // This file is auto-generated by @hey-api/openapi-ts -export { acknowledgeAlarm, activateAiProvider, activateApiKey, activateConnection, activateProvider, addClusterMember, addContext, addEnvironmentDomain, addEvents, addManagedDomain, addSessionReplayEvents, addTeamMember, adminDrainNode, adminDrainStatus, adminGetNode, adminListNodeContainers, adminListNodes, adminRemoveNode, adminUndrainNode, applyHostnameMode, archiveConversation, archiveFlag, assignRole, attachScheduleServices, blobCopy, blobDelete, blobDisable, blobDownload, blobEnable, blobHead, blobList, blobPut, blobStatus, blobUpdate, cancel, cancelBackup, cancelDeployment, cancelDomainOrder, cancelPgUpgrade, cancelRun, cancelScheduleRun, changePasswordSelf, changeProjectSource, chatCompletions, checkAnalyticsHasEvents, checkCommitExists, checkDomainStatus, checkExplorerSupport, checkIpBlocked, checkProviderDeletionSafety, chunkUploadOptions, cleanupExpiredBackups, clearPreviewPassword, cliDeviceApprove, cliDeviceDeny, cliDeviceLookup, cliDevicePoll, cliDeviceStart, cliLogout, cmd, cmdKill, cmdLogs, confirmPendingAction, containerMetricsGetHistory, createAgent, createAlert, createAlertRule, createApiKey, createBackupSchedule, createBitbucketProvider, createCloudflareProvider, createConversation, createCustomDomain, createDashboard, createDeploymentToken, createDnsProvider, createDomain, createDsn, createEmailDomain, createEmailProvider, createEnvironment, createEnvironmentVariable, createFlag, createFunnel, createGenericProvider, createGiteaPatProvider, createGithubPatProvider, createGitlabOauthProvider, createGitlabPatProvider, createGitProvider, createGlobalMcp, createGlobalSkill, createIncident, createIpAccessControl, createMcp, createMonitor, createNotificationEmailProvider, createNotificationProvider, createOidcProvider, createOidcRoleMapping, createOrRecreateOrder, createPlan, createPr, createProject, createProjectFromTemplate, createProjectRelease, createProjectSecret, createProviderKey, createRelease, createRoute, createS3Source, createSandbox, createService, createSkill, createSlackProvider, createTeam, createUser, createWebhook, createWebhookProvider, deactivateApiKey, deactivateConnection, deactivateProvider, deleteAgent, deleteAlert, deleteAlertRule, deleteApiKey, deleteBackup, deleteBackupSchedule, deleteConnection, deleteCustomDomain, deleteDashboard, deleteDeploymentToken, deleteDnsProvider, deleteDomain, deleteEmailDomain, deleteEmailProvider, deleteEnvironment, deleteEnvironmentDomain, deleteEnvironmentVariable, deleteExternalImage, deleteFunnel, deleteGitProvider, deleteGlobalMcp, deleteGlobalSkill, deleteIpAccessControl, deleteMcp, deleteMonitor, deleteNotificationProvider, deleteOidcProvider, deleteOidcRoleMapping, deletePreferences, deleteProject, deleteProjectSecret, deleteProviderKey, deleteProviderSafely, deleteReleaseSourceFiles, deleteReleaseSourceMaps, deleteRoute, deleteS3Source, deleteScan, deleteSecret, deleteService, deleteSessionReplay, deleteSkill, deleteSourceMap, deleteStaticBundle, deleteTeam, deleteUser, deleteWebhook, deployFromImage, deployFromImageUpload, deployFromStatic, deployFromUploadedSource, deploymentMetricsGetLatest, deploymentMetricsGetRange, deploymentMetricsToggle, destroySandbox, detachScheduleService, detectPublicPresets, disableBackupSchedule, disableMfa, discoverWorkloads, domain, downloadGlobalSkillArchive, downloadObject, downloadSkillArchive, emailStatus, embeddings, enableBackupSchedule, enrichVisitor, exec, execDetached, executeDeploymentOperation, executeImport, extendTimeout, externalServiceEnablePgStatStatements, externalServiceMetricsByDatabase, externalServiceMetricsCreateAlertRule, externalServiceMetricsDeleteAlertRule, externalServiceMetricsGetAlertRules, externalServiceMetricsGetLatest, externalServiceMetricsGetRange, externalServiceMetricsStatus, externalServiceMetricsToggle, externalServiceMetricsUpdateAlertRule, externalServiceResetPgStatStatements, finalizeOrder, finalizeProjectRelease, findConversation, generateJoinToken, generatePresetDockerfile, getAccessInfo, getActiveVisitors, getActivityGraph, getAdminGate, getAgent, getAggregatedBuckets, getAiAgentBreakdown, getAiAgentPages, getAiAgentTimeline, getAiPageBreakdown, getAiStatusBreakdown, getAlert, getAlertRule, getAllRepositoriesByName, getAnalyticsActiveVisitors, getAnalyticsEventsCount, getAnalyticsSessionEvents, getAnalyticsVisitorSessions, getApiKey, getApiKeyPermissions, getAuditLog, getBackup, getBackupSchedule, getBranchesByRepositoryId, getBucketedIncidents, getBucketedStatus, getChallengeToken, getChatReadiness, getCliStatus, getClusterHealth, getClusterMember, getCmd, getContainerDetail, getContainerEnvironmentVariable, getContainerInfo, getContainerLogs, getContainerLogsById, getContainerMetrics, getConversation, getConversationDetail, getConversations, getCronById, getCronExecutions, getCrossProjectTraceSiblings, getCurrentMonitorStatus, getCurrentUser, getCustomDomain, getDashboard, getDashboardProjectsAnalytics, getDelivery, getDeployment, getDeploymentContainerLogContent, getDeploymentJobLogs, getDeploymentJobs, getDeploymentOperations, getDeploymentOperationStatus, getDeploymentToken, getDiskStatus, getDnsChanges, getDnsProvider, getDomain, getDomainByHost, getDomainById, getDomainByName, getDomainDnsRecords, getDomainOrder, getEmail, getEmailEvents, getEmailLinks, getEmailProvider, getEmailStats, getEmailTracking, getEmailTrackingStatus, getEntityInfo, getEnvironment, getEnvironmentCrons, getEnvironmentDomains, getEnvironments, getEnvironmentVariables, getEnvironmentVariableValue, getErrorDashboardStats, getErrorEvent, getErrorGroup, getErrorStats, getErrorTimeSeries, getEventDetail, getEventEntries, getEventsCount, getEventsTimeline, getEventTypeBreakdown, getEventVisitors, getExternalImage, getFile, getFlag, getFlagSnapshot, getFunnelMetrics, getGenaiTrace, getGeneralStats, getGitProvider, getGlobalEvents, getGlobalEventStats, getGlobalMcp, getGlobalSandboxStatus, getGlobalSkill, getGroupedPageMetrics, getHealth, getHourlyVisits, getHttpChallengeDebug, getImportStatus, getIncident, getIncidentUpdates, getIpAccessControl, getIpGeolocation, getJoinTokenStatus, getLastDeployment, getLatestScan, getLatestScansPerEnvironment, getLiveVisitorsList, getLogContext, getMcp, getMetricsOverTime, getMonitor, getNotificationProvider, getOnDemandCertStatus, getOrCreateDsn, getPageFlow, getPageHourlySessions, getPagePathDetail, getPagePaths, getPagePathsSparklines, getPagePathVisitors, getPendingAction, getPerformanceMetrics, getPgUpgrade, getPgUpgradeLogs, getPipelineStats, getPlatformInfo, getPostgresWalHealth, getPreferences, getPreviewGatewayLogs, getPreviewGatewaySettings, getPreviewGatewayStatus, getPricing, getPrivateIp, getProject, getProjectAlarmsSummary, getProjectBySlug, getProjectDeployments, getProjects, getProjectServiceEnvironmentVariables, getProjectSessionReplays, getProjectsHealth, getProjectsMonitorHealth, getProjectStatistics, getProjectTemplate, getPropertyBreakdown, getPropertyTimeline, getProviderConnections, getProviderMetadata, getProvidersMetadata, getProxyLogById, getProxyLogByRequestId, getProxyLogs, getPublicBranches, getPublicIp, getPublicRepository, getQuota, getRecentActivity, getRemoteExternalImage, getRepositoryBranches, getRepositoryById, getRepositoryByName, getRepositoryPresetByName, getRepositoryPresetLive, getRepositoryTags, getResolvedEnvironmentVariables, getResolvedEnvironmentVariableValue, getRestoreCapabilities, getRestoreRun, getRoute, getRun, getRunWithLogs, getS3Credentials, getS3Source, getSandbox, getSandboxStatus, getScan, getScanByDeployment, getScanVulnerabilities, getService, getServiceBySlug, getServiceEnvironmentVariable, getServiceEnvironmentVariables, getServiceHealthStatus, getServicePreviewEnvironmentVariableNames, getServicePreviewEnvironmentVariablesMasked, getServiceRuntime, getServiceStats, getServiceTypeParameters, getServiceTypes, getSessionDetails, getSessionEvents, getSessionLogs, getSessionReplay, getSessionReplayEvents, getSettings, getSkill, getSlowQueries, getStaticBundle, getStatusOverview, getTagsByRepositoryId, getTeam, getTimeBucketStats, getTodayStats, getTrace, getUnifiedTrace, getUniqueCounts, getUniqueEvents, getUpdateStatus, getUptimeHistory, getUsageByProvider, getUsageRecent, getUsageSummary, getUsageTimeseries, getUsageTopModels, getVisitorByGuid, getVisitorById, getVisitorDetails, getVisitorFacets, getVisitorInfo, getVisitorJourney, getVisitors, getVisitorSessions, getVisitorStats, getWebhook, grantProjectAccess, handleGitProviderOauthCallback, hasAnalyticsEvents, hasErrorGroups, hasPerformanceMetrics, importExternalService, ingestLogs, ingestLogsByPath, ingestMetrics, ingestMetricsByPath, ingestSentryEnvelope, ingestSentryEvent, ingestTraces, ingestTracesByPath, initSessionReplay, inspectDropArchive, jobLogs, jobStatus, killJob, kvDel, kvDisable, kvEnable, kvExpire, kvGet, kvIncr, kvKeys, kvSet, kvStatus, kvTtl, kvUpdate, latestRunForSource, linkCustomDomainToCertificate, linkServiceToProject, listAgentRuns, listAgents, listAiProviders, listAlertRules, listAlerts, listAllConversations, listAllRuns, listApiKeys, listAuditLogs, listAvailableContainers, listBackupAlerts, listBackupChildren, listBackupSchedules, listBackupsForSchedule, listCommitsByRepositoryId, listConnections, listContainers, listContainersAtPath, listConversations, listCustomDomainsForProject, listDashboards, listDeliveries, listDeploymentContainerLogs, listDeploymentTokens, listDnsProviders, listDomains, listDsns, listEmailDomains, listEmailProviders, listEmails, listEnrollmentTokens, listEntities, listErrorEvents, listErrorGroups, listEvents, listEventTypes, listExternalImages, listExternalPlugins, listExternalServiceBackups, listFlags, listFunnels, listGitProviders, listGlobalMcps, listGlobalSkills, listIncidents, listInsights, listIpAccessControl, listJobs, listKnownAiAgents, listManagedDomains, listMcps, listMetricLabelKeys, listMetricLabelValues, listMetricNames, listModels, listMonitors, listNotificationProviders, listOidcProviders, listOidcProviderUsers, listOidcRoleMappings, listOnDemandCerts, listOrders, listPeers, listPendingActions, listPgUpgrades, listPresets, listProjectAccess, listProjectAlarms, listProjectScans, listProjectSecrets, listProjectServices, listProjectTemplates, listProjectTemplateTags, listProviderKeys, listProviderZones, listPublicProviders, listReleaseFiles, listReleases, listRemoteExternalImages, listRepositoriesByConnection, listRepositoriesByProvider, listRestoreRunsForService, listRootContainers, listRoutes, listS3Sources, listSandboxes, listScheduleRunJobs, listScheduleRuns, listScheduleServices, listSecrets, listServiceHealthStatuses, listServiceProjects, listServices, listServiceSchedules, listSkills, listSourceBackups, listSourceFiles, listSourceMaps, listSources, listStaticBundles, listSyncedRepositories, listTeamMembers, listTeamProjects, listTeams, listUsers, listWebhooks, login, logout, lookupDnsARecords, mintEnrollmentToken, mkdir, nodeHeartbeat, nodeMetricsGetRange, observabilityFullEvent, observabilityListEvents, oidcCallback, type Options, patchAdminGate, patchPreviewGatewaySettings, pauseDeployment, pauseSandbox, planRestore, postDnsAck, previewAlert, previewFunnelMetrics, previewHostnameMode, promoteClusterMember, promoteDeployment, provisionDomain, purgeProjectLogs, pushExternalImage, queryData, queryGenaiTraces, queryLogs, queryMetrics, queryTraces, queryTraceSummaries, readFile, reAnalyze, rebuildSandboxImage, recordConsoleEvent, recordEventMetrics, recordFlagExposure, recordSpeedMetrics, refreshRouteTable, regenerateDsn, registerExternalImage, registerNode, reinstallGitlabWebhook, rejectPendingAction, reloadPlugins, removeClusterMember, removeManagedDomain, removeRole, removeTeamMember, renameConversation, renewDomain, requestPasswordReset, resetPassword, resizeSandbox, resolveAlarm, restartContainer, restartPreviewGateway, restartSandbox, restoreFlag, restoreUser, resumeDeployment, resumeSandbox, retryCluster, retryDelivery, retryPgUpgrade, retryRun, revealGlobalMcpConfig, revealMcpConfig, revealNotificationProviderConfig, revealServiceParameter, revenueCreateIntegration, revenueDeleteIntegration, revenueGlobalEvents, revenueImportInvoicesCsv, revenueImportSubscriptionsCsv, revenueListIntegrations, revenueListProviders, revenueMetricsCustomers, revenueMetricsGlobalMrr, revenueMetricsGlobalSummary, revenueMetricsMrr, revenueMetricsSummary, revenueRecentEvents, revenueRotateToken, revenueUpdateConfig, revenueUpdateSecret, revokeDsn, revokeEnrollmentToken, revokeJoinToken, revokeProjectAccess, rollbackPgUpgrade, rollbackToDeployment, rootfsGc, rootfsReport, rotateApiKey, rotateDeploymentToken, runBackupForSource, runConnectionHealthCheck, runExternalServiceBackup, runScheduleNow, sandboxCreatePreviewLink, saveAgentToken, saveAiProviderCredential, searchLogs, sendEmail, sendMessage, setDefaultS3Source, setFlagEnvironment, setPreviewPassword, setupDns, setupDnsChallenge, setupEmailTracking, setupMfa, sleepEnvironment, smokeTestAgent, sourceSandbox, startAnalysis, startContainer, startFix, startGitProviderOauth, startOidcLoginBySlug, startPgUpgrade, startRestore, startService, statPath, stopContainer, stopSandbox, stopService, streamContainerMetrics, streamEvents, streamRunEvents, syncRepositories, tailDeploymentJobLogs, tailLogs, teardownDeployment, teardownEnvironment, testNotificationProvider, testOidcProvider, testProvider, testProviderConnection, testProviderKeyById, testProviderKeyInline, testS3ConnectionPreview, testS3SourceConnection, trackClick, trackOpen, triggerAgent, triggerProjectPipeline, triggerScan, triggerServiceHealthCheck, triggerWeeklyDigest, unlinkServiceFromProject, updateAgent, updateAiProvider, updateAlert, updateAlertRule, updateApiKey, updateAutomaticDeploy, updateBackupSchedule, updateCloudflareProvider, updateConnectionToken, updateCustomDomain, updateDashboard, updateDeploymentToken, updateEmailProvider, updateEnvironmentSettings, updateEnvironmentSubdomain, updateEnvironmentVariable, updateErrorGroup, updateFlag, updateFunnel, updateGitProviderCredentials, updateGitSettings, updateGlobalMcp, updateGlobalSkill, updateIncidentStatus, updateIpAccessControl, updateManagedDomain, updateMcp, updateNotificationEmailProvider, updateNotificationProvider, updateOidcProvider, updatePreferences, updateProject, updateProjectDeploymentConfig, updateProjectSecret, updateProjectSettings, updateProvider, updateProviderKey, updateRoute, updateS3Source, updateSelf, updateService, updateServiceResources, updateSessionDuration, updateSettings, updateSkill, updateSlackProvider, updateSpeedMetrics, updateTeam, updateTeamMemberRole, updateUser, updateWebhook, updateWebhookProvider, upgradePreviewGateway, upgradeService, uploadGlobalSkill, uploadReleaseFile, uploadSkill, uploadSourceFile, uploadSourceMap, uploadStaticBundle, upsertSecret, validateConnection, validateEmail, verifyAndEnableMfa, verifyDomain, verifyEmail, verifyManagedDomain, verifyMfaChallenge, verifyStepUp, wakeEnvironment, webhookTrigger, workflowDryRun, writeFile, writeFiles } from './sdk.gen'; -export type { AcknowledgeAlarmData, AcknowledgeAlarmErrors, AcknowledgeAlarmResponses, AcmeOrderResponse, ActivateAiProviderData, ActivateAiProviderErrors, ActivateAiProviderResponse, ActivateAiProviderResponses, ActivateApiKeyData, ActivateApiKeyErrors, ActivateApiKeyResponse, ActivateApiKeyResponses, ActivateConnectionData, ActivateConnectionErrors, ActivateConnectionResponses, ActivateProviderData, ActivateProviderErrors, ActivateProviderResponse, ActivateProviderResponses, ActiveVisitor, ActiveVisitorsQuery, ActiveVisitorsResponse, ActivityDay, ActivityEvent, ActivityGraphQuery, ActivityGraphResponse, AddClusterMemberData, AddClusterMemberErrors, AddClusterMemberRequest, AddClusterMemberResponse, AddClusterMemberResponses, AddContextData, AddContextErrors, AddContextRequest, AddContextResponses, AddEnvironmentDomainData, AddEnvironmentDomainErrors, AddEnvironmentDomainRequest, AddEnvironmentDomainResponse, AddEnvironmentDomainResponses, AddEventsData, AddEventsError, AddEventsErrors, AddEventsRequest, AddEventsResponse, AddEventsResponse2, AddEventsResponses, AddManagedDomainApiRequest, AddManagedDomainData, AddManagedDomainErrors, AddManagedDomainResponse, AddManagedDomainResponses, AddSessionReplayEventsData, AddSessionReplayEventsError, AddSessionReplayEventsErrors, AddSessionReplayEventsResponse, AddSessionReplayEventsResponses, AddTeamMemberData, AddTeamMemberErrors, AddTeamMemberResponse, AddTeamMemberResponses, AdminDrainNodeData, AdminDrainNodeErrors, AdminDrainNodeResponse, AdminDrainNodeResponses, AdminDrainStatusData, AdminDrainStatusErrors, AdminDrainStatusResponse, AdminDrainStatusResponses, AdminGateResponse, AdminGateSource, AdminGetNodeData, AdminGetNodeErrors, AdminGetNodeResponse, AdminGetNodeResponses, AdminListNodeContainersData, AdminListNodeContainersErrors, AdminListNodeContainersResponse, AdminListNodeContainersResponses, AdminListNodesData, AdminListNodesErrors, AdminListNodesResponse, AdminListNodesResponses, AdminRemoveNodeData, AdminRemoveNodeErrors, AdminRemoveNodeResponse, AdminRemoveNodeResponses, AdminUndrainNodeData, AdminUndrainNodeErrors, AdminUndrainNodeResponse, AdminUndrainNodeResponses, AgentConfigResponse, AgentRunLogResponse, AgentRunResponse, AgentRunWithLogsResponse, AgentSandboxSettings, AgentSandboxSettingsMasked, AggregatedBucketItem, AggregatedBucketsQuery, AggregatedBucketsResponse, AggregationLevel, AggregationTemporality, AiAgentBreakdownResponse, AiAgentBreakdownRow, AiAgentDescriptor, AiAgentPageRow, AiAgentPagesResponse, AiAgentTimelineResponse, AiAgentTimelineRow, AiChatLimitsSettings, AiConfigSettings, AiPageBreakdownResponse, AiPageBreakdownRow, AiStatusBreakdownResponse, AiStatusBreakdownRow, AlarmListResponse, AlarmResponse, AlarmSummaryResponse, AlertRuleResponse, AllocEntry, AnalyticsSessionEventsResponse, AnnotatedSpan, AnomalyAlgorithm, AnomalyParams, AnomalyPreviewPointResponse, AnomalyPreviewRequest, AnomalyPreviewResponse, ApiKeyListResponse, ApiKeyResponse, ApplyHostnameModeData, ApplyHostnameModeErrors, ApplyHostnameModeRequest, ApplyHostnameModeResponse, ApplyHostnameModeResponses, AppSettings, AppSettingsResponse, ArchiveConversationData, ArchiveConversationErrors, ArchiveConversationResponse, ArchiveConversationResponses, ArchiveFlagData, ArchiveFlagErrors, ArchiveFlagResponse, ArchiveFlagResponse2, ArchiveFlagResponses, ArchiveMode, AssignRoleData, AssignRoleErrors, AssignRoleRequest, AssignRoleResponses, AttachScheduleServicesData, AttachScheduleServicesError, AttachScheduleServicesErrors, AttachScheduleServicesRequest, AttachScheduleServicesResponse, AttachScheduleServicesResponse2, AttachScheduleServicesResponses, AuditLogIpInfo, AuditLogResponse, AuditLogUserInfo, AuthFlavorDto, AuthResponse, AuthStatusResponse, AuthTokenResponse, AutofixerRunResponse, AutofixerRunWithLogsResponse, AutofixRunConfig, AutoWatchParams, AvailableContainerInfo, AvailablePermissions, BackupAlertListResponse, BackupAlertResponse, BackupResponse, BackupScheduleResponse, BitbucketAuthInput, BlobCopyData, BlobCopyError, BlobCopyErrors, BlobCopyResponse, BlobCopyResponses, BlobDeleteData, BlobDeleteError, BlobDeleteErrors, BlobDeleteResponse, BlobDeleteResponses, BlobDisableData, BlobDisableErrors, BlobDisableResponse, BlobDisableResponses, BlobDownloadData, BlobDownloadError, BlobDownloadErrors, BlobDownloadResponses, BlobEnableData, BlobEnableErrors, BlobEnableResponse, BlobEnableResponses, BlobHeadData, BlobHeadError, BlobHeadErrors, BlobHeadResponses, BlobListData, BlobListError, BlobListErrors, BlobListResponse, BlobListResponses, BlobPutData, BlobPutError, BlobPutErrors, BlobPutResponse, BlobPutResponses, BlobResponse, BlobStatusData, BlobStatusErrors, BlobStatusResponse, BlobStatusResponse2, BlobStatusResponses, BlobUpdateData, BlobUpdateErrors, BlobUpdateResponse, BlobUpdateResponses, BranchInfo, BranchListResponse, BrowserCount, BrowsersQuery, BuildConfiguration, BuildLimitsSettings, CancelBackupData, CancelBackupError, CancelBackupErrors, CancelBackupResponse, CancelBackupResponse2, CancelBackupResponses, CancelData, CancelDeploymentData, CancelDeploymentErrors, CancelDeploymentResponse, CancelDeploymentResponses, CancelDomainOrderData, CancelDomainOrderErrors, CancelDomainOrderResponse, CancelDomainOrderResponses, CancelErrors, CancelPgUpgradeData, CancelPgUpgradeErrors, CancelPgUpgradeResponse, CancelPgUpgradeResponses, CancelResponses, CancelRunData, CancelRunErrors, CancelRunResponse, CancelRunResponses, CancelScheduleRunData, CancelScheduleRunError, CancelScheduleRunErrors, CancelScheduleRunResponse, CancelScheduleRunResponses, CertStatusResponse, ChallengeConfig, ChallengeError, ChallengeValidationStatus, ChangePasswordRequest, ChangePasswordSelfData, ChangePasswordSelfErrors, ChangePasswordSelfResponse, ChangePasswordSelfResponses, ChangeProjectSourceData, ChangeProjectSourceErrors, ChangeProjectSourceRequest, ChangeProjectSourceResponse, ChangeProjectSourceResponses, ChatCompletionChoice, ChatCompletionRequest, ChatCompletionResponse, ChatCompletionsData, ChatCompletionsError, ChatCompletionsErrors, ChatCompletionsResponse, ChatCompletionsResponses, ChatMessage, ChatReadinessResponse, CheckAnalyticsHasEventsData, CheckAnalyticsHasEventsErrors, CheckAnalyticsHasEventsResponse, CheckAnalyticsHasEventsResponses, CheckCommitExistsData, CheckCommitExistsErrors, CheckCommitExistsResponse, CheckCommitExistsResponses, CheckDomainStatusData, CheckDomainStatusErrors, CheckDomainStatusResponse, CheckDomainStatusResponses, CheckExplorerSupportData, CheckExplorerSupportErrors, CheckExplorerSupportResponse, CheckExplorerSupportResponses, CheckIpBlockedData, CheckIpBlockedError, CheckIpBlockedErrors, CheckIpBlockedResponses, CheckProviderDeletionSafetyData, CheckProviderDeletionSafetyErrors, CheckProviderDeletionSafetyResponse, CheckProviderDeletionSafetyResponses, ChildBackupEntryResponse, ChildBackupListResponse, ChunkUploadOptionsData, ChunkUploadOptionsResponse, ChunkUploadOptionsResponses, CleanupExpiredBackupsData, CleanupExpiredBackupsError, CleanupExpiredBackupsErrors, CleanupExpiredBackupsRequest, CleanupExpiredBackupsResponse, CleanupExpiredBackupsResponses, ClearPreviewPasswordData, ClearPreviewPasswordErrors, ClearPreviewPasswordResponse, ClearPreviewPasswordResponses, CliDeviceApproveData, CliDeviceApproveErrors, CliDeviceApproveRequest, CliDeviceApproveResponse, CliDeviceApproveResponse2, CliDeviceApproveResponses, CliDeviceDenyData, CliDeviceDenyErrors, CliDeviceDenyResponse, CliDeviceDenyResponses, CliDeviceLookupData, CliDeviceLookupErrors, CliDeviceLookupResponse, CliDeviceLookupResponse2, CliDeviceLookupResponses, CliDevicePollData, CliDevicePollErrors, CliDevicePollRequest, CliDevicePollResponse, CliDevicePollResponse2, CliDevicePollResponses, CliDeviceStartData, CliDeviceStartErrors, CliDeviceStartRequest, CliDeviceStartResponse, CliDeviceStartResponse2, CliDeviceStartResponses, ClientOptions, CliLoginRequest, CliLogoutData, CliLogoutErrors, CliLogoutResponse, CliLogoutResponses, CloudflareConfig, CloudProvider, ClusterCapacity, ClusterDnsSettings, ClusterHealthReportResponse, ClusterMemberHealthResponse, ClusterMemberRequest, CmdBody, CmdData, CmdErrors, CmdInner, CmdKillBody, CmdKillData, CmdKillErrors, CmdKillResponse, CmdKillResponses, CmdLogsData, CmdLogsErrors, CmdLogsResponses, CmdResponse, CmdResponse2, CmdResponses, CommitExistsResponse, CommitInfo, CommitListResponse, Comparator, ComposePublicPort, ConfirmPendingActionData, ConfirmPendingActionErrors, ConfirmPendingActionResponse, ConfirmPendingActionResponses, ConnectionListQuery, ConnectionListResponse, ConnectionResponse, ConnectionTestResult, ConsoleEventPayload, ContainerActionResponse, ContainerDetailResponse, ContainerEnvironmentVariableValueResponse, ContainerInfoResponse, ContainerInventoryItem, ContainerListResponse, ContainerLogSettings, ContainerLogsQuery, ContainerMetricHistoryPoint, ContainerMetricsGetHistoryData, ContainerMetricsGetHistoryErrors, ContainerMetricsGetHistoryResponse, ContainerMetricsGetHistoryResponses, ContainerMetricsHistoryQuery, ContainerMetricsResponse, ContainerResponse, ContainerRuntimeInfo, ContainerStatsSample, ContentPart, ContextLine, ContextLogsRequest, ContextLogsResponse, ConversationDetailResponse, ConversationResponse, ConversationsQueryParams, ConversationSummary, CopyBlobRequest, CostAnalysis, CreateAgentData, CreateAgentErrors, CreateAgentResponse, CreateAgentResponses, CreateAlertData, CreateAlertError, CreateAlertErrors, CreateAlertResponse, CreateAlertResponses, CreateAlertRuleData, CreateAlertRuleErrors, CreateAlertRuleRequest, CreateAlertRuleResponse, CreateAlertRuleResponses, CreateApiKeyData, CreateApiKeyErrors, CreateApiKeyRequest, CreateApiKeyResponse, CreateApiKeyResponse2, CreateApiKeyResponses, CreateBackupScheduleData, CreateBackupScheduleError, CreateBackupScheduleErrors, CreateBackupScheduleRequest, CreateBackupScheduleResponse, CreateBackupScheduleResponses, CreateBitbucketProviderData, CreateBitbucketProviderErrors, CreateBitbucketProviderResponse, CreateBitbucketProviderResponses, CreateBitbucketRequest, CreateCloudflareProviderData, CreateCloudflareProviderErrors, CreateCloudflareProviderRequest, CreateCloudflareProviderResponse, CreateCloudflareProviderResponses, CreateConversationData, CreateConversationErrors, CreateConversationRequest, CreateConversationResponse, CreateConversationResponses, CreateCustomDomainData, CreateCustomDomainErrors, CreateCustomDomainResponse, CreateCustomDomainResponses, CreateDashboardData, CreateDashboardError, CreateDashboardErrors, CreateDashboardRequest, CreateDashboardResponse, CreateDashboardResponses, CreateDeploymentTokenData, CreateDeploymentTokenErrors, CreateDeploymentTokenRequest, CreateDeploymentTokenResponse, CreateDeploymentTokenResponse2, CreateDeploymentTokenResponses, CreateDnsProviderData, CreateDnsProviderErrors, CreateDnsProviderRequest, CreateDnsProviderResponse, CreateDnsProviderResponses, CreateDomainData, CreateDomainErrors, CreateDomainRequest, CreateDomainResponse, CreateDomainResponses, CreatedResource, CreateDsnData, CreateDsnErrors, CreateDsnRequest, CreateDsnResponse, CreateDsnResponses, CreateEmailDomainData, CreateEmailDomainErrors, CreateEmailDomainRequest, CreateEmailDomainResponse, CreateEmailDomainResponses, CreateEmailProviderData, CreateEmailProviderErrors, CreateEmailProviderRequest, CreateEmailProviderResponse, CreateEmailProviderResponses, CreateEnvironmentData, CreateEnvironmentErrors, CreateEnvironmentRequest, CreateEnvironmentResponse, CreateEnvironmentResponses, CreateEnvironmentVariableData, CreateEnvironmentVariableErrors, CreateEnvironmentVariableRequest, CreateEnvironmentVariableResponse, CreateEnvironmentVariableResponses, CreateExternalServiceRequest, CreateFlagData, CreateFlagErrors, CreateFlagRequest, CreateFlagResponse, CreateFlagResponses, CreateFunnelData, CreateFunnelErrors, CreateFunnelRequest, CreateFunnelResponse, CreateFunnelResponse2, CreateFunnelResponses, CreateFunnelStep, CreateGenericProviderData, CreateGenericProviderErrors, CreateGenericProviderResponse, CreateGenericProviderResponses, CreateGenericRequest, CreateGiteaPatProviderData, CreateGiteaPatProviderErrors, CreateGiteaPatProviderResponse, CreateGiteaPatProviderResponses, CreateGiteaPatRequest, CreateGithubPatProviderData, CreateGithubPatProviderErrors, CreateGithubPatProviderResponse, CreateGithubPatProviderResponses, CreateGitHubPatRequest, CreateGitlabOauthProviderData, CreateGitlabOauthProviderErrors, CreateGitlabOauthProviderResponse, CreateGitlabOauthProviderResponses, CreateGitLabOAuthRequest, CreateGitlabPatProviderData, CreateGitlabPatProviderErrors, CreateGitlabPatProviderResponse, CreateGitlabPatProviderResponses, CreateGitLabPatRequest, CreateGitProviderData, CreateGitProviderErrors, CreateGitProviderResponse, CreateGitProviderResponses, CreateGlobalMcpData, CreateGlobalMcpErrors, CreateGlobalMcpResponse, CreateGlobalMcpResponses, CreateGlobalSkillData, CreateGlobalSkillErrors, CreateGlobalSkillResponse, CreateGlobalSkillResponses, CreateIncidentData, CreateIncidentErrors, CreateIncidentRequest, CreateIncidentResponse, CreateIncidentResponses, CreateIntegrationBody, CreateIpAccessControlData, CreateIpAccessControlError, CreateIpAccessControlErrors, CreateIpAccessControlRequest, CreateIpAccessControlResponse, CreateIpAccessControlResponses, CreateMcpData, CreateMcpErrors, CreateMcpRequest, CreateMcpResponse, CreateMcpResponses, CreateMetricAlertRequest, CreateMonitorData, CreateMonitorErrors, CreateMonitorRequest, CreateMonitorResponse, CreateMonitorResponses, CreateNotificationEmailProviderData, CreateNotificationEmailProviderErrors, CreateNotificationEmailProviderRequest, CreateNotificationEmailProviderResponse, CreateNotificationEmailProviderResponses, CreateNotificationProviderData, CreateNotificationProviderErrors, CreateNotificationProviderResponse, CreateNotificationProviderResponses, CreateOidcProviderData, CreateOidcProviderErrors, CreateOidcProviderRequest, CreateOidcProviderResponse, CreateOidcProviderResponses, CreateOidcRoleMappingData, CreateOidcRoleMappingRequest, CreateOidcRoleMappingResponse, CreateOidcRoleMappingResponses, CreateOrRecreateOrderData, CreateOrRecreateOrderErrors, CreateOrRecreateOrderResponse, CreateOrRecreateOrderResponses, CreatePlanData, CreatePlanErrors, CreatePlanRequest, CreatePlanResponse, CreatePlanResponse2, CreatePlanResponses, CreatePrData, CreatePrErrors, CreateProjectAccessRequest, CreateProjectData, CreateProjectErrors, CreateProjectFromTemplateData, CreateProjectFromTemplateErrors, CreateProjectFromTemplateRequest, CreateProjectFromTemplateResponse, CreateProjectFromTemplateResponse2, CreateProjectFromTemplateResponses, CreateProjectReleaseData, CreateProjectReleaseErrors, CreateProjectReleaseResponse, CreateProjectReleaseResponses, CreateProjectRequest, CreateProjectResponse, CreateProjectResponses, CreateProjectSecretData, CreateProjectSecretErrors, CreateProjectSecretRequest, CreateProjectSecretResponse, CreateProjectSecretResponses, CreateProviderKeyData, CreateProviderKeyError, CreateProviderKeyErrors, CreateProviderKeyRequest, CreateProviderKeyResponse, CreateProviderKeyResponses, CreateProviderRequest, CreatePrResponse, CreatePrResponse2, CreatePrResponses, CreateReleaseData, CreateReleaseErrors, CreateReleaseResponse, CreateReleaseResponses, CreateRouteData, CreateRouteErrors, CreateRouteRequest, CreateRouteResponse, CreateRouteResponses, CreateS3SourceData, CreateS3SourceError, CreateS3SourceErrors, CreateS3SourceRequest, CreateS3SourceResponse, CreateS3SourceResponses, CreateSandboxBody, CreateSandboxData, CreateSandboxErrors, CreateSandboxResponse, CreateSandboxResponses, CreateServiceData, CreateServiceErrors, CreateServiceResponse, CreateServiceResponses, CreateSkillData, CreateSkillErrors, CreateSkillRequest, CreateSkillResponse, CreateSkillResponses, CreateSlackProviderData, CreateSlackProviderErrors, CreateSlackProviderRequest, CreateSlackProviderResponse, CreateSlackProviderResponses, CreateTeamData, CreateTeamErrors, CreateTeamMemberRequest, CreateTeamRequest, CreateTeamResponse, CreateTeamResponses, CreateUserData, CreateUserErrors, CreateUserRequest, CreateUserResponse, CreateUserResponses, CreateWebhookData, CreateWebhookErrors, CreateWebhookProviderData, CreateWebhookProviderErrors, CreateWebhookProviderRequest, CreateWebhookProviderResponse, CreateWebhookProviderResponses, CreateWebhookRequestBody, CreateWebhookResponse, CreateWebhookResponses, CronExecutionInfo, CronInfo, CrossProjectSiblingRef, CrossProjectTraceResponse, CurrentStatusResponse, CustomDomainRequest, CustomDomainResponse, CustomerMovementResponse, DashboardLayout, DashboardProjectsAnalyticsQuery, DashboardProjectsAnalyticsResponse, DashboardSection, DashboardTile, DatabaseMetricsResponse, DatabaseMetricsRow, DataImplication, DataImplicationSeverity, DeactivateApiKeyData, DeactivateApiKeyErrors, DeactivateApiKeyResponse, DeactivateApiKeyResponses, DeactivateConnectionData, DeactivateConnectionErrors, DeactivateConnectionResponses, DeactivateProviderData, DeactivateProviderErrors, DeactivateProviderResponses, DeleteAgentData, DeleteAgentErrors, DeleteAgentResponse, DeleteAgentResponses, DeleteAlertData, DeleteAlertError, DeleteAlertErrors, DeleteAlertResponse, DeleteAlertResponses, DeleteAlertRuleData, DeleteAlertRuleErrors, DeleteAlertRuleResponse, DeleteAlertRuleResponses, DeleteApiKeyData, DeleteApiKeyErrors, DeleteApiKeyResponse, DeleteApiKeyResponses, DeleteBackupData, DeleteBackupError, DeleteBackupErrors, DeleteBackupResponse, DeleteBackupResponses, DeleteBackupScheduleData, DeleteBackupScheduleError, DeleteBackupScheduleErrors, DeleteBackupScheduleResponse, DeleteBackupScheduleResponses, DeleteBlobRequest, DeleteBlobResponse, DeleteConnectionData, DeleteConnectionErrors, DeleteConnectionResponse, DeleteConnectionResponses, DeleteCustomDomainData, DeleteCustomDomainErrors, DeleteCustomDomainResponse, DeleteCustomDomainResponses, DeleteDashboardData, DeleteDashboardError, DeleteDashboardErrors, DeleteDashboardResponse, DeleteDashboardResponses, DeleteDeploymentTokenData, DeleteDeploymentTokenErrors, DeleteDeploymentTokenResponse, DeleteDeploymentTokenResponses, DeleteDnsProviderData, DeleteDnsProviderErrors, DeleteDnsProviderResponse, DeleteDnsProviderResponses, DeleteDomainData, DeleteDomainErrors, DeleteDomainResponse, DeleteDomainResponses, DeleteEmailDomainData, DeleteEmailDomainErrors, DeleteEmailDomainResponse, DeleteEmailDomainResponses, DeleteEmailProviderData, DeleteEmailProviderErrors, DeleteEmailProviderResponse, DeleteEmailProviderResponses, DeleteEnvironmentData, DeleteEnvironmentDomainData, DeleteEnvironmentDomainErrors, DeleteEnvironmentDomainResponse, DeleteEnvironmentDomainResponses, DeleteEnvironmentErrors, DeleteEnvironmentResponse, DeleteEnvironmentResponses, DeleteEnvironmentVariableData, DeleteEnvironmentVariableErrors, DeleteEnvironmentVariableResponse, DeleteEnvironmentVariableResponses, DeleteExternalImageData, DeleteExternalImageErrors, DeleteExternalImageResponse, DeleteExternalImageResponses, DeleteFunnelData, DeleteFunnelErrors, DeleteFunnelResponses, DeleteGitProviderData, DeleteGitProviderErrors, DeleteGitProviderResponse, DeleteGitProviderResponses, DeleteGlobalMcpData, DeleteGlobalMcpErrors, DeleteGlobalMcpResponse, DeleteGlobalMcpResponses, DeleteGlobalSkillData, DeleteGlobalSkillErrors, DeleteGlobalSkillResponse, DeleteGlobalSkillResponses, DeleteIpAccessControlData, DeleteIpAccessControlError, DeleteIpAccessControlErrors, DeleteIpAccessControlResponse, DeleteIpAccessControlResponses, DeleteMcpData, DeleteMcpErrors, DeleteMcpResponse, DeleteMcpResponses, DeleteMonitorData, DeleteMonitorErrors, DeleteMonitorResponse, DeleteMonitorResponses, DeleteNotificationProviderData, DeleteNotificationProviderErrors, DeleteNotificationProviderResponse, DeleteNotificationProviderResponses, DeleteOidcProviderData, DeleteOidcProviderResponse, DeleteOidcProviderResponses, DeleteOidcRoleMappingData, DeleteOidcRoleMappingResponse, DeleteOidcRoleMappingResponses, DeletePreferencesData, DeletePreferencesErrors, DeletePreferencesResponse, DeletePreferencesResponses, DeleteProjectData, DeleteProjectErrors, DeleteProjectResponse, DeleteProjectResponses, DeleteProjectSecretData, DeleteProjectSecretErrors, DeleteProjectSecretResponse, DeleteProjectSecretResponses, DeleteProviderKeyData, DeleteProviderKeyError, DeleteProviderKeyErrors, DeleteProviderKeyResponse, DeleteProviderKeyResponses, DeleteProviderSafelyData, DeleteProviderSafelyErrors, DeleteProviderSafelyResponse, DeleteProviderSafelyResponses, DeleteReleaseSourceFilesData, DeleteReleaseSourceFilesErrors, DeleteReleaseSourceFilesResponse, DeleteReleaseSourceFilesResponses, DeleteReleaseSourceMapsData, DeleteReleaseSourceMapsErrors, DeleteReleaseSourceMapsResponse, DeleteReleaseSourceMapsResponses, DeleteResponse, DeleteRouteData, DeleteRouteErrors, DeleteRouteResponse, DeleteRouteResponses, DeleteS3SourceData, DeleteS3SourceError, DeleteS3SourceErrors, DeleteS3SourceResponse, DeleteS3SourceResponses, DeleteScanData, DeleteScanError, DeleteScanErrors, DeleteScanResponse, DeleteScanResponses, DeleteSecretData, DeleteSecretErrors, DeleteSecretResponse, DeleteSecretResponses, DeleteServiceData, DeleteServiceErrors, DeleteServiceResponse, DeleteServiceResponses, DeleteSessionReplayData, DeleteSessionReplayError, DeleteSessionReplayErrors, DeleteSessionReplayResponses, DeleteSkillData, DeleteSkillErrors, DeleteSkillResponse, DeleteSkillResponses, DeleteSourceMapData, DeleteSourceMapErrors, DeleteSourceMapResponse, DeleteSourceMapResponses, DeleteStaticBundleData, DeleteStaticBundleErrors, DeleteStaticBundleResponse, DeleteStaticBundleResponses, DeleteTeamData, DeleteTeamErrors, DeleteTeamResponse, DeleteTeamResponses, DeleteUserData, DeleteUserErrors, DeleteUserResponse, DeleteUserResponses, DeleteWebhookData, DeleteWebhookErrors, DeleteWebhookResponse, DeleteWebhookResponses, DelRequest, DelResponse, DeployFromImageData, DeployFromImageErrors, DeployFromImageRequest, DeployFromImageResponse, DeployFromImageResponses, DeployFromImageUploadData, DeployFromImageUploadErrors, DeployFromImageUploadQuery, DeployFromImageUploadResponse, DeployFromImageUploadResponses, DeployFromStaticData, DeployFromStaticErrors, DeployFromStaticRequest, DeployFromStaticResponse, DeployFromStaticResponses, DeployFromUploadedSourceData, DeployFromUploadedSourceErrors, DeployFromUploadedSourceResponse, DeployFromUploadedSourceResponses, DeploymentConfig, DeploymentConfigSnapshot, DeploymentConfiguration, DeploymentContainerLogContentResponse, DeploymentContainerLogResponse, DeploymentContainerLogsListResponse, DeploymentEnvironmentResponse, DeploymentJobResponse, DeploymentJobsResponse, DeploymentListResponse, DeploymentMetadata, DeploymentMetricsGetLatestData, DeploymentMetricsGetLatestErrors, DeploymentMetricsGetLatestResponse, DeploymentMetricsGetLatestResponses, DeploymentMetricsGetRangeData, DeploymentMetricsGetRangeErrors, DeploymentMetricsGetRangeResponse, DeploymentMetricsGetRangeResponses, DeploymentMetricsToggleData, DeploymentMetricsToggleErrors, DeploymentMetricsToggleResponses, DeploymentResponse, DeploymentStateResponse, DeploymentStrategy, DeploymentTokenListResponse, DeploymentTokenResponse, DestroySandboxData, DestroySandboxErrors, DestroySandboxResponse, DestroySandboxResponses, DetachScheduleServiceData, DetachScheduleServiceError, DetachScheduleServiceErrors, DetachScheduleServiceResponse, DetachScheduleServiceResponses, DetectionConfig, DetectPublicPresetsData, DetectPublicPresetsErrors, DetectPublicPresetsResponse, DetectPublicPresetsResponses, DeviceCount, DigestSections, Direction, DisableBackupScheduleData, DisableBackupScheduleErrors, DisableBackupScheduleResponse, DisableBackupScheduleResponses, DisableBlobResponse, DisableKvResponse, DisableMfaData, DisableMfaErrors, DisableMfaRequest, DisableMfaResponse, DisableMfaResponses, DiscoverRequest, DiscoverResponse, DiscoverWorkloadsData, DiscoverWorkloadsErrors, DiscoverWorkloadsResponse, DiscoverWorkloadsResponses, DiskInfo, DiskSpaceAlert, DiskSpaceAlertSettings, DiskSpaceCheckResult, DnsAckRequest, DnsAckResponse, DnsChallengeRecordResult, DnsChangesResponse, DnsCompletionResponse, DnsLookupError, DnsLookupRequest, DnsLookupResponse, DnsProviderCredentials, DnsProviderResponse, DnsProviderSettings, DnsProviderSettingsMasked, DnsProviderType, DnsRecord, DnsRecordChange, DnsRecordContent, DnsRecordResponse, DnsRecordSetupResult, DnsRecordStatusResponse, DnsZone, DockerComposePresetConfig, DockerfilePresetConfig, DockerfileVariant, DockerRegistrySettings, DockerRegistrySettingsMasked, DomainAction, DomainChallengeResponse, DomainData, DomainEnvironmentResponse, DomainError, DomainErrors, DomainPlan, DomainResponse, DomainResponse2, DomainResponses, DownloadGlobalSkillArchiveData, DownloadGlobalSkillArchiveErrors, DownloadGlobalSkillArchiveResponse, DownloadGlobalSkillArchiveResponses, DownloadObjectData, DownloadObjectErrors, DownloadObjectResponse, DownloadObjectResponses, DownloadSkillArchiveData, DownloadSkillArchiveErrors, DownloadSkillArchiveResponse, DownloadSkillArchiveResponses, DrainNodeResponse, DrainStatusResponse, DropArchiveUpload, DropInspectionResponse, DropOffPoint, DropPresetCandidate, EmailConfig, EmailDomainResponse, EmailDomainWithDnsResponse, EmailProviderResponse, EmailProviderTypeRoute, EmailRequest, EmailResponse, EmailStatsResponse, EmailStatusData, EmailStatusErrors, EmailStatusResponse, EmailStatusResponse2, EmailStatusResponses, EmailTrackingResponse, EmailTrackingSetupResponse, EmailTrackingStatusResponse, EmbeddingData, EmbeddingInput, EmbeddingRequest, EmbeddingResponse, EmbeddingsData, EmbeddingsError, EmbeddingsErrors, EmbeddingsResponse, EmbeddingsResponses, EmbeddingUsage, EnableBackupScheduleData, EnableBackupScheduleErrors, EnableBackupScheduleResponse, EnableBackupScheduleResponses, EnableBlobRequest, EnableBlobResponse, EnableKvRequest, EnableKvResponse, EnablePgStatStatementsResponse, EndpointDto, EnqueuedJob, EnrichVisitorData, EnrichVisitorErrors, EnrichVisitorRequest, EnrichVisitorResponse, EnrichVisitorResponse2, EnrichVisitorResponses, EnrollmentTokenInfo, EnrollmentTokenListResponse, EntityInfoResponse, EntityResponse, EnvironmentConfiguration, EnvironmentDomainResponse, EnvironmentInfo, EnvironmentResponse, EnvironmentVariable, EnvironmentVariableInfo, EnvironmentVariableResponse, EnvironmentVariableValueResponse, EnvVarInput, EnvVarIntegrationInfo, EnvVarResponse, EnvVarTemplateResponse, ErrorDashboardStatsQuery, ErrorDashboardStatsResponse, ErrorEventResponse, ErrorGroupResponse, ErrorGroupStatsResponse, ErrorResponse, ErrorRow, ErrorTimeSeriesDataResponse, ErrorTimeSeriesQuery, EventActivityBucket, EventBreakdown, EventBrowserStats, EventCount, EventCountryStats, EventDetailQuery, EventDetailResponse, EventEntriesQuery, EventEntriesResponse, EventEntryInfo, EventKind, EventMetricsPayload, EventReferrerStats, EventsCountQuery, EventsResponse, EventTimeline, EventTimelineQuery, EventType, EventTypeBreakdown, EventTypeBreakdownQuery, EventTypeResponse, EventTypesResponse, EventVisitorInfo, EventVisitorsQuery, EventVisitorsResponse, ExecBody, ExecData, ExecDetachedData, ExecDetachedErrors, ExecDetachedResponse, ExecDetachedResponse2, ExecDetachedResponses, ExecErrors, ExecResponse, ExecResponse2, ExecResponses, ExecuteDeploymentOperationData, ExecuteDeploymentOperationErrors, ExecuteDeploymentOperationResponse, ExecuteDeploymentOperationResponses, ExecuteImportData, ExecuteImportErrors, ExecuteImportRequest, ExecuteImportResponse, ExecuteImportResponse2, ExecuteImportResponses, ExecuteOperationRequest, ExpireRequest, ExpireResponse, ExplorerSupportResponse, ExtendTimeoutBody, ExtendTimeoutData, ExtendTimeoutErrors, ExtendTimeoutResponse, ExtendTimeoutResponses, ExternalImageResponse, ExternalServiceBackupResponse, ExternalServiceDetails, ExternalServiceEnablePgStatStatementsData, ExternalServiceEnablePgStatStatementsErrors, ExternalServiceEnablePgStatStatementsResponse, ExternalServiceEnablePgStatStatementsResponses, ExternalServiceInfo, ExternalServiceMetricsByDatabaseData, ExternalServiceMetricsByDatabaseErrors, ExternalServiceMetricsByDatabaseResponse, ExternalServiceMetricsByDatabaseResponses, ExternalServiceMetricsCreateAlertRuleData, ExternalServiceMetricsCreateAlertRuleErrors, ExternalServiceMetricsCreateAlertRuleResponse, ExternalServiceMetricsCreateAlertRuleResponses, ExternalServiceMetricsDeleteAlertRuleData, ExternalServiceMetricsDeleteAlertRuleErrors, ExternalServiceMetricsDeleteAlertRuleResponse, ExternalServiceMetricsDeleteAlertRuleResponses, ExternalServiceMetricsGetAlertRulesData, ExternalServiceMetricsGetAlertRulesErrors, ExternalServiceMetricsGetAlertRulesResponse, ExternalServiceMetricsGetAlertRulesResponses, ExternalServiceMetricsGetLatestData, ExternalServiceMetricsGetLatestErrors, ExternalServiceMetricsGetLatestResponse, ExternalServiceMetricsGetLatestResponses, ExternalServiceMetricsGetRangeData, ExternalServiceMetricsGetRangeErrors, ExternalServiceMetricsGetRangeResponse, ExternalServiceMetricsGetRangeResponses, ExternalServiceMetricsStatusData, ExternalServiceMetricsStatusErrors, ExternalServiceMetricsStatusResponse, ExternalServiceMetricsStatusResponses, ExternalServiceMetricsToggleData, ExternalServiceMetricsToggleErrors, ExternalServiceMetricsToggleResponses, ExternalServiceMetricsUpdateAlertRuleData, ExternalServiceMetricsUpdateAlertRuleErrors, ExternalServiceMetricsUpdateAlertRuleResponse, ExternalServiceMetricsUpdateAlertRuleResponses, ExternalServiceResetPgStatStatementsData, ExternalServiceResetPgStatStatementsErrors, ExternalServiceResetPgStatStatementsResponse, ExternalServiceResetPgStatStatementsResponses, ExternalServiceSummary, FieldResponse, FinalizeOrderData, FinalizeOrderErrors, FinalizeOrderResponse, FinalizeOrderResponses, FinalizeProjectReleaseData, FinalizeProjectReleaseErrors, FinalizeProjectReleaseResponse, FinalizeProjectReleaseResponses, FindConversationData, FindConversationErrors, FindConversationResponse, FindConversationResponses, FiringSeriesEntry, FlagEnvironmentResponse, FlagListResponse, FlagResponse, FlagSnapshot, FlagSnapshotResponse, FlagValueType, ForecastAlgorithm, ForecastParams, FullError, FullEvent, FullRequest, FunnelMetricsResponse, FunnelResponse, GatewayStatus, GenAiEvent, GenAiSpanDetail, GenAiTraceDetailResponse, GenAiTraceSummariesResponse, GenAiTraceSummary, GeneralStatsQuery, GeneralStatsResponse, GenerateDockerfileRequest, GenerateDockerfileResponse, GenerateJoinTokenData, GenerateJoinTokenErrors, GenerateJoinTokenResponse, GenerateJoinTokenResponse2, GenerateJoinTokenResponses, GeneratePresetDockerfileData, GeneratePresetDockerfileErrors, GeneratePresetDockerfileResponse, GeneratePresetDockerfileResponses, GeoLocationResponse, GeoRestrictionsConfig, GetAccessInfoData, GetAccessInfoErrors, GetAccessInfoResponse, GetAccessInfoResponses, GetActiveVisitorsData, GetActiveVisitorsErrors, GetActiveVisitorsResponse, GetActiveVisitorsResponses, GetActivityGraphData, GetActivityGraphErrors, GetActivityGraphResponse, GetActivityGraphResponses, GetAdminGateData, GetAdminGateErrors, GetAdminGateResponse, GetAdminGateResponses, GetAgentData, GetAgentErrors, GetAgentResponse, GetAgentResponses, GetAggregatedBucketsData, GetAggregatedBucketsErrors, GetAggregatedBucketsResponse, GetAggregatedBucketsResponses, GetAiAgentBreakdownData, GetAiAgentBreakdownError, GetAiAgentBreakdownErrors, GetAiAgentBreakdownResponse, GetAiAgentBreakdownResponses, GetAiAgentPagesData, GetAiAgentPagesError, GetAiAgentPagesErrors, GetAiAgentPagesResponse, GetAiAgentPagesResponses, GetAiAgentTimelineData, GetAiAgentTimelineError, GetAiAgentTimelineErrors, GetAiAgentTimelineResponse, GetAiAgentTimelineResponses, GetAiPageBreakdownData, GetAiPageBreakdownError, GetAiPageBreakdownErrors, GetAiPageBreakdownResponse, GetAiPageBreakdownResponses, GetAiStatusBreakdownData, GetAiStatusBreakdownError, GetAiStatusBreakdownErrors, GetAiStatusBreakdownResponse, GetAiStatusBreakdownResponses, GetAlertData, GetAlertError, GetAlertErrors, GetAlertResponse, GetAlertResponses, GetAlertRuleData, GetAlertRuleErrors, GetAlertRuleResponse, GetAlertRuleResponses, GetAllRepositoriesByNameData, GetAllRepositoriesByNameErrors, GetAllRepositoriesByNameResponse, GetAllRepositoriesByNameResponses, GetAnalyticsActiveVisitorsData, GetAnalyticsActiveVisitorsErrors, GetAnalyticsActiveVisitorsResponse, GetAnalyticsActiveVisitorsResponses, GetAnalyticsEventsCountData, GetAnalyticsEventsCountErrors, GetAnalyticsEventsCountResponse, GetAnalyticsEventsCountResponses, GetAnalyticsSessionEventsData, GetAnalyticsSessionEventsErrors, GetAnalyticsSessionEventsResponse, GetAnalyticsSessionEventsResponses, GetAnalyticsVisitorSessionsData, GetAnalyticsVisitorSessionsErrors, GetAnalyticsVisitorSessionsResponse, GetAnalyticsVisitorSessionsResponses, GetApiKeyData, GetApiKeyErrors, GetApiKeyPermissionsData, GetApiKeyPermissionsErrors, GetApiKeyPermissionsResponse, GetApiKeyPermissionsResponses, GetApiKeyResponse, GetApiKeyResponses, GetAuditLogData, GetAuditLogErrors, GetAuditLogResponse, GetAuditLogResponses, GetBackupData, GetBackupError, GetBackupErrors, GetBackupResponse, GetBackupResponses, GetBackupScheduleData, GetBackupScheduleErrors, GetBackupScheduleResponse, GetBackupScheduleResponses, GetBranchesByRepositoryIdData, GetBranchesByRepositoryIdErrors, GetBranchesByRepositoryIdResponse, GetBranchesByRepositoryIdResponses, GetBucketedIncidentsData, GetBucketedIncidentsErrors, GetBucketedIncidentsResponse, GetBucketedIncidentsResponses, GetBucketedStatusData, GetBucketedStatusErrors, GetBucketedStatusResponse, GetBucketedStatusResponses, GetChallengeTokenData, GetChallengeTokenErrors, GetChallengeTokenResponse, GetChallengeTokenResponses, GetChatReadinessData, GetChatReadinessErrors, GetChatReadinessResponse, GetChatReadinessResponses, GetCliStatusData, GetCliStatusErrors, GetCliStatusResponses, GetClusterHealthData, GetClusterHealthErrors, GetClusterHealthResponse, GetClusterHealthResponses, GetClusterMemberData, GetClusterMemberErrors, GetClusterMemberResponse, GetClusterMemberResponses, GetCmdData, GetCmdErrors, GetCmdResponse, GetCmdResponses, GetContainerDetailData, GetContainerDetailErrors, GetContainerDetailResponse, GetContainerDetailResponses, GetContainerEnvironmentVariableData, GetContainerEnvironmentVariableErrors, GetContainerEnvironmentVariableResponse, GetContainerEnvironmentVariableResponses, GetContainerInfoData, GetContainerInfoErrors, GetContainerInfoResponse, GetContainerInfoResponses, GetContainerLogsByIdData, GetContainerLogsByIdErrors, GetContainerLogsData, GetContainerLogsErrors, GetContainerMetricsData, GetContainerMetricsErrors, GetContainerMetricsResponse, GetContainerMetricsResponses, GetConversationData, GetConversationDetailData, GetConversationDetailError, GetConversationDetailErrors, GetConversationDetailResponse, GetConversationDetailResponses, GetConversationErrors, GetConversationResponse, GetConversationResponses, GetConversationsData, GetConversationsError, GetConversationsErrors, GetConversationsResponse, GetConversationsResponses, GetCronByIdData, GetCronByIdErrors, GetCronByIdResponse, GetCronByIdResponses, GetCronExecutionsData, GetCronExecutionsErrors, GetCronExecutionsResponse, GetCronExecutionsResponses, GetCrossProjectTraceSiblingsData, GetCrossProjectTraceSiblingsError, GetCrossProjectTraceSiblingsErrors, GetCrossProjectTraceSiblingsResponse, GetCrossProjectTraceSiblingsResponses, GetCurrentMonitorStatusData, GetCurrentMonitorStatusErrors, GetCurrentMonitorStatusResponse, GetCurrentMonitorStatusResponses, GetCurrentUserData, GetCurrentUserErrors, GetCurrentUserResponse, GetCurrentUserResponses, GetCustomDomainData, GetCustomDomainErrors, GetCustomDomainResponse, GetCustomDomainResponses, GetDashboardData, GetDashboardError, GetDashboardErrors, GetDashboardProjectsAnalyticsData, GetDashboardProjectsAnalyticsErrors, GetDashboardProjectsAnalyticsResponse, GetDashboardProjectsAnalyticsResponses, GetDashboardResponse, GetDashboardResponses, GetDeliveryData, GetDeliveryErrors, GetDeliveryResponse, GetDeliveryResponses, GetDeploymentContainerLogContentData, GetDeploymentContainerLogContentErrors, GetDeploymentContainerLogContentResponse, GetDeploymentContainerLogContentResponses, GetDeploymentData, GetDeploymentErrors, GetDeploymentJobLogsData, GetDeploymentJobLogsErrors, GetDeploymentJobLogsResponse, GetDeploymentJobLogsResponses, GetDeploymentJobsData, GetDeploymentJobsErrors, GetDeploymentJobsResponse, GetDeploymentJobsResponses, GetDeploymentOperationsData, GetDeploymentOperationsErrors, GetDeploymentOperationsResponse, GetDeploymentOperationsResponses, GetDeploymentOperationStatusData, GetDeploymentOperationStatusErrors, GetDeploymentOperationStatusResponse, GetDeploymentOperationStatusResponses, GetDeploymentResponse, GetDeploymentResponses, GetDeploymentsParams, GetDeploymentTokenData, GetDeploymentTokenErrors, GetDeploymentTokenResponse, GetDeploymentTokenResponses, GetDiskStatusData, GetDiskStatusErrors, GetDiskStatusResponse, GetDiskStatusResponses, GetDnsChangesData, GetDnsChangesErrors, GetDnsChangesResponse, GetDnsChangesResponses, GetDnsProviderData, GetDnsProviderErrors, GetDnsProviderResponse, GetDnsProviderResponses, GetDomainByHostData, GetDomainByHostErrors, GetDomainByHostResponse, GetDomainByHostResponses, GetDomainByIdData, GetDomainByIdErrors, GetDomainByIdResponse, GetDomainByIdResponses, GetDomainByNameData, GetDomainByNameErrors, GetDomainByNameResponse, GetDomainByNameResponses, GetDomainData, GetDomainDnsRecordsData, GetDomainDnsRecordsErrors, GetDomainDnsRecordsResponse, GetDomainDnsRecordsResponses, GetDomainErrors, GetDomainOrderData, GetDomainOrderErrors, GetDomainOrderResponse, GetDomainOrderResponses, GetDomainResponse, GetDomainResponses, GetEmailData, GetEmailErrors, GetEmailEventsData, GetEmailEventsErrors, GetEmailEventsResponse, GetEmailEventsResponses, GetEmailLinksData, GetEmailLinksErrors, GetEmailLinksResponse, GetEmailLinksResponses, GetEmailProviderData, GetEmailProviderErrors, GetEmailProviderResponse, GetEmailProviderResponses, GetEmailResponse, GetEmailResponses, GetEmailStatsData, GetEmailStatsErrors, GetEmailStatsResponse, GetEmailStatsResponses, GetEmailTrackingData, GetEmailTrackingErrors, GetEmailTrackingResponse, GetEmailTrackingResponses, GetEmailTrackingStatusData, GetEmailTrackingStatusErrors, GetEmailTrackingStatusResponse, GetEmailTrackingStatusResponses, GetEntityInfoData, GetEntityInfoErrors, GetEntityInfoResponse, GetEntityInfoResponses, GetEnvironmentCronsData, GetEnvironmentCronsErrors, GetEnvironmentCronsResponse, GetEnvironmentCronsResponses, GetEnvironmentData, GetEnvironmentDomainsData, GetEnvironmentDomainsErrors, GetEnvironmentDomainsResponse, GetEnvironmentDomainsResponses, GetEnvironmentErrors, GetEnvironmentResponse, GetEnvironmentResponses, GetEnvironmentsData, GetEnvironmentsErrors, GetEnvironmentsResponse, GetEnvironmentsResponses, GetEnvironmentVariablesData, GetEnvironmentVariablesErrors, GetEnvironmentVariablesQuery, GetEnvironmentVariablesResponse, GetEnvironmentVariablesResponses, GetEnvironmentVariableValueData, GetEnvironmentVariableValueErrors, GetEnvironmentVariableValueResponse, GetEnvironmentVariableValueResponses, GetErrorDashboardStatsData, GetErrorDashboardStatsErrors, GetErrorDashboardStatsResponse, GetErrorDashboardStatsResponses, GetErrorEventData, GetErrorEventErrors, GetErrorEventResponse, GetErrorEventResponses, GetErrorGroupData, GetErrorGroupErrors, GetErrorGroupResponse, GetErrorGroupResponses, GetErrorStatsData, GetErrorStatsErrors, GetErrorStatsResponse, GetErrorStatsResponses, GetErrorTimeSeriesData, GetErrorTimeSeriesErrors, GetErrorTimeSeriesResponse, GetErrorTimeSeriesResponses, GetEventDetailData, GetEventDetailErrors, GetEventDetailResponse, GetEventDetailResponses, GetEventEntriesData, GetEventEntriesErrors, GetEventEntriesResponse, GetEventEntriesResponses, GetEventsCountData, GetEventsCountErrors, GetEventsCountResponse, GetEventsCountResponses, GetEventsTimelineData, GetEventsTimelineErrors, GetEventsTimelineResponse, GetEventsTimelineResponses, GetEventTypeBreakdownData, GetEventTypeBreakdownErrors, GetEventTypeBreakdownResponse, GetEventTypeBreakdownResponses, GetEventVisitorsData, GetEventVisitorsErrors, GetEventVisitorsResponse, GetEventVisitorsResponses, GetExternalImageData, GetExternalImageErrors, GetExternalImageResponse, GetExternalImageResponses, GetFileData, GetFileErrors, GetFileResponse, GetFileResponses, GetFlagData, GetFlagErrors, GetFlagResponse, GetFlagResponses, GetFlagSnapshotData, GetFlagSnapshotErrors, GetFlagSnapshotResponse, GetFlagSnapshotResponses, GetFunnelMetricsData, GetFunnelMetricsErrors, GetFunnelMetricsQuery, GetFunnelMetricsResponse, GetFunnelMetricsResponses, GetGenaiTraceData, GetGenaiTraceError, GetGenaiTraceErrors, GetGenaiTraceResponse, GetGenaiTraceResponses, GetGeneralStatsData, GetGeneralStatsErrors, GetGeneralStatsResponse, GetGeneralStatsResponses, GetGitProviderData, GetGitProviderErrors, GetGitProviderResponse, GetGitProviderResponses, GetGlobalEventsData, GetGlobalEventsErrors, GetGlobalEventsResponse, GetGlobalEventsResponses, GetGlobalEventStatsData, GetGlobalEventStatsErrors, GetGlobalEventStatsResponse, GetGlobalEventStatsResponses, GetGlobalMcpData, GetGlobalMcpErrors, GetGlobalMcpResponse, GetGlobalMcpResponses, GetGlobalSandboxStatusData, GetGlobalSandboxStatusErrors, GetGlobalSandboxStatusResponse, GetGlobalSandboxStatusResponses, GetGlobalSkillData, GetGlobalSkillErrors, GetGlobalSkillResponse, GetGlobalSkillResponses, GetGroupedPageMetricsData, GetGroupedPageMetricsError, GetGroupedPageMetricsErrors, GetGroupedPageMetricsResponse, GetGroupedPageMetricsResponses, GetHealthData, GetHealthError, GetHealthErrors, GetHealthResponse, GetHealthResponses, GetHourlyVisitsData, GetHourlyVisitsErrors, GetHourlyVisitsResponse, GetHourlyVisitsResponses, GetHttpChallengeDebugData, GetHttpChallengeDebugErrors, GetHttpChallengeDebugResponse, GetHttpChallengeDebugResponses, GetImportStatusData, GetImportStatusErrors, GetImportStatusResponse, GetImportStatusResponses, GetIncidentData, GetIncidentErrors, GetIncidentResponse, GetIncidentResponses, GetIncidentUpdatesData, GetIncidentUpdatesErrors, GetIncidentUpdatesResponse, GetIncidentUpdatesResponses, GetIpAccessControlData, GetIpAccessControlError, GetIpAccessControlErrors, GetIpAccessControlResponse, GetIpAccessControlResponses, GetIpGeolocationData, GetIpGeolocationError, GetIpGeolocationErrors, GetIpGeolocationResponse, GetIpGeolocationResponses, GetJoinTokenStatusData, GetJoinTokenStatusErrors, GetJoinTokenStatusResponse, GetJoinTokenStatusResponses, GetLastDeploymentData, GetLastDeploymentErrors, GetLastDeploymentResponse, GetLastDeploymentResponses, GetLatestScanData, GetLatestScanError, GetLatestScanErrors, GetLatestScanResponse, GetLatestScanResponses, GetLatestScansPerEnvironmentData, GetLatestScansPerEnvironmentError, GetLatestScansPerEnvironmentErrors, GetLatestScansPerEnvironmentResponse, GetLatestScansPerEnvironmentResponses, GetLiveVisitorsListData, GetLiveVisitorsListErrors, GetLiveVisitorsListResponse, GetLiveVisitorsListResponses, GetLogContextData, GetLogContextError, GetLogContextErrors, GetLogContextResponse, GetLogContextResponses, GetMcpData, GetMcpErrors, GetMcpResponse, GetMcpResponses, GetMetricsOverTimeData, GetMetricsOverTimeError, GetMetricsOverTimeErrors, GetMetricsOverTimeResponse, GetMetricsOverTimeResponses, GetMonitorData, GetMonitorErrors, GetMonitorResponse, GetMonitorResponses, GetNotificationProviderData, GetNotificationProviderErrors, GetNotificationProviderResponse, GetNotificationProviderResponses, GetOnDemandCertStatusData, GetOnDemandCertStatusErrors, GetOnDemandCertStatusResponse, GetOnDemandCertStatusResponses, GetOrCreateDsnData, GetOrCreateDsnErrors, GetOrCreateDsnRequest, GetOrCreateDsnResponse, GetOrCreateDsnResponses, GetPageFlowData, GetPageFlowErrors, GetPageFlowResponse, GetPageFlowResponses, GetPageHourlySessionsData, GetPageHourlySessionsErrors, GetPageHourlySessionsResponse, GetPageHourlySessionsResponses, GetPagePathDetailData, GetPagePathDetailErrors, GetPagePathDetailResponse, GetPagePathDetailResponses, GetPagePathsData, GetPagePathsErrors, GetPagePathsResponse, GetPagePathsResponses, GetPagePathsSparklinesData, GetPagePathsSparklinesErrors, GetPagePathsSparklinesResponse, GetPagePathsSparklinesResponses, GetPagePathVisitorsData, GetPagePathVisitorsErrors, GetPagePathVisitorsResponse, GetPagePathVisitorsResponses, GetPendingActionData, GetPendingActionErrors, GetPendingActionResponse, GetPendingActionResponses, GetPerformanceMetricsData, GetPerformanceMetricsError, GetPerformanceMetricsErrors, GetPerformanceMetricsResponse, GetPerformanceMetricsResponses, GetPgUpgradeData, GetPgUpgradeErrors, GetPgUpgradeLogsData, GetPgUpgradeLogsErrors, GetPgUpgradeLogsResponse, GetPgUpgradeLogsResponses, GetPgUpgradeResponse, GetPgUpgradeResponses, GetPipelineStatsData, GetPipelineStatsError, GetPipelineStatsErrors, GetPipelineStatsResponse, GetPipelineStatsResponses, GetPlatformInfoData, GetPlatformInfoErrors, GetPlatformInfoResponse, GetPlatformInfoResponses, GetPostgresWalHealthData, GetPostgresWalHealthErrors, GetPostgresWalHealthResponse, GetPostgresWalHealthResponses, GetPreferencesData, GetPreferencesErrors, GetPreferencesResponse, GetPreferencesResponses, GetPreviewGatewayLogsData, GetPreviewGatewayLogsResponse, GetPreviewGatewayLogsResponses, GetPreviewGatewaySettingsData, GetPreviewGatewaySettingsResponse, GetPreviewGatewaySettingsResponses, GetPreviewGatewayStatusData, GetPreviewGatewayStatusResponse, GetPreviewGatewayStatusResponses, GetPricingData, GetPricingError, GetPricingErrors, GetPricingResponse, GetPricingResponses, GetPrivateIpData, GetPrivateIpErrors, GetPrivateIpResponses, GetProjectAlarmsSummaryData, GetProjectAlarmsSummaryErrors, GetProjectAlarmsSummaryResponse, GetProjectAlarmsSummaryResponses, GetProjectBySlugData, GetProjectBySlugErrors, GetProjectBySlugResponse, GetProjectBySlugResponses, GetProjectData, GetProjectDeploymentsData, GetProjectDeploymentsErrors, GetProjectDeploymentsResponse, GetProjectDeploymentsResponses, GetProjectErrors, GetProjectResponse, GetProjectResponses, GetProjectsData, GetProjectSecretsQuery, GetProjectsErrors, GetProjectServiceEnvironmentVariablesData, GetProjectServiceEnvironmentVariablesErrors, GetProjectServiceEnvironmentVariablesResponse, GetProjectServiceEnvironmentVariablesResponses, GetProjectSessionReplaysData, GetProjectSessionReplaysError, GetProjectSessionReplaysErrors, GetProjectSessionReplaysQuery, GetProjectSessionReplaysResponse, GetProjectSessionReplaysResponse2, GetProjectSessionReplaysResponses, GetProjectsHealthData, GetProjectsHealthError, GetProjectsHealthErrors, GetProjectsHealthResponse, GetProjectsHealthResponses, GetProjectsMonitorHealthData, GetProjectsMonitorHealthErrors, GetProjectsMonitorHealthResponse, GetProjectsMonitorHealthResponses, GetProjectsResponse, GetProjectsResponses, GetProjectStatisticsData, GetProjectStatisticsErrors, GetProjectStatisticsResponse, GetProjectStatisticsResponses, GetProjectTemplateData, GetProjectTemplateErrors, GetProjectTemplateResponse, GetProjectTemplateResponses, GetPropertyBreakdownData, GetPropertyBreakdownErrors, GetPropertyBreakdownResponse, GetPropertyBreakdownResponses, GetPropertyTimelineData, GetPropertyTimelineErrors, GetPropertyTimelineResponse, GetPropertyTimelineResponses, GetProviderConnectionsData, GetProviderConnectionsErrors, GetProviderConnectionsResponse, GetProviderConnectionsResponses, GetProviderMetadataData, GetProviderMetadataErrors, GetProviderMetadataResponse, GetProviderMetadataResponses, GetProvidersMetadataData, GetProvidersMetadataErrors, GetProvidersMetadataResponse, GetProvidersMetadataResponses, GetProxyLogByIdData, GetProxyLogByIdError, GetProxyLogByIdErrors, GetProxyLogByIdResponse, GetProxyLogByIdResponses, GetProxyLogByRequestIdData, GetProxyLogByRequestIdError, GetProxyLogByRequestIdErrors, GetProxyLogByRequestIdResponse, GetProxyLogByRequestIdResponses, GetProxyLogsData, GetProxyLogsError, GetProxyLogsErrors, GetProxyLogsResponse, GetProxyLogsResponses, GetPublicBranchesData, GetPublicBranchesErrors, GetPublicBranchesResponse, GetPublicBranchesResponses, GetPublicIpData, GetPublicIpErrors, GetPublicIpResponses, GetPublicRepositoryData, GetPublicRepositoryErrors, GetPublicRepositoryResponse, GetPublicRepositoryResponses, GetQuotaData, GetQuotaError, GetQuotaErrors, GetQuotaResponse, GetQuotaResponses, GetRecentActivityData, GetRecentActivityErrors, GetRecentActivityResponse, GetRecentActivityResponses, GetRemoteExternalImageData, GetRemoteExternalImageErrors, GetRemoteExternalImageResponse, GetRemoteExternalImageResponses, GetRepositoryBranchesData, GetRepositoryBranchesErrors, GetRepositoryBranchesResponse, GetRepositoryBranchesResponses, GetRepositoryByIdData, GetRepositoryByIdErrors, GetRepositoryByIdResponse, GetRepositoryByIdResponses, GetRepositoryByNameData, GetRepositoryByNameErrors, GetRepositoryByNameResponse, GetRepositoryByNameResponses, GetRepositoryPresetByNameData, GetRepositoryPresetByNameErrors, GetRepositoryPresetByNameResponse, GetRepositoryPresetByNameResponses, GetRepositoryPresetLiveData, GetRepositoryPresetLiveErrors, GetRepositoryPresetLiveResponse, GetRepositoryPresetLiveResponses, GetRepositoryTagsData, GetRepositoryTagsErrors, GetRepositoryTagsResponse, GetRepositoryTagsResponses, GetRequest, GetResolvedEnvironmentVariablesData, GetResolvedEnvironmentVariablesErrors, GetResolvedEnvironmentVariablesResponse, GetResolvedEnvironmentVariablesResponses, GetResolvedEnvironmentVariableValueData, GetResolvedEnvironmentVariableValueErrors, GetResolvedEnvironmentVariableValueResponse, GetResolvedEnvironmentVariableValueResponses, GetResponse, GetRestoreCapabilitiesData, GetRestoreCapabilitiesError, GetRestoreCapabilitiesErrors, GetRestoreCapabilitiesResponse, GetRestoreCapabilitiesResponses, GetRestoreRunData, GetRestoreRunError, GetRestoreRunErrors, GetRestoreRunResponse, GetRestoreRunResponses, GetRouteData, GetRouteErrors, GetRouteResponse, GetRouteResponses, GetRunData, GetRunErrors, GetRunResponse, GetRunResponses, GetRunWithLogsData, GetRunWithLogsErrors, GetRunWithLogsResponse, GetRunWithLogsResponses, GetS3CredentialsData, GetS3CredentialsErrors, GetS3CredentialsResponse, GetS3CredentialsResponses, GetS3SourceData, GetS3SourceError, GetS3SourceErrors, GetS3SourceResponse, GetS3SourceResponses, GetSandboxData, GetSandboxErrors, GetSandboxResponse, GetSandboxResponses, GetSandboxStatusData, GetSandboxStatusErrors, GetSandboxStatusResponse, GetSandboxStatusResponses, GetScanByDeploymentData, GetScanByDeploymentError, GetScanByDeploymentErrors, GetScanByDeploymentResponse, GetScanByDeploymentResponses, GetScanData, GetScanError, GetScanErrors, GetScanResponse, GetScanResponses, GetScanVulnerabilitiesData, GetScanVulnerabilitiesError, GetScanVulnerabilitiesErrors, GetScanVulnerabilitiesResponse, GetScanVulnerabilitiesResponses, GetServiceBySlugData, GetServiceBySlugErrors, GetServiceBySlugResponse, GetServiceBySlugResponses, GetServiceData, GetServiceEnvironmentVariableData, GetServiceEnvironmentVariableErrors, GetServiceEnvironmentVariableResponse, GetServiceEnvironmentVariableResponses, GetServiceEnvironmentVariablesData, GetServiceEnvironmentVariablesErrors, GetServiceEnvironmentVariablesResponse, GetServiceEnvironmentVariablesResponses, GetServiceErrors, GetServiceHealthStatusData, GetServiceHealthStatusErrors, GetServiceHealthStatusResponse, GetServiceHealthStatusResponses, GetServicePreviewEnvironmentVariableNamesData, GetServicePreviewEnvironmentVariableNamesErrors, GetServicePreviewEnvironmentVariableNamesResponse, GetServicePreviewEnvironmentVariableNamesResponses, GetServicePreviewEnvironmentVariablesMaskedData, GetServicePreviewEnvironmentVariablesMaskedErrors, GetServicePreviewEnvironmentVariablesMaskedResponse, GetServicePreviewEnvironmentVariablesMaskedResponses, GetServiceResponse, GetServiceResponses, GetServiceRuntimeData, GetServiceRuntimeErrors, GetServiceRuntimeResponse, GetServiceRuntimeResponses, GetServiceStatsData, GetServiceStatsErrors, GetServiceStatsResponse, GetServiceStatsResponses, GetServiceTypeParametersData, GetServiceTypeParametersErrors, GetServiceTypeParametersResponses, GetServiceTypesData, GetServiceTypesErrors, GetServiceTypesResponse, GetServiceTypesResponses, GetSessionDetailsData, GetSessionDetailsErrors, GetSessionDetailsResponse, GetSessionDetailsResponses, GetSessionEventsData, GetSessionEventsErrors, GetSessionEventsResponse, GetSessionEventsResponses, GetSessionLogsData, GetSessionLogsErrors, GetSessionLogsResponse, GetSessionLogsResponses, GetSessionReplayData, GetSessionReplayError, GetSessionReplayErrors, GetSessionReplayEventsData, GetSessionReplayEventsError, GetSessionReplayEventsErrors, GetSessionReplayEventsResponse, GetSessionReplayEventsResponses, GetSessionReplayResponse, GetSessionReplayResponse2, GetSessionReplayResponses, GetSettingsData, GetSettingsErrors, GetSettingsResponse, GetSettingsResponses, GetSkillData, GetSkillErrors, GetSkillResponse, GetSkillResponses, GetSlowQueriesData, GetSlowQueriesErrors, GetSlowQueriesResponse, GetSlowQueriesResponses, GetStaticBundleData, GetStaticBundleErrors, GetStaticBundleResponse, GetStaticBundleResponses, GetStatusOverviewData, GetStatusOverviewErrors, GetStatusOverviewResponse, GetStatusOverviewResponses, GetTagsByRepositoryIdData, GetTagsByRepositoryIdErrors, GetTagsByRepositoryIdResponse, GetTagsByRepositoryIdResponses, GetTeamData, GetTeamErrors, GetTeamResponse, GetTeamResponses, GetTimeBucketStatsData, GetTimeBucketStatsError, GetTimeBucketStatsErrors, GetTimeBucketStatsResponse, GetTimeBucketStatsResponses, GetTodayStatsData, GetTodayStatsError, GetTodayStatsErrors, GetTodayStatsResponse, GetTodayStatsResponses, GetTraceData, GetTraceError, GetTraceErrors, GetTraceResponse, GetTraceResponses, GetUnifiedTraceData, GetUnifiedTraceError, GetUnifiedTraceErrors, GetUnifiedTraceResponse, GetUnifiedTraceResponses, GetUniqueCountsData, GetUniqueCountsErrors, GetUniqueCountsResponse, GetUniqueCountsResponses, GetUniqueEventsData, GetUniqueEventsErrors, GetUniqueEventsQuery, GetUniqueEventsResponse, GetUniqueEventsResponses, GetUpdateStatusData, GetUpdateStatusErrors, GetUpdateStatusResponse, GetUpdateStatusResponses, GetUptimeHistoryData, GetUptimeHistoryErrors, GetUptimeHistoryResponse, GetUptimeHistoryResponses, GetUsageByProviderData, GetUsageByProviderError, GetUsageByProviderErrors, GetUsageByProviderResponse, GetUsageByProviderResponses, GetUsageRecentData, GetUsageRecentError, GetUsageRecentErrors, GetUsageRecentResponse, GetUsageRecentResponses, GetUsageSummaryData, GetUsageSummaryError, GetUsageSummaryErrors, GetUsageSummaryResponse, GetUsageSummaryResponses, GetUsageTimeseriesData, GetUsageTimeseriesError, GetUsageTimeseriesErrors, GetUsageTimeseriesResponse, GetUsageTimeseriesResponses, GetUsageTopModelsData, GetUsageTopModelsError, GetUsageTopModelsErrors, GetUsageTopModelsResponse, GetUsageTopModelsResponses, GetVisitorByGuidData, GetVisitorByGuidErrors, GetVisitorByGuidResponse, GetVisitorByGuidResponses, GetVisitorByIdData, GetVisitorByIdErrors, GetVisitorByIdResponse, GetVisitorByIdResponses, GetVisitorDetailsData, GetVisitorDetailsErrors, GetVisitorDetailsResponse, GetVisitorDetailsResponses, GetVisitorFacetsData, GetVisitorFacetsErrors, GetVisitorFacetsResponse, GetVisitorFacetsResponses, GetVisitorInfoData, GetVisitorInfoErrors, GetVisitorInfoResponse, GetVisitorInfoResponses, GetVisitorJourneyData, GetVisitorJourneyErrors, GetVisitorJourneyResponse, GetVisitorJourneyResponses, GetVisitorsData, GetVisitorsErrors, GetVisitorSessionsData, GetVisitorSessionsError, GetVisitorSessionsErrors, GetVisitorSessionsQuery, GetVisitorSessionsResponse, GetVisitorSessionsResponse2, GetVisitorSessionsResponses, GetVisitorsResponse, GetVisitorsResponses, GetVisitorStatsData, GetVisitorStatsErrors, GetVisitorStatsResponse, GetVisitorStatsResponses, GetWebhookData, GetWebhookErrors, GetWebhookResponse, GetWebhookResponses, GitPushEvent, GitRefResponse, GitSourcePlan, GlobalConversationResponse, GlobalEventStatsResponse, GlobalMrrResponse, GlobalRecentEventResponse, GlobalRevenueSummaryResponse, GrantProjectAccessData, GrantProjectAccessErrors, GrantProjectAccessResponse, GrantProjectAccessResponses, GroupedPageMetric, GroupedPageMetricsQuery, GroupedPageMetricsResponse, HandleGitProviderOauthCallbackData, HandleGitProviderOauthCallbackErrors, HasAnalyticsEventsData, HasAnalyticsEventsErrors, HasAnalyticsEventsResponse, HasAnalyticsEventsResponse2, HasAnalyticsEventsResponses, HasErrorGroupsData, HasErrorGroupsErrors, HasErrorGroupsResponse, HasErrorGroupsResponse2, HasErrorGroupsResponses, HasEventsQuery, HasEventsResponse, HasMetricsQuery, HasMetricsResponse, HasPerformanceMetricsData, HasPerformanceMetricsError, HasPerformanceMetricsErrors, HasPerformanceMetricsResponse, HasPerformanceMetricsResponses, HealthCheckConfiguration, HealthCheckEntryResponse, HealthResponse, HealthStatus, HealthSummary, HeartbeatApiRequest, HeartbeatResponse, HierarchyLevel, HistogramSummary, HostnameChange, HostnamePreviewResponse, HourlyPageSessions, HourlyVisitsQuery, HttpChallengeDebugResponse, ImportCredentials, ImportExecutionStatus, ImportExternalServiceData, ImportExternalServiceErrors, ImportExternalServiceRequest, ImportExternalServiceResponse, ImportExternalServiceResponses, ImportOutcomeResponse, ImportPlan, ImportRowErrorResponse, ImportSelector, ImportSource, ImportSourceCapabilities, ImportSourceInfo, ImportStatusResponse, IncidentBucket, IncidentBucketedResponse, IncidentResponse, IncidentUpdateResponse, IncrRequest, IncrResponse, IngestLogsByPathData, IngestLogsByPathError, IngestLogsByPathErrors, IngestLogsByPathResponses, IngestLogsData, IngestLogsError, IngestLogsErrors, IngestLogsResponses, IngestMetricsByPathData, IngestMetricsByPathError, IngestMetricsByPathErrors, IngestMetricsByPathResponses, IngestMetricsData, IngestMetricsError, IngestMetricsErrors, IngestMetricsResponses, IngestSentryEnvelopeData, IngestSentryEnvelopeErrors, IngestSentryEnvelopeResponses, IngestSentryEventData, IngestSentryEventErrors, IngestSentryEventResponse, IngestSentryEventResponses, IngestTracesByPathData, IngestTracesByPathError, IngestTracesByPathErrors, IngestTracesByPathResponses, IngestTracesData, IngestTracesError, IngestTracesErrors, IngestTracesResponses, InitAuthResponse, InitSessionReplayData, InitSessionReplayError, InitSessionReplayErrors, InitSessionReplayResponse, InitSessionReplayResponses, Insight, InsightSeverity, InsightsResponse, InsightStatus, InspectDropArchiveData, InspectDropArchiveErrors, InspectDropArchiveResponse, InspectDropArchiveResponses, IntegrationResponse, IpAccessControlQuery, IpAccessControlResponse, JobLogsData, JobLogsErrors, JobLogsResponses, JobStatusData, JobStatusErrors, JobStatusResponse, JobStatusResponse2, JobStatusResponses, JobSummaryResponse, JoinTokenStatusResponse, JourneyEvent, JourneySession, KeysRequest, KeysResponse, KillJobBody, KillJobData, KillJobErrors, KillJobResponse, KillJobResponses, KnownAiAgentsResponse, KvDelData, KvDelErrors, KvDelResponse, KvDelResponses, KvDisableData, KvDisableErrors, KvDisableResponse, KvDisableResponses, KvEnableData, KvEnableErrors, KvEnableResponse, KvEnableResponses, KvExpireData, KvExpireErrors, KvExpireResponse, KvExpireResponses, KvGetData, KvGetErrors, KvGetResponse, KvGetResponses, KvIncrData, KvIncrErrors, KvIncrResponse, KvIncrResponses, KvKeysData, KvKeysErrors, KvKeysResponse, KvKeysResponses, KvSetData, KvSetErrors, KvSetResponse, KvSetResponses, KvStatusData, KvStatusErrors, KvStatusResponse, KvStatusResponse2, KvStatusResponses, KvTtlData, KvTtlErrors, KvTtlResponse, KvTtlResponses, KvUpdateData, KvUpdateErrors, KvUpdateResponse, KvUpdateResponses, LatestRunForSourceData, LatestRunForSourceErrors, LatestRunForSourceResponse, LatestRunForSourceResponses, LemonSqueezyConfig, LetsEncryptSettings, LineContext, LinkCustomDomainToCertificateData, LinkCustomDomainToCertificateErrors, LinkCustomDomainToCertificateResponse, LinkCustomDomainToCertificateResponses, LinkServiceRequest, LinkServiceToProjectData, LinkServiceToProjectErrors, LinkServiceToProjectResponse, LinkServiceToProjectResponses, ListAgentRunsData, ListAgentRunsErrors, ListAgentRunsResponse, ListAgentRunsResponses, ListAgentsData, ListAgentsErrors, ListAgentsResponse, ListAgentsResponse2, ListAgentsResponses, ListAiProvidersData, ListAiProvidersErrors, ListAiProvidersResponse, ListAiProvidersResponses, ListAlertRulesData, ListAlertRulesErrors, ListAlertRulesResponse, ListAlertRulesResponses, ListAlertsData, ListAlertsError, ListAlertsErrors, ListAlertsResponse, ListAlertsResponses, ListAllConversationsData, ListAllConversationsErrors, ListAllConversationsResponse, ListAllConversationsResponses, ListAllRunsData, ListAllRunsErrors, ListAllRunsResponse, ListAllRunsResponses, ListApiKeysData, ListApiKeysErrors, ListApiKeysQuery, ListApiKeysResponse, ListApiKeysResponses, ListAuditLogsData, ListAuditLogsErrors, ListAuditLogsQuery, ListAuditLogsResponse, ListAuditLogsResponses, ListAvailableContainersData, ListAvailableContainersErrors, ListAvailableContainersResponse, ListAvailableContainersResponses, ListBackupAlertsData, ListBackupAlertsError, ListBackupAlertsErrors, ListBackupAlertsResponse, ListBackupAlertsResponses, ListBackupChildrenData, ListBackupChildrenError, ListBackupChildrenErrors, ListBackupChildrenResponse, ListBackupChildrenResponses, ListBackupSchedulesData, ListBackupSchedulesError, ListBackupSchedulesErrors, ListBackupSchedulesResponse, ListBackupSchedulesResponses, ListBackupsForScheduleData, ListBackupsForScheduleErrors, ListBackupsForScheduleResponse, ListBackupsForScheduleResponses, ListBlobsQuery, ListBlobsResponse, ListCommitsByRepositoryIdData, ListCommitsByRepositoryIdErrors, ListCommitsByRepositoryIdResponse, ListCommitsByRepositoryIdResponses, ListConnectionsData, ListConnectionsErrors, ListConnectionsResponse, ListConnectionsResponses, ListContainersAtPathData, ListContainersAtPathErrors, ListContainersAtPathResponse, ListContainersAtPathResponses, ListContainersData, ListContainersErrors, ListContainersResponse, ListContainersResponses, ListConversationsData, ListConversationsErrors, ListConversationsResponse, ListConversationsResponses, ListCustomDomainsForProjectData, ListCustomDomainsForProjectErrors, ListCustomDomainsForProjectResponse, ListCustomDomainsForProjectResponses, ListCustomDomainsResponse, ListDashboardsData, ListDashboardsError, ListDashboardsErrors, ListDashboardsResponse, ListDashboardsResponses, ListDeliveriesData, ListDeliveriesErrors, ListDeliveriesResponse, ListDeliveriesResponses, ListDeploymentContainerLogsData, ListDeploymentContainerLogsErrors, ListDeploymentContainerLogsResponse, ListDeploymentContainerLogsResponses, ListDeploymentTokensData, ListDeploymentTokensErrors, ListDeploymentTokensQuery, ListDeploymentTokensResponse, ListDeploymentTokensResponses, ListDnsProvidersData, ListDnsProvidersErrors, ListDnsProvidersResponse, ListDnsProvidersResponses, ListDomainsData, ListDomainsErrors, ListDomainsResponse, ListDomainsResponse2, ListDomainsResponses, ListDsnsData, ListDsnsErrors, ListDsnsResponse, ListDsnsResponses, ListEmailDomainsData, ListEmailDomainsErrors, ListEmailDomainsResponse, ListEmailDomainsResponses, ListEmailProvidersData, ListEmailProvidersErrors, ListEmailProvidersResponse, ListEmailProvidersResponses, ListEmailsData, ListEmailsErrors, ListEmailsResponse, ListEmailsResponses, ListEnrollmentTokensData, ListEnrollmentTokensErrors, ListEnrollmentTokensResponse, ListEnrollmentTokensResponses, ListEntitiesData, ListEntitiesErrors, ListEntitiesQuery, ListEntitiesResponse, ListEntitiesResponses, ListErrorEventsData, ListErrorEventsErrors, ListErrorEventsQuery, ListErrorEventsResponse, ListErrorEventsResponses, ListErrorGroupsData, ListErrorGroupsErrors, ListErrorGroupsQuery, ListErrorGroupsResponse, ListErrorGroupsResponses, ListEventsData, ListEventsResponse, ListEventsResponses, ListEventTypesData, ListEventTypesResponse, ListEventTypesResponses, ListExternalImagesData, ListExternalImagesErrors, ListExternalImagesResponse, ListExternalImagesResponses, ListExternalPluginsData, ListExternalPluginsErrors, ListExternalPluginsResponse, ListExternalPluginsResponses, ListExternalServiceBackupsData, ListExternalServiceBackupsError, ListExternalServiceBackupsErrors, ListExternalServiceBackupsResponse, ListExternalServiceBackupsResponses, ListFlagsData, ListFlagsErrors, ListFlagsResponse, ListFlagsResponses, ListFunnelsData, ListFunnelsErrors, ListFunnelsResponse, ListFunnelsResponses, ListGitProvidersData, ListGitProvidersErrors, ListGitProvidersResponse, ListGitProvidersResponses, ListGlobalMcpsData, ListGlobalMcpsErrors, ListGlobalMcpsResponse, ListGlobalMcpsResponses, ListGlobalSkillsData, ListGlobalSkillsErrors, ListGlobalSkillsResponse, ListGlobalSkillsResponses, ListIncidentsData, ListIncidentsErrors, ListIncidentsResponses, ListInsightsData, ListInsightsError, ListInsightsErrors, ListInsightsResponse, ListInsightsResponses, ListIpAccessControlData, ListIpAccessControlError, ListIpAccessControlErrors, ListIpAccessControlResponse, ListIpAccessControlResponses, ListJobsData, ListJobsErrors, ListJobsResponse, ListJobsResponse2, ListJobsResponses, ListKnownAiAgentsData, ListKnownAiAgentsError, ListKnownAiAgentsErrors, ListKnownAiAgentsResponse, ListKnownAiAgentsResponses, ListManagedDomainsData, ListManagedDomainsErrors, ListManagedDomainsResponse, ListManagedDomainsResponses, ListMcpsData, ListMcpsErrors, ListMcpsResponse, ListMcpsResponse2, ListMcpsResponses, ListMetricLabelKeysData, ListMetricLabelKeysError, ListMetricLabelKeysErrors, ListMetricLabelKeysResponse, ListMetricLabelKeysResponses, ListMetricLabelValuesData, ListMetricLabelValuesError, ListMetricLabelValuesErrors, ListMetricLabelValuesResponse, ListMetricLabelValuesResponses, ListMetricNamesData, ListMetricNamesError, ListMetricNamesErrors, ListMetricNamesResponse, ListMetricNamesResponses, ListModelsData, ListModelsError, ListModelsErrors, ListModelsResponse, ListModelsResponses, ListMonitorsData, ListMonitorsErrors, ListMonitorsResponse, ListMonitorsResponses, ListNotificationProvidersData, ListNotificationProvidersErrors, ListNotificationProvidersResponse, ListNotificationProvidersResponses, ListOidcProvidersData, ListOidcProvidersResponse, ListOidcProvidersResponses, ListOidcProviderUsersData, ListOidcProviderUsersErrors, ListOidcProviderUsersResponse, ListOidcProviderUsersResponses, ListOidcRoleMappingsData, ListOidcRoleMappingsResponse, ListOidcRoleMappingsResponses, ListOnDemandCertsData, ListOnDemandCertsErrors, ListOnDemandCertsResponse, ListOnDemandCertsResponse2, ListOnDemandCertsResponses, ListOrdersData, ListOrdersErrors, ListOrdersResponse, ListOrdersResponse2, ListOrdersResponses, ListPeersData, ListPeersErrors, ListPeersResponse, ListPeersResponses, ListPendingActionsData, ListPendingActionsErrors, ListPendingActionsResponse, ListPendingActionsResponses, ListPgUpgradesData, ListPgUpgradesErrors, ListPgUpgradesResponse, ListPgUpgradesResponses, ListPresetsData, ListPresetsErrors, ListPresetsResponse, ListPresetsResponse2, ListPresetsResponses, ListProjectAccessData, ListProjectAccessErrors, ListProjectAccessResponse, ListProjectAccessResponses, ListProjectAlarmsData, ListProjectAlarmsErrors, ListProjectAlarmsResponse, ListProjectAlarmsResponses, ListProjectScansData, ListProjectScansError, ListProjectScansErrors, ListProjectScansResponse, ListProjectScansResponses, ListProjectSecretsData, ListProjectSecretsErrors, ListProjectSecretsResponse, ListProjectSecretsResponses, ListProjectServicesData, ListProjectServicesErrors, ListProjectServicesResponse, ListProjectServicesResponses, ListProjectTemplatesData, ListProjectTemplatesErrors, ListProjectTemplatesResponse, ListProjectTemplatesResponses, ListProjectTemplateTagsData, ListProjectTemplateTagsErrors, ListProjectTemplateTagsResponse, ListProjectTemplateTagsResponses, ListProviderKeysData, ListProviderKeysError, ListProviderKeysErrors, ListProviderKeysResponse, ListProviderKeysResponses, ListProviderZonesData, ListProviderZonesErrors, ListProviderZonesResponse, ListProviderZonesResponses, ListPublicProvidersData, ListPublicProvidersResponse, ListPublicProvidersResponses, ListReleaseFilesData, ListReleaseFilesErrors, ListReleaseFilesResponse, ListReleaseFilesResponses, ListReleasesData, ListReleasesErrors, ListReleasesResponse, ListReleasesResponses, ListRemoteExternalImagesData, ListRemoteExternalImagesErrors, ListRemoteExternalImagesResponse, ListRemoteExternalImagesResponses, ListRepositoriesByConnectionData, ListRepositoriesByConnectionErrors, ListRepositoriesByConnectionResponse, ListRepositoriesByConnectionResponses, ListRepositoriesByProviderData, ListRepositoriesByProviderErrors, ListRepositoriesByProviderResponse, ListRepositoriesByProviderResponses, ListRestoreRunsForServiceData, ListRestoreRunsForServiceResponse, ListRestoreRunsForServiceResponses, ListRootContainersData, ListRootContainersErrors, ListRootContainersResponse, ListRootContainersResponses, ListRoutesData, ListRoutesErrors, ListRoutesResponse, ListRoutesResponses, ListRunsResponse, ListS3SourcesData, ListS3SourcesError, ListS3SourcesErrors, ListS3SourcesResponse, ListS3SourcesResponses, ListSandboxesData, ListSandboxesResponse, ListSandboxesResponse2, ListSandboxesResponses, ListScansQuery, ListScheduleRunJobsData, ListScheduleRunJobsError, ListScheduleRunJobsErrors, ListScheduleRunJobsResponse, ListScheduleRunJobsResponses, ListScheduleRunsData, ListScheduleRunsError, ListScheduleRunsErrors, ListScheduleRunsResponse, ListScheduleRunsResponses, ListScheduleServicesData, ListScheduleServicesError, ListScheduleServicesErrors, ListScheduleServicesResponse, ListScheduleServicesResponses, ListSecretsData, ListSecretsErrors, ListSecretsResponse, ListSecretsResponse2, ListSecretsResponses, ListServiceHealthStatusesData, ListServiceHealthStatusesErrors, ListServiceHealthStatusesResponse, ListServiceHealthStatusesResponses, ListServiceProjectsData, ListServiceProjectsErrors, ListServiceProjectsResponse, ListServiceProjectsResponses, ListServiceSchedulesData, ListServiceSchedulesError, ListServiceSchedulesErrors, ListServiceSchedulesResponse, ListServiceSchedulesResponses, ListServicesData, ListServicesErrors, ListServicesResponse, ListServicesResponses, ListSkillsData, ListSkillsErrors, ListSkillsResponse, ListSkillsResponse2, ListSkillsResponses, ListSourceBackupsData, ListSourceBackupsError, ListSourceBackupsErrors, ListSourceBackupsResponse, ListSourceBackupsResponses, ListSourceFilesData, ListSourceFilesErrors, ListSourceFilesResponse, ListSourceFilesResponses, ListSourceMapsData, ListSourceMapsErrors, ListSourceMapsResponse, ListSourceMapsResponses, ListSourcesData, ListSourcesErrors, ListSourcesResponse, ListSourcesResponses, ListStaticBundlesData, ListStaticBundlesErrors, ListStaticBundlesResponse, ListStaticBundlesResponses, ListSyncedRepositoriesData, ListSyncedRepositoriesErrors, ListSyncedRepositoriesResponse, ListSyncedRepositoriesResponses, ListTagsResponse, ListTeamMembersData, ListTeamMembersErrors, ListTeamMembersResponse, ListTeamMembersResponses, ListTeamProjectsData, ListTeamProjectsErrors, ListTeamProjectsResponse, ListTeamProjectsResponses, ListTeamsData, ListTeamsErrors, ListTeamsResponse, ListTeamsResponses, ListTemplatesQuery, ListTemplatesResponse, ListUsersData, ListUsersErrors, ListUsersResponse, ListUsersResponses, ListVulnerabilitiesQuery, ListWebhooksData, ListWebhooksErrors, ListWebhooksResponse, ListWebhooksResponses, LiveVisitorInfo, LiveVisitorsListResponse, LocationCount, LocationGranularity, LocationInfo, LoginData, LoginErrors, LoginRequest, LoginResponse, LoginResponses, LogLevel, LogoutData, LogoutErrors, LogoutResponses, LogRecord, LogSearchLine, LogSeverity, LogSource, LogsQuery, LogsResponse, LogStream, LookupDnsARecordsData, LookupDnsARecordsError, LookupDnsARecordsErrors, LookupDnsARecordsResponse, LookupDnsARecordsResponses, ManagedDomainResponse, ManualAction, ManualActionTiming, McpDefinitionResponse, MessageContent, MessagePart, MessageResponse, MeteredMode, MetricAggregation, MetricBucket, MetricDataPoint, MetricsOverTimeResponse, MetricsQuery, MetricsRangeQuery, MetricsStatusResponse, MetricsStoreKind, MetricsSummaryResponse, MetricType, MfaRequiredResponse, MfaSetupResponse, MfaVerificationRequest, MigrationStep, MigrationSummary, MintEnrollmentTokenData, MintEnrollmentTokenErrors, MintEnrollmentTokenRequest, MintEnrollmentTokenResponse, MintEnrollmentTokenResponse2, MintEnrollmentTokenResponses, MiscResult, MkdirBody, MkdirData, MkdirErrors, MkdirResponse, MkdirResponses, ModelInfo, ModelListResponse, ModelPricing, ModelUsage, MonitoringSettings, MonitoringSettingsMasked, MonitorResponse, MonitorStatus, MrrBucketResponse, MultiNodeSettings, MultiNodeSettingsMasked, MxResult, NavEntry, NavSection, NetworkConfiguration, NetworkMode, NixpacksPresetConfig, NixpacksProvider, NodeContainerListResponse, NodeContainerResponse, NodeCostInfo, NodeHeartbeatData, NodeHeartbeatErrors, NodeHeartbeatResponse, NodeHeartbeatResponses, NodeInfoResponse, NodeListResponse, NodeMetricsGetRangeData, NodeMetricsGetRangeErrors, NodeMetricsGetRangeResponse, NodeMetricsGetRangeResponses, NotificationPreferencesResponse, NotificationProviderResponse, ObservabilityCompressionSettings, ObservabilityEvent, ObservabilityFullEventData, ObservabilityFullEventError, ObservabilityFullEventErrors, ObservabilityFullEventResponse, ObservabilityFullEventResponses, ObservabilityListEventsData, ObservabilityListEventsError, ObservabilityListEventsErrors, ObservabilityListEventsResponse, ObservabilityListEventsResponses, ObservabilityRetentionSettings, OidcCallbackData, OidcProviderResponse, OidcProvidersListResponse, OidcProviderSummary, OidcProviderUserResponse, OidcRoleMappingResponse, OidcTestConnectionResponse, OnDemandCertAttemptResponse, OnDemandCertRow, OnDemandTlsSettings, OpenAiError, OpenAiErrorResponse, OperatingSystemCount, OperationResultResponse, OperationResultsResponse, OtelDashboardResponse, OtelDashboardsResponse, OtelMetricAlertRuleResponse, OtelMetricAlertsResponse, OtelMetricLabelKeysResponse, OtelMetricLabelValuesResponse, OtelMetricNamesResponse, OtelMetricsResponse, OutlierAlgorithm, OutlierParams, OverprovisioningAssessment, OverprovisioningVerdict, PageActivityBucket, PageCountryStats, PageFlowEntry, PageFlowQuery, PageFlowResponse, PageHourlySessionsQuery, PageHourlySessionsResponse, PagePathDetailQuery, PagePathDetailResponse, PagePathInfo, PagePathSparkline, PagePathSparklinePoint, PagePathsQuery, PagePathsResponse, PagePathsSparklineQuery, PagePathsSparklineResponse, PagePathVisitorsQuery, PagePathVisitorsResponse, PageReferrerStats, PagesComparisonResponse, PageSessionComparison, PageSessionStats, PageSessionStatsQuery, PageTransition, PageVisit, PageVisitorSession, PaginatedEmailsResponse, PaginatedEntitiesResponse, PaginatedErrorEventsResponse, PaginatedErrorGroupsResponse, PaginatedEventsResponse, PaginatedExternalImagesResponse, PaginatedProjectList, PaginatedStaticBundlesResponse, Pagination, PaginationMeta, PaginationParams, PasswordProtectionConfig, PatchAdminGateData, PatchAdminGateErrors, PatchAdminGateResponse, PatchAdminGateResponses, PatchPreviewGatewaySettingsData, PatchPreviewGatewaySettingsResponse, PatchPreviewGatewaySettingsResponses, PatchSettingsRequest, PathVisitors, PathVisitorsAnalyticsQuery, PathVisitorsResponse, PauseDeploymentData, PauseDeploymentErrors, PauseDeploymentResponse, PauseDeploymentResponses, PauseSandboxData, PauseSandboxErrors, PauseSandboxResponse, PauseSandboxResponses, PeerEntry, PeerListResponse, PendingActionResponse, PerformanceMetricsQuery, PerformanceMetricsResponse, PermissionInfo, PgUpgradeLogResponse, PgUpgradeResponse, PipelineStats, PipelineStatsResponse, PlanComplexity, PlanMetadata, PlanRestoreData, PlanRestoreError, PlanRestoreErrors, PlanRestoreResponse, PlanRestoreResponses, PlanSourceBackup, PlanTarget, PlatformInfo, PluginManifest, PortMapping, PostDnsAckData, PostDnsAckErrors, PostDnsAckResponse, PostDnsAckResponses, PostgresWalHealth, PresetConfigSchema, PresetInfo, PresetResponse, PreviewAlertData, PreviewAlertError, PreviewAlertErrors, PreviewAlertResponse, PreviewAlertResponses, PreviewFunnelMetricsData, PreviewFunnelMetricsErrors, PreviewFunnelMetricsResponse, PreviewFunnelMetricsResponses, PreviewGatewaySettings, PreviewGatewaySettingsMasked, PreviewGatewaySettingsResponse, PreviewHostnameModeData, PreviewHostnameModeErrors, PreviewHostnameModeResponse, PreviewHostnameModeResponses, PreviewShareLinkBody, PreviewShareLinkResponse, PricingResponse, ProblemDetails, ProjectAccessResponse, ProjectConfiguration, ProjectDashboardAnalytics, ProjectDsnResponse, ProjectHealthSummary, ProjectInfo, ProjectMonitorHealth, ProjectPresetResponse, ProjectQuery, ProjectRef, ProjectResponse, ProjectSecretEnvironmentInfo, ProjectSecretResponse, ProjectServiceInfo, ProjectsHealthResponse, ProjectsMonitorHealthResponse, ProjectStatisticsResponse, ProjectStatsBreakdown, ProjectType, ProjectUsageInfoResponse, PromoteClusterMemberData, PromoteClusterMemberErrors, PromoteClusterMemberResponses, PromoteDeploymentData, PromoteDeploymentErrors, PromoteDeploymentRequest, PromoteDeploymentResponse, PromoteDeploymentResponses, PropertyBreakdownItem, PropertyBreakdownQuery, PropertyBreakdownResponse, PropertyColumn, PropertyTimelineItem, PropertyTimelineQuery, PropertyTimelineResponse, Protocol, ProviderCatalogDto, ProviderCatalogResponse, ProviderConfig, ProviderConfigMasked, ProviderDeletionCheckResponse, ProviderDescriptor, ProviderKeyResponse, ProviderMetadata, ProviderResponse, ProviderUsage, ProvisionDomainData, ProvisionDomainErrors, ProvisionDomainResponse, ProvisionDomainResponses, ProvisionResponse, ProxyLogResponse, ProxyLogsPaginatedResponse, PublicHostnameStrategy, PublicPresetResponse, PublicRepositoryInfo, PurgeLogsRequest, PurgeProjectLogsData, PurgeProjectLogsError, PurgeProjectLogsErrors, PurgeProjectLogsResponses, PushedExternalImageResponse, PushExternalImageData, PushExternalImageErrors, PushExternalImageResponse, PushExternalImageResponses, PushImageRequest, QueryDataData, QueryDataErrors, QueryDataRequest, QueryDataResponse, QueryDataResponse2, QueryDataResponses, QueryGenaiTracesData, QueryGenaiTracesError, QueryGenaiTracesErrors, QueryGenaiTracesResponse, QueryGenaiTracesResponses, QueryLogsData, QueryLogsError, QueryLogsErrors, QueryLogsResponse, QueryLogsResponses, QueryMetricsData, QueryMetricsError, QueryMetricsErrors, QueryMetricsResponse, QueryMetricsResponses, QueryTracesData, QueryTracesError, QueryTracesErrors, QueryTracesResponse, QueryTracesResponses, QueryTraceSummariesData, QueryTraceSummariesError, QueryTraceSummariesErrors, QueryTraceSummariesResponse, QueryTraceSummariesResponses, QuotaResponse, RateLimitConfig, RateLimitSettings, ReachabilityStatus, ReadFileData, ReadFileErrors, ReadFileResponse, ReadFileResponse2, ReadFileResponses, ReAnalyzeData, ReAnalyzeErrors, ReAnalyzeResponses, RebuildSandboxImageData, RebuildSandboxImageErrors, RebuildSandboxImageResponses, RecentActivityQuery, RecentActivityResponse, RecentEventResponse, RecentQueryParams, RecordConsoleEventData, RecordConsoleEventErrors, RecordConsoleEventResponses, RecordEventMetricsData, RecordEventMetricsErrors, RecordEventMetricsResponse, RecordEventMetricsResponses, RecordExposureRequest, RecordExposureResponse, RecordFlagExposureData, RecordFlagExposureErrors, RecordFlagExposureResponse, RecordFlagExposureResponses, RecordListResponse, RecordSpeedMetricsData, RecordSpeedMetricsError, RecordSpeedMetricsErrors, RecordSpeedMetricsResponse, RecordSpeedMetricsResponses, RecoveryTarget, ReferrerCount, ReferrersAnalyticsQuery, RefreshRouteTableData, RefreshRouteTableErrors, RefreshRouteTableResponse, RefreshRouteTableResponses, RegenerateDsnData, RegenerateDsnErrors, RegenerateDsnRequest, RegenerateDsnResponse, RegenerateDsnResponses, RegisterExternalImageData, RegisterExternalImageErrors, RegisterExternalImageResponse, RegisterExternalImageResponses, RegisterImageRequest, RegisterNodeApiRequest, RegisterNodeData, RegisterNodeErrors, RegisterNodeResponse, RegisterNodeResponse2, RegisterNodeResponses, RegisterRequest, ReinstallGitlabWebhookData, ReinstallGitlabWebhookErrors, ReinstallGitlabWebhookResponse, ReinstallGitlabWebhookResponses, ReinstallWebhookResponse, RejectPendingActionData, RejectPendingActionErrors, RejectPendingActionResponse, RejectPendingActionResponses, ReleaseListResponse, ReloadPluginsData, ReloadPluginsErrors, ReloadPluginsResponse, ReloadPluginsResponses, ReloadResponse, RemoteDeploymentResponse, RemoveClusterMemberData, RemoveClusterMemberErrors, RemoveClusterMemberResponse, RemoveClusterMemberResponses, RemoveManagedDomainData, RemoveManagedDomainErrors, RemoveManagedDomainResponse, RemoveManagedDomainResponses, RemoveNodeResponse, RemoveRoleData, RemoveRoleErrors, RemoveRoleResponse, RemoveRoleResponses, RemoveTeamMemberData, RemoveTeamMemberErrors, RemoveTeamMemberResponse, RemoveTeamMemberResponses, RenameConversationData, RenameConversationErrors, RenameConversationRequest, RenameConversationResponse, RenameConversationResponses, RenewDomainData, RenewDomainErrors, RenewDomainResponse, RenewDomainResponses, RepositoryListQuery, RepositoryListResponse, RepositoryPresetResponse, RepositoryResponse, RepositorySyncStartedResponse, RequestPasswordResetData, RequestPasswordResetErrors, RequestPasswordResetResponse, RequestPasswordResetResponses, RequestRow, ResetPasswordData, ResetPasswordErrors, ResetPasswordRequest, ResetPasswordResponse, ResetPasswordResponses, ResetPgStatStatementsRequest, ResetPgStatStatementsResponse, ResizeSandboxBody, ResizeSandboxData, ResizeSandboxErrors, ResizeSandboxResponse, ResizeSandboxResponses, ResolveAlarmData, ResolveAlarmErrors, ResolveAlarmResponses, ResolvedEnvVarResponse, ResolvedEnvVarSource, ResourceCounts, ResourceFootprint, ResourceInfo, ResourceLimitApplyResult, ResourceLimits, ResourceLimitsResponse, ResourceLimitsUpdateResponse, ResourcesBody, RestartContainerData, RestartContainerErrors, RestartContainerResponse, RestartContainerResponses, RestartPreviewGatewayData, RestartPreviewGatewayResponse, RestartPreviewGatewayResponses, RestartSandboxData, RestartSandboxErrors, RestartSandboxResponse, RestartSandboxResponses, RestoreCapabilities, RestoreCapabilitiesResponse, RestoreFlagData, RestoreFlagErrors, RestoreFlagResponse, RestoreFlagResponses, RestorePlan, RestoreRequestMode, RestoreRunView, RestoreUserData, RestoreUserErrors, RestoreUserResponse, RestoreUserResponses, ResumeDeploymentData, ResumeDeploymentErrors, ResumeDeploymentResponse, ResumeDeploymentResponses, ResumeSandboxData, ResumeSandboxErrors, ResumeSandboxResponse, ResumeSandboxResponses, RetentionCleanupFailure, RetentionCleanupReport, RetryClusterData, RetryClusterErrors, RetryClusterRequest, RetryClusterResponse, RetryClusterResponses, RetryDeliveryData, RetryDeliveryErrors, RetryDeliveryResponse, RetryDeliveryResponses, RetryPgUpgradeData, RetryPgUpgradeErrors, RetryPgUpgradeResponse, RetryPgUpgradeResponses, RetryRunData, RetryRunErrors, RetryRunResponse, RetryRunResponses, RevealGlobalMcpConfigData, RevealGlobalMcpConfigErrors, RevealGlobalMcpConfigResponse, RevealGlobalMcpConfigResponses, RevealMcpConfigData, RevealMcpConfigErrors, RevealMcpConfigResponse, RevealMcpConfigResponses, RevealNotificationProviderConfigData, RevealNotificationProviderConfigErrors, RevealNotificationProviderConfigResponse, RevealNotificationProviderConfigResponses, RevealServiceParameterData, RevealServiceParameterErrors, RevealServiceParameterResponse, RevealServiceParameterResponses, RevenueCreateIntegrationData, RevenueCreateIntegrationErrors, RevenueCreateIntegrationResponse, RevenueCreateIntegrationResponses, RevenueDeleteIntegrationData, RevenueDeleteIntegrationResponse, RevenueDeleteIntegrationResponses, RevenueGlobalEventsData, RevenueGlobalEventsResponse, RevenueGlobalEventsResponses, RevenueImportInvoicesCsvData, RevenueImportInvoicesCsvErrors, RevenueImportInvoicesCsvResponse, RevenueImportInvoicesCsvResponses, RevenueImportSubscriptionsCsvData, RevenueImportSubscriptionsCsvErrors, RevenueImportSubscriptionsCsvResponse, RevenueImportSubscriptionsCsvResponses, RevenueListIntegrationsData, RevenueListIntegrationsResponse, RevenueListIntegrationsResponses, RevenueListProvidersData, RevenueListProvidersResponse, RevenueListProvidersResponses, RevenueMetricsCustomersData, RevenueMetricsCustomersResponse, RevenueMetricsCustomersResponses, RevenueMetricsGlobalMrrData, RevenueMetricsGlobalMrrResponse, RevenueMetricsGlobalMrrResponses, RevenueMetricsGlobalSummaryData, RevenueMetricsGlobalSummaryResponse, RevenueMetricsGlobalSummaryResponses, RevenueMetricsMrrData, RevenueMetricsMrrResponse, RevenueMetricsMrrResponses, RevenueMetricsSummaryData, RevenueMetricsSummaryResponse, RevenueMetricsSummaryResponses, RevenueRecentEventsData, RevenueRecentEventsResponse, RevenueRecentEventsResponses, RevenueRotateTokenData, RevenueRotateTokenResponse, RevenueRotateTokenResponses, RevenueRow, RevenueUpdateConfigData, RevenueUpdateConfigErrors, RevenueUpdateConfigResponse, RevenueUpdateConfigResponses, RevenueUpdateSecretData, RevenueUpdateSecretErrors, RevenueUpdateSecretResponse, RevenueUpdateSecretResponses, RevokeDsnData, RevokeDsnErrors, RevokeDsnResponse, RevokeDsnResponses, RevokeEnrollmentTokenData, RevokeEnrollmentTokenErrors, RevokeEnrollmentTokenResponse, RevokeEnrollmentTokenResponses, RevokeJoinTokenData, RevokeJoinTokenErrors, RevokeJoinTokenResponse, RevokeJoinTokenResponses, RevokeProjectAccessData, RevokeProjectAccessErrors, RevokeProjectAccessResponse, RevokeProjectAccessResponses, RiskLevel, RoleInfo, RollbackPgUpgradeData, RollbackPgUpgradeErrors, RollbackPgUpgradeResponse, RollbackPgUpgradeResponses, RollbackToDeploymentData, RollbackToDeploymentErrors, RollbackToDeploymentResponse, RollbackToDeploymentResponses, RootfsCacheEntry, RootfsGcData, RootfsGcReport, RootfsGcResponses, RootfsReport, RootfsReportData, RootfsReportResponses, RootfsVmEntry, RotateApiKeyData, RotateApiKeyErrors, RotateApiKeyResponse, RotateApiKeyResponses, RotateDeploymentTokenData, RotateDeploymentTokenErrors, RotateDeploymentTokenResponse, RotateDeploymentTokenResponses, RouteRefreshResponse, RouteResponse, RouteRole, RouteUser, RouteUserWithRoles, RunBackupForSourceData, RunBackupForSourceError, RunBackupForSourceErrors, RunBackupForSourceResponse, RunBackupForSourceResponses, RunBackupRequest, RunConnectionHealthCheckData, RunConnectionHealthCheckErrors, RunConnectionHealthCheckResponse, RunConnectionHealthCheckResponses, RunExternalServiceBackupData, RunExternalServiceBackupError, RunExternalServiceBackupErrors, RunExternalServiceBackupRequest, RunExternalServiceBackupResponse, RunExternalServiceBackupResponses, RunScheduleNowData, RunScheduleNowError, RunScheduleNowErrors, RunScheduleNowResponse, RunScheduleNowResponses, S3ConnectionTestResponse, S3CredentialsResponse, S3SourceResponse, S3SourceResponseWritable, SandboxCreatePreviewLinkData, SandboxCreatePreviewLinkErrors, SandboxCreatePreviewLinkResponse, SandboxCreatePreviewLinkResponses, SandboxDomainResponse, SandboxEvent, SandboxEventsResponse, SandboxInner, SandboxResponse, SandboxRoute, SandboxStatusResponse, SaveAgentTokenData, SaveAgentTokenErrors, SaveAgentTokenRequest, SaveAgentTokenResponse, SaveAgentTokenResponse2, SaveAgentTokenResponses, SaveAiProviderCredentialData, SaveAiProviderCredentialErrors, SaveAiProviderCredentialResponse, SaveAiProviderCredentialResponses, SaveCredentialRequest, SaveCredentialResponse, ScalewayCredentialsRequest, ScanResponse, ScheduleRunEntry, ScheduleRunJobEntry, ScheduleRunListResponse, ScheduleRunResponse, ScheduleRunSummary, ScheduleRunSummaryList, ScreenshotSettings, SearchLogsData, SearchLogsError, SearchLogsErrors, SearchLogsRequest, SearchLogsResponse, SearchLogsResponse2, SearchLogsResponses, SearchMode, Seasonality, SecretResponse, SecurityConfig, SecurityHeadersConfig, SecurityHeadersSettings, SendEmailData, SendEmailErrors, SendEmailRequestBody, SendEmailResponse, SendEmailResponseBody, SendEmailResponses, SendMessageData, SendMessageErrors, SendMessageRequest, SendMessageResponses, SensitiveConfigValueResponse, SensitiveMcpConfigValueResponse, SensitiveValueResponse, SentryChunkUploadResponse, SentryCreateReleaseRequest, SentryEventRequest, SentryEventResponse, SentryReleaseFileResponse, SentryReleaseProjectRef, SentryReleaseResponse, SeriesStateEntry, ServiceAccessInfo, ServiceAction, ServiceAlertRuleResponse, ServiceBackupEntryResponse, ServiceBackupListResponse, ServiceCreateAlertRuleRequest, ServiceHealthResponse, ServiceHealthStatusBatchResponse, ServiceHealthStatusEntryResponse, ServiceMemberInfo, ServiceParameter, ServicePlan, ServiceResourceLimits, ServiceRuntimeReport, ServiceStatsReport, ServiceTypeInfo, ServiceTypeRoute, ServiceUpdateAlertRuleRequest, SesCredentialsRequest, SessionDetails, SessionDetailsQuery, SessionEvent, SessionEventDto, SessionEventsQuery, SessionEventsResponse, SessionLogsQuery, SessionLogsResponse, SessionReplayEventsRequest, SessionReplayInfoDto, SessionReplayInitRequest, SessionReplayInitResponse, SessionReplayWithEventsDto, SessionReplayWithVisitorDto, SessionRequestLog, SessionSummary, SetDefaultS3SourceData, SetDefaultS3SourceError, SetDefaultS3SourceErrors, SetDefaultS3SourceResponse, SetDefaultS3SourceResponses, SetFlagEnvironmentData, SetFlagEnvironmentErrors, SetFlagEnvironmentRequest, SetFlagEnvironmentResponse, SetFlagEnvironmentResponses, SetPreviewPasswordBody, SetPreviewPasswordData, SetPreviewPasswordErrors, SetPreviewPasswordResponse, SetPreviewPasswordResponse2, SetPreviewPasswordResponses, SetRequest, SetResponse, SettingsUpdateResponse, SetupDnsChallengeData, SetupDnsChallengeErrors, SetupDnsChallengeRequest, SetupDnsChallengeResponse, SetupDnsChallengeResponse2, SetupDnsChallengeResponses, SetupDnsData, SetupDnsErrors, SetupDnsRequest, SetupDnsResponse, SetupDnsResponse2, SetupDnsResponses, SetupEmailTrackingData, SetupEmailTrackingErrors, SetupEmailTrackingResponse, SetupEmailTrackingResponses, SetupMfaData, SetupMfaErrors, SetupMfaResponse, SetupMfaResponses, SiblingRef, SkillDefinitionResponse, SlackConfig, SleepEnvironmentData, SleepEnvironmentErrors, SleepEnvironmentResponse, SleepEnvironmentResponses, SlowQueriesResponse, SlowQueryRow, SmartFilter, SmokeTestAgentData, SmokeTestAgentErrors, SmokeTestAgentResponse, SmokeTestAgentResponses, SmokeTestResponse, SmtpCredentialsRequest, SmtpEncryptionRoute, SmtpResult, SourceArchiveUpload, SourceBackupEntry, SourceBackupIndexResponse, SourceBody, SourceFileListResponse, SourceFileResponse, SourceMapListResponse, SourceMapResponse, SourceSandboxData, SourceSandboxErrors, SourceSandboxResponse, SourceSandboxResponses, SourceType, SpanEvent, SpanKind, SpanRecord, SpanRow, SpanStatusCode, SpeedMetricsPayload, SpeedSegmentFilters, StaleSlot, StartAnalysisData, StartAnalysisErrors, StartAnalysisRequest, StartAnalysisResponse, StartAnalysisResponses, StartContainerData, StartContainerErrors, StartContainerResponse, StartContainerResponses, StartFixData, StartFixErrors, StartFixResponses, StartGitProviderOauthData, StartGitProviderOauthErrors, StartOidcLoginBySlugData, StartOidcLoginBySlugErrors, StartPgUpgradeData, StartPgUpgradeErrors, StartPgUpgradeRequest, StartPgUpgradeResponse, StartPgUpgradeResponses, StartRestoreData, StartRestoreError, StartRestoreErrors, StartRestoreRequest, StartRestoreResponse, StartRestoreResponses, StartServiceData, StartServiceErrors, StartServiceResponse, StartServiceResponses, StaticBundleResponse, StaticParams, StaticPresetConfig, StatPathData, StatPathErrors, StatPathResponse, StatPathResponses, StatResponse, StatsFilters, StatusBucket, StatusBucketedResponse, StatusCodeCount, StatusCodesQuery, StatusPageOverview, StepConversionResponse, StepResourceType, StepResult, StepUpResponse, StopContainerData, StopContainerErrors, StopContainerResponse, StopContainerResponses, StopSandboxData, StopSandboxErrors, StopSandboxResponse, StopSandboxResponses, StopSequence, StopServiceData, StopServiceErrors, StopServiceResponse, StopServiceResponses, StorageQuota, StreamContainerMetricsData, StreamContainerMetricsErrors, StreamContainerMetricsResponses, StreamEventsData, StreamEventsErrors, StreamEventsResponses, StreamRunEventsData, StreamRunEventsErrors, StreamRunEventsResponses, StripeConfig, SyncedRepositoryListQuery, SyncRepositoriesData, SyncRepositoriesErrors, SyncRepositoriesResponse, SyncRepositoriesResponses, SyntaxResult, TagInfo, TagListResponse, TailDeploymentJobLogsData, TailDeploymentJobLogsErrors, TailLogsData, TailLogsError, TailLogsErrors, TailLogsRequest, TailLogsResponses, TargetRecommendation, TeamListResponse, TeamMemberResponse, TeamResponse, TeamRole, TeardownDeploymentData, TeardownDeploymentErrors, TeardownDeploymentResponse, TeardownDeploymentResponses, TeardownEnvironmentData, TeardownEnvironmentErrors, TeardownEnvironmentResponse, TeardownEnvironmentResponses, TemplateResponse, TestEmailRequest, TestEmailResponse, TestNotificationProviderData, TestNotificationProviderErrors, TestNotificationProviderResponse, TestNotificationProviderResponses, TestOidcProviderData, TestOidcProviderResponse, TestOidcProviderResponses, TestProviderConnectionData, TestProviderConnectionErrors, TestProviderConnectionResponse, TestProviderConnectionResponses, TestProviderData, TestProviderErrors, TestProviderKeyByIdData, TestProviderKeyByIdError, TestProviderKeyByIdErrors, TestProviderKeyByIdResponse, TestProviderKeyByIdResponses, TestProviderKeyInlineData, TestProviderKeyInlineError, TestProviderKeyInlineErrors, TestProviderKeyInlineResponse, TestProviderKeyInlineResponses, TestProviderKeyRequest, TestProviderKeyResponse, TestProviderResponse, TestProviderResponse2, TestProviderResponses, TestS3ConnectionPreviewData, TestS3ConnectionPreviewError, TestS3ConnectionPreviewErrors, TestS3ConnectionPreviewResponse, TestS3ConnectionPreviewResponses, TestS3SourceConnectionData, TestS3SourceConnectionError, TestS3SourceConnectionErrors, TestS3SourceConnectionResponse, TestS3SourceConnectionResponses, TimeBucketStats, TimeBucketStatsResponse, TimeseriesBucket, TimeseriesQueryParams, TlsMode, TodayStatsResponse, ToggleDeploymentMetricsRequest, ToggleServiceMetricsRequest, TokenRenewalRequest, ToolCallEvent, ToolInfo, ToolResultEvent, TopModelsQueryParams, TraceProjectRef, TracesResponse, TraceSummariesResponse, TraceSummary, TrackClickData, TrackClickErrors, TrackedLinkResponse, TrackingEventResponse, TrackOpenData, TrackOpenErrors, TrackOpenResponses, TriggerAgentData, TriggerAgentErrors, TriggerAgentRequest, TriggerAgentResponse, TriggerAgentResponses, TriggerDigestResponse, TriggerPipelinePayload, TriggerPipelineResponse, TriggerProjectPipelineData, TriggerProjectPipelineErrors, TriggerProjectPipelineResponse, TriggerProjectPipelineResponses, TriggerScanData, TriggerScanError, TriggerScanErrors, TriggerScanRequest, TriggerScanResponse, TriggerScanResponse2, TriggerScanResponses, TriggerServiceHealthCheckData, TriggerServiceHealthCheckErrors, TriggerServiceHealthCheckResponse, TriggerServiceHealthCheckResponses, TriggerWeeklyDigestData, TriggerWeeklyDigestErrors, TriggerWeeklyDigestResponse, TriggerWeeklyDigestResponses, TtlRequest, TtlResponse, TxtRecord, UiManifest, UiRoute, UndrainNodeResponse, UnifiedTrace, UniqueCountsQuery, UniqueCountsResponse, UnlinkServiceFromProjectData, UnlinkServiceFromProjectErrors, UnlinkServiceFromProjectResponse, UnlinkServiceFromProjectResponses, UnsupportedFeature, UpdateAdminGateRequest, UpdateAgentData, UpdateAgentErrors, UpdateAgentResponse, UpdateAgentResponses, UpdateAiProviderData, UpdateAiProviderErrors, UpdateAiProviderRequest, UpdateAiProviderResponse, UpdateAiProviderResponse2, UpdateAiProviderResponses, UpdateAlertData, UpdateAlertError, UpdateAlertErrors, UpdateAlertResponse, UpdateAlertResponses, UpdateAlertRuleData, UpdateAlertRuleErrors, UpdateAlertRuleRequest, UpdateAlertRuleResponse, UpdateAlertRuleResponses, UpdateApiKeyData, UpdateApiKeyErrors, UpdateApiKeyRequest, UpdateApiKeyResponse, UpdateApiKeyResponses, UpdateAutomaticDeployData, UpdateAutomaticDeployErrors, UpdateAutomaticDeployRequest, UpdateAutomaticDeployResponse, UpdateAutomaticDeployResponses, UpdateBackupScheduleData, UpdateBackupScheduleError, UpdateBackupScheduleErrors, UpdateBackupScheduleRequest, UpdateBackupScheduleResponse, UpdateBackupScheduleResponses, UpdateBlobRequest, UpdateBlobResponse, UpdateCloudflareProviderData, UpdateCloudflareProviderErrors, UpdateCloudflareProviderRequest, UpdateCloudflareProviderResponse, UpdateCloudflareProviderResponses, UpdateConfigBody, UpdateConnectionTokenData, UpdateConnectionTokenErrors, UpdateConnectionTokenResponse, UpdateConnectionTokenResponses, UpdateCustomDomainData, UpdateCustomDomainErrors, UpdateCustomDomainRequest, UpdateCustomDomainResponse, UpdateCustomDomainResponses, UpdateDashboardData, UpdateDashboardError, UpdateDashboardErrors, UpdateDashboardRequest, UpdateDashboardResponse, UpdateDashboardResponses, UpdateDeploymentConfigRequest, UpdateDeploymentTokenData, UpdateDeploymentTokenErrors, UpdateDeploymentTokenRequest, UpdateDeploymentTokenResponse, UpdateDeploymentTokenResponses, UpdateDnsProviderRequest, UpdateEmailProviderData, UpdateEmailProviderErrors, UpdateEmailProviderRequest, UpdateEmailProviderResponse, UpdateEmailProviderResponses, UpdateEnvironmentSettingsData, UpdateEnvironmentSettingsErrors, UpdateEnvironmentSettingsRequest, UpdateEnvironmentSettingsResponse, UpdateEnvironmentSettingsResponses, UpdateEnvironmentSubdomainData, UpdateEnvironmentSubdomainErrors, UpdateEnvironmentSubdomainRequest, UpdateEnvironmentSubdomainResponse, UpdateEnvironmentSubdomainResponses, UpdateEnvironmentVariableData, UpdateEnvironmentVariableErrors, UpdateEnvironmentVariableRequest, UpdateEnvironmentVariableResponse, UpdateEnvironmentVariableResponses, UpdateErrorGroupData, UpdateErrorGroupErrors, UpdateErrorGroupRequest, UpdateErrorGroupResponses, UpdateExternalServiceRequest, UpdateFlagData, UpdateFlagErrors, UpdateFlagRequest, UpdateFlagResponse, UpdateFlagResponses, UpdateFunnelData, UpdateFunnelErrors, UpdateFunnelResponses, UpdateGitProviderCredentialsData, UpdateGitProviderCredentialsErrors, UpdateGitProviderCredentialsResponse, UpdateGitProviderCredentialsResponses, UpdateGitSettingsData, UpdateGitSettingsErrors, UpdateGitSettingsRequest, UpdateGitSettingsResponse, UpdateGitSettingsResponses, UpdateGlobalMcpData, UpdateGlobalMcpErrors, UpdateGlobalMcpResponse, UpdateGlobalMcpResponses, UpdateGlobalSkillData, UpdateGlobalSkillErrors, UpdateGlobalSkillResponse, UpdateGlobalSkillResponses, UpdateIncidentStatusData, UpdateIncidentStatusErrors, UpdateIncidentStatusRequest, UpdateIncidentStatusResponse, UpdateIncidentStatusResponses, UpdateIpAccessControlData, UpdateIpAccessControlError, UpdateIpAccessControlErrors, UpdateIpAccessControlRequest, UpdateIpAccessControlResponse, UpdateIpAccessControlResponses, UpdateKvRequest, UpdateKvResponse, UpdateManagedDomainApiRequest, UpdateManagedDomainData, UpdateManagedDomainErrors, UpdateManagedDomainResponse, UpdateManagedDomainResponses, UpdateMcpData, UpdateMcpErrors, UpdateMcpRequest, UpdateMcpResponse, UpdateMcpResponses, UpdateMemberRoleRequest, UpdateMetricAlertRequest, UpdateNotificationEmailProviderData, UpdateNotificationEmailProviderErrors, UpdateNotificationEmailProviderRequest, UpdateNotificationEmailProviderResponse, UpdateNotificationEmailProviderResponses, UpdateNotificationProviderData, UpdateNotificationProviderErrors, UpdateNotificationProviderResponse, UpdateNotificationProviderResponses, UpdateOidcProviderData, UpdateOidcProviderRequest, UpdateOidcProviderResponse, UpdateOidcProviderResponses, UpdatePreferencesData, UpdatePreferencesErrors, UpdatePreferencesRequest, UpdatePreferencesResponse, UpdatePreferencesResponses, UpdateProjectData, UpdateProjectDeploymentConfigData, UpdateProjectDeploymentConfigErrors, UpdateProjectDeploymentConfigResponse, UpdateProjectDeploymentConfigResponses, UpdateProjectErrors, UpdateProjectResponse, UpdateProjectResponses, UpdateProjectSecretData, UpdateProjectSecretErrors, UpdateProjectSecretRequest, UpdateProjectSecretResponse, UpdateProjectSecretResponses, UpdateProjectSettingsData, UpdateProjectSettingsErrors, UpdateProjectSettingsRequest, UpdateProjectSettingsResponse, UpdateProjectSettingsResponses, UpdateProviderCredentialsRequest, UpdateProviderData, UpdateProviderErrors, UpdateProviderKeyData, UpdateProviderKeyError, UpdateProviderKeyErrors, UpdateProviderKeyRequest, UpdateProviderKeyResponse, UpdateProviderKeyResponses, UpdateProviderRequest, UpdateProviderResponse, UpdateProviderResponses, UpdateRouteData, UpdateRouteErrors, UpdateRouteRequest, UpdateRouteResponse, UpdateRouteResponses, UpdateS3SourceData, UpdateS3SourceError, UpdateS3SourceErrors, UpdateS3SourceRequest, UpdateS3SourceResponse, UpdateS3SourceResponses, UpdateSecretBody, UpdateSelfData, UpdateSelfErrors, UpdateSelfRequest, UpdateSelfResponse, UpdateSelfResponses, UpdateServiceData, UpdateServiceErrors, UpdateServiceResourcesData, UpdateServiceResourcesErrors, UpdateServiceResourcesResponse, UpdateServiceResourcesResponses, UpdateServiceResponse, UpdateServiceResponses, UpdateSessionDurationData, UpdateSessionDurationError, UpdateSessionDurationErrors, UpdateSessionDurationRequest, UpdateSessionDurationResponse, UpdateSessionDurationResponse2, UpdateSessionDurationResponses, UpdateSettingsData, UpdateSettingsErrors, UpdateSettingsResponse, UpdateSettingsResponses, UpdateSkillData, UpdateSkillErrors, UpdateSkillRequest, UpdateSkillResponse, UpdateSkillResponses, UpdateSlackProviderData, UpdateSlackProviderErrors, UpdateSlackProviderRequest, UpdateSlackProviderResponse, UpdateSlackProviderResponses, UpdateSpeedMetricsData, UpdateSpeedMetricsError, UpdateSpeedMetricsErrors, UpdateSpeedMetricsPayload, UpdateSpeedMetricsResponse, UpdateSpeedMetricsResponses, UpdateStatusResponse, UpdateTeamData, UpdateTeamErrors, UpdateTeamMemberRoleData, UpdateTeamMemberRoleErrors, UpdateTeamMemberRoleResponse, UpdateTeamMemberRoleResponses, UpdateTeamRequest, UpdateTeamResponse, UpdateTeamResponses, UpdateTokenRequest, UpdateTokenResponse, UpdateUserData, UpdateUserErrors, UpdateUserRequest, UpdateUserResponse, UpdateUserResponses, UpdateWebhookData, UpdateWebhookErrors, UpdateWebhookProviderData, UpdateWebhookProviderErrors, UpdateWebhookProviderRequest, UpdateWebhookProviderResponse, UpdateWebhookProviderResponses, UpdateWebhookRequestBody, UpdateWebhookResponse, UpdateWebhookResponses, UpgradeExternalServiceRequest, UpgradePreviewGatewayData, UpgradePreviewGatewayResponse, UpgradePreviewGatewayResponses, UpgradeRequest, UpgradeServiceData, UpgradeServiceErrors, UpgradeServiceResponse, UpgradeServiceResponses, UploadGlobalSkillData, UploadGlobalSkillErrors, UploadGlobalSkillResponse, UploadGlobalSkillResponses, UploadReleaseFileData, UploadReleaseFileErrors, UploadReleaseFileResponse, UploadReleaseFileResponses, UploadSkillData, UploadSkillErrors, UploadSkillResponse, UploadSkillResponses, UploadSourceFileData, UploadSourceFileErrors, UploadSourceFileResponse, UploadSourceFileResponses, UploadSourceMapData, UploadSourceMapErrors, UploadSourceMapResponse, UploadSourceMapResponses, UploadStaticBundleData, UploadStaticBundleErrors, UploadStaticBundleResponse, UploadStaticBundleResponses, UpsertAgentRequest, UpsertSecretData, UpsertSecretErrors, UpsertSecretRequest, UpsertSecretResponse, UpsertSecretResponses, UptimeDataPoint, UptimeHistoryResponse, UsageFilter, UsageInfo, UsageLogEntry, UsageLogPage, UsageQueryParams, UsageSource, UsageSummary, UserResponse, ValidateConnectionData, ValidateConnectionErrors, ValidateConnectionResponse, ValidateConnectionResponses, ValidateEmailData, ValidateEmailErrors, ValidateEmailRequest, ValidateEmailResponse, ValidateEmailResponse2, ValidateEmailResponses, ValidationLevel, ValidationReport, ValidationResponse, ValidationResult, ValidationStatus, ValidationSummary, VerifyAndEnableMfaData, VerifyAndEnableMfaErrors, VerifyAndEnableMfaResponse, VerifyAndEnableMfaResponses, VerifyDomainData, VerifyDomainErrors, VerifyDomainResponse, VerifyDomainResponses, VerifyEmailData, VerifyEmailErrors, VerifyEmailResponse, VerifyEmailResponses, VerifyManagedDomainData, VerifyManagedDomainErrors, VerifyManagedDomainResponse, VerifyManagedDomainResponses, VerifyMfaChallengeData, VerifyMfaChallengeErrors, VerifyMfaChallengeResponse, VerifyMfaChallengeResponses, VerifyMfaRequest, VerifyStepUpData, VerifyStepUpErrors, VerifyStepUpRequest, VerifyStepUpResponse, VerifyStepUpResponses, ViewItem, ViewsOverTime, ViewsOverTimeQuery, VisitorDetails, VisitorFacets, VisitorFacetsQuery, VisitorFacetValue, VisitorInfo, VisitorJourneyQuery, VisitorJourneyResponse, VisitorLocationsQuery, VisitorRecord, VisitorSegmentFilters, VisitorSessionsQuery, VisitorSessionsResponse, VisitorsListQuery, VisitorsResponse, VisitorStats, VisitorWithGeolocation, VolumeMount, VolumeType, VulnerabilityResponse, WakeEnvironmentData, WakeEnvironmentErrors, WakeEnvironmentResponse, WakeEnvironmentResponses, WalWarning, WalWarningSeverity, WebhookConfig, WebhookDeliveryResponse, WebhookResponse, WebhookTriggerData, WebhookTriggerErrors, WebhookTriggerRequest, WebhookTriggerResponse, WebhookTriggerResponse2, WebhookTriggerResponses, WorkflowDryRunData, WorkflowDryRunErrors, WorkflowDryRunRequest, WorkflowDryRunResponse, WorkflowDryRunResponses, WorkloadDescriptor, WorkloadId, WorkloadStatus, WorkloadType, WriteFileBody, WriteFileData, WriteFileErrors, WriteFileResponse, WriteFileResponses, WriteFilesBody, WriteFilesData, WriteFilesErrors, WriteFilesResponse, WriteFilesResponse2, WriteFilesResponses, ZoneListResponse } from './types.gen'; +export { acknowledgeAlarm, activateAiProvider, activateApiKey, activateConnection, activateProvider, addClusterMember, addContext, addEnvironmentDomain, addEvents, addManagedDomain, addSessionReplayEvents, addTeamMember, adminDrainNode, adminDrainStatus, adminGetNode, adminListNodeContainers, adminListNodes, adminRemoveNode, adminUndrainNode, applyHostnameMode, archiveConversation, archiveFlag, assignRole, attachScheduleServices, blobCopy, blobDelete, blobDisable, blobDownload, blobEnable, blobHead, blobList, blobPut, blobStatus, blobUpdate, cancel, cancelBackup, cancelDeployment, cancelDomainOrder, cancelPgUpgrade, cancelRun, cancelScheduleRun, changePasswordSelf, changeProjectSource, chatCompletions, checkAnalyticsHasEvents, checkCommitExists, checkDomainStatus, checkExplorerSupport, checkIpBlocked, checkProviderDeletionSafety, chunkUploadOptions, cleanupExpiredBackups, clearPreviewPassword, cliDeviceApprove, cliDeviceDeny, cliDeviceLookup, cliDevicePoll, cliDeviceStart, cliLogout, cmd, cmdKill, cmdLogs, confirmPendingAction, containerMetricsGetHistory, createAgent, createAlert, createAlertRule, createApiKey, createBackupSchedule, createBitbucketProvider, createCloudflareProvider, createConversation, createCustomDomain, createDashboard, createDeploymentToken, createDnsProvider, createDomain, createDsn, createEmailDomain, createEmailProvider, createEnvironment, createEnvironmentVariable, createFlag, createFunnel, createGenericProvider, createGiteaPatProvider, createGithubPatProvider, createGitlabOauthProvider, createGitlabPatProvider, createGitProvider, createGlobalMcp, createGlobalSkill, createIncident, createIpAccessControl, createMcp, createMonitor, createNotificationEmailProvider, createNotificationProvider, createOidcProvider, createOidcRoleMapping, createOrRecreateOrder, createPlan, createPr, createProject, createProjectFromTemplate, createProjectRelease, createProjectSecret, createProviderKey, createRelease, createRoute, createS3Source, createSandbox, createService, createSkill, createSlackProvider, createTeam, createUser, createWebhook, createWebhookProvider, deactivateApiKey, deactivateConnection, deactivateProvider, deleteAgent, deleteAlert, deleteAlertRule, deleteApiKey, deleteBackup, deleteBackupSchedule, deleteConnection, deleteCustomDomain, deleteDashboard, deleteDeploymentToken, deleteDnsProvider, deleteDomain, deleteEmailDomain, deleteEmailProvider, deleteEnvironment, deleteEnvironmentDomain, deleteEnvironmentVariable, deleteExternalImage, deleteFunnel, deleteGitProvider, deleteGlobalMcp, deleteGlobalSkill, deleteIpAccessControl, deleteMcp, deleteMonitor, deleteNotificationProvider, deleteOidcProvider, deleteOidcRoleMapping, deletePreferences, deleteProject, deleteProjectSecret, deleteProviderKey, deleteProviderSafely, deleteReleaseSourceFiles, deleteReleaseSourceMaps, deleteRoute, deleteS3Source, deleteScan, deleteSecret, deleteService, deleteSessionReplay, deleteSkill, deleteSourceMap, deleteStaticBundle, deleteTeam, deleteUser, deleteWebhook, deployFromImage, deployFromImageUpload, deployFromStatic, deployFromUploadedSource, deploymentMetricsGetLatest, deploymentMetricsGetRange, deploymentMetricsToggle, destroySandbox, detachScheduleService, detectPublicPresets, disableBackupSchedule, disableMfa, disconnectCloud, discoverWorkloads, domain, downloadGlobalSkillArchive, downloadObject, downloadSkillArchive, emailStatus, embeddings, enableBackupSchedule, enrichVisitor, enrollCloud, exec, execDetached, executeDeploymentOperation, executeImport, extendTimeout, externalServiceEnablePgStatStatements, externalServiceMetricsByDatabase, externalServiceMetricsCreateAlertRule, externalServiceMetricsDeleteAlertRule, externalServiceMetricsGetAlertRules, externalServiceMetricsGetLatest, externalServiceMetricsGetRange, externalServiceMetricsStatus, externalServiceMetricsToggle, externalServiceMetricsUpdateAlertRule, externalServiceResetPgStatStatements, finalizeOrder, finalizeProjectRelease, findConversation, generateJoinToken, generatePresetDockerfile, getAccessInfo, getActiveVisitors, getActivityGraph, getAdminGate, getAgent, getAggregatedBuckets, getAiAgentBreakdown, getAiAgentPages, getAiAgentTimeline, getAiPageBreakdown, getAiStatusBreakdown, getAlert, getAlertRule, getAllRepositoriesByName, getAnalyticsActiveVisitors, getAnalyticsEventsCount, getAnalyticsSessionEvents, getAnalyticsVisitorSessions, getApiKey, getApiKeyPermissions, getAuditLog, getBackup, getBackupSchedule, getBranchesByRepositoryId, getBucketedIncidents, getBucketedStatus, getChallengeToken, getChatReadiness, getCliStatus, getCloudCapability, getCloudStatus, getClusterHealth, getClusterMember, getCmd, getContainerDetail, getContainerEnvironmentVariable, getContainerInfo, getContainerLogs, getContainerLogsById, getContainerMetrics, getConversation, getConversationDetail, getConversations, getCronById, getCronExecutions, getCrossProjectTraceSiblings, getCurrentMonitorStatus, getCurrentUser, getCustomDomain, getDashboard, getDashboardProjectsAnalytics, getDelivery, getDeployment, getDeploymentContainerLogContent, getDeploymentJobLogs, getDeploymentJobs, getDeploymentOperations, getDeploymentOperationStatus, getDeploymentToken, getDiskStatus, getDnsChanges, getDnsProvider, getDomain, getDomainByHost, getDomainById, getDomainByName, getDomainDnsRecords, getDomainOrder, getEmail, getEmailEvents, getEmailLinks, getEmailProvider, getEmailStats, getEmailTracking, getEmailTrackingStatus, getEntityInfo, getEnvironment, getEnvironmentCrons, getEnvironmentDomains, getEnvironments, getEnvironmentVariables, getEnvironmentVariableValue, getErrorDashboardStats, getErrorEvent, getErrorGroup, getErrorStats, getErrorTimeSeries, getEventDetail, getEventEntries, getEventsCount, getEventsTimeline, getEventTypeBreakdown, getEventVisitors, getExternalImage, getFile, getFlag, getFlagSnapshot, getFunnelMetrics, getGenaiTrace, getGeneralStats, getGitProvider, getGlobalEvents, getGlobalEventStats, getGlobalMcp, getGlobalSandboxStatus, getGlobalSkill, getGroupedPageMetrics, getHealth, getHourlyVisits, getHttpChallengeDebug, getImportStatus, getIncident, getIncidentUpdates, getIpAccessControl, getIpGeolocation, getJoinTokenStatus, getLastDeployment, getLatestScan, getLatestScansPerEnvironment, getLiveVisitorsList, getLogContext, getMcp, getMetricsOverTime, getMonitor, getNotificationProvider, getOnDemandCertStatus, getOrCreateDsn, getPageFlow, getPageHourlySessions, getPagePathDetail, getPagePaths, getPagePathsSparklines, getPagePathVisitors, getPendingAction, getPerformanceMetrics, getPgUpgrade, getPgUpgradeLogs, getPipelineStats, getPlatformInfo, getPostgresWalHealth, getPreferences, getPreviewGatewayLogs, getPreviewGatewaySettings, getPreviewGatewayStatus, getPricing, getPrivateIp, getProject, getProjectAlarmsSummary, getProjectBySlug, getProjectDeployments, getProjects, getProjectServiceEnvironmentVariables, getProjectSessionReplays, getProjectsHealth, getProjectsMonitorHealth, getProjectStatistics, getProjectTemplate, getPropertyBreakdown, getPropertyTimeline, getProviderConnections, getProviderMetadata, getProvidersMetadata, getProxyLogById, getProxyLogByRequestId, getProxyLogs, getPublicBranches, getPublicIp, getPublicRepository, getQuota, getRecentActivity, getRemoteExternalImage, getRepositoryBranches, getRepositoryById, getRepositoryByName, getRepositoryPresetByName, getRepositoryPresetLive, getRepositoryTags, getResolvedEnvironmentVariables, getResolvedEnvironmentVariableValue, getRestoreCapabilities, getRestoreRun, getRoute, getRun, getRunWithLogs, getS3Credentials, getS3Source, getSandbox, getSandboxStatus, getScan, getScanByDeployment, getScanVulnerabilities, getService, getServiceBySlug, getServiceEnvironmentVariable, getServiceEnvironmentVariables, getServiceHealthStatus, getServicePreviewEnvironmentVariableNames, getServicePreviewEnvironmentVariablesMasked, getServiceRuntime, getServiceStats, getServiceTypeParameters, getServiceTypes, getSessionDetails, getSessionEvents, getSessionLogs, getSessionReplay, getSessionReplayEvents, getSettings, getSkill, getSlowQueries, getStaticBundle, getStatusOverview, getTagsByRepositoryId, getTeam, getTimeBucketStats, getTodayStats, getTrace, getUnifiedTrace, getUniqueCounts, getUniqueEvents, getUpdateStatus, getUptimeHistory, getUsageByProvider, getUsageRecent, getUsageSummary, getUsageTimeseries, getUsageTopModels, getVisitorByGuid, getVisitorById, getVisitorDetails, getVisitorFacets, getVisitorInfo, getVisitorJourney, getVisitors, getVisitorSessions, getVisitorStats, getWebhook, grantProjectAccess, handleGitProviderOauthCallback, hasAnalyticsEvents, hasErrorGroups, hasPerformanceMetrics, importExternalService, ingestLogs, ingestLogsByPath, ingestMetrics, ingestMetricsByPath, ingestSentryEnvelope, ingestSentryEvent, ingestTraces, ingestTracesByPath, initSessionReplay, inspectDropArchive, jobLogs, jobStatus, killJob, kvDel, kvDisable, kvEnable, kvExpire, kvGet, kvIncr, kvKeys, kvSet, kvStatus, kvTtl, kvUpdate, latestRunForSource, linkCustomDomainToCertificate, linkServiceToProject, listAgentRuns, listAgents, listAiProviders, listAlertRules, listAlerts, listAllConversations, listAllRuns, listApiKeys, listAuditLogs, listAvailableContainers, listBackupAlerts, listBackupChildren, listBackupSchedules, listBackupsForSchedule, listCommitsByRepositoryId, listConnections, listContainers, listContainersAtPath, listConversations, listCustomDomainsForProject, listDashboards, listDeliveries, listDeploymentContainerLogs, listDeploymentTokens, listDnsProviders, listDomains, listDsns, listEmailDomains, listEmailProviders, listEmails, listEnrollmentTokens, listEntities, listErrorEvents, listErrorGroups, listEvents, listEventTypes, listExternalImages, listExternalPlugins, listExternalServiceBackups, listFlags, listFunnels, listGitProviders, listGlobalMcps, listGlobalSkills, listIncidents, listInsights, listIpAccessControl, listJobs, listKnownAiAgents, listManagedDomains, listMcps, listMetricLabelKeys, listMetricLabelValues, listMetricNames, listModels, listMonitors, listNotificationProviders, listOidcProviders, listOidcProviderUsers, listOidcRoleMappings, listOnDemandCerts, listOrders, listPeers, listPendingActions, listPgUpgrades, listPresets, listProjectAccess, listProjectAlarms, listProjectScans, listProjectSecrets, listProjectServices, listProjectTemplates, listProjectTemplateTags, listProviderKeys, listProviderZones, listPublicProviders, listReleaseFiles, listReleases, listRemoteExternalImages, listRepositoriesByConnection, listRepositoriesByProvider, listRestoreRunsForService, listRootContainers, listRoutes, listS3Sources, listSandboxes, listScheduleRunJobs, listScheduleRuns, listScheduleServices, listSecrets, listServiceHealthStatuses, listServiceProjects, listServices, listServiceSchedules, listSkills, listSourceBackups, listSourceFiles, listSourceMaps, listSources, listStaticBundles, listSyncedRepositories, listTeamMembers, listTeamProjects, listTeams, listUsers, listWebhooks, login, logout, lookupDnsARecords, mintEnrollmentToken, mkdir, nodeHeartbeat, nodeMetricsGetRange, observabilityFullEvent, observabilityListEvents, oidcCallback, type Options, patchAdminGate, patchPreviewGatewaySettings, pauseDeployment, pauseSandbox, planRestore, postDnsAck, previewAlert, previewFunnelMetrics, previewHostnameMode, promoteClusterMember, promoteDeployment, provisionDomain, purgeProjectLogs, pushExternalImage, queryData, queryGenaiTraces, queryLogs, queryMetrics, queryTraces, queryTraceSummaries, readFile, reAnalyze, rebuildSandboxImage, recordConsoleEvent, recordEventMetrics, recordFlagExposure, recordSpeedMetrics, refreshRouteTable, regenerateDsn, registerExternalImage, registerNode, reinstallGitlabWebhook, rejectPendingAction, reloadPlugins, removeClusterMember, removeManagedDomain, removeRole, removeTeamMember, renameConversation, renewDomain, requestPasswordReset, resetPassword, resizeSandbox, resolveAlarm, restartContainer, restartPreviewGateway, restartSandbox, restoreFlag, restoreUser, resumeDeployment, resumeSandbox, retryCluster, retryDelivery, retryPgUpgrade, retryRun, revealGlobalMcpConfig, revealMcpConfig, revealNotificationProviderConfig, revealServiceParameter, revenueCreateIntegration, revenueDeleteIntegration, revenueGlobalEvents, revenueImportInvoicesCsv, revenueImportSubscriptionsCsv, revenueListIntegrations, revenueListProviders, revenueMetricsCustomers, revenueMetricsGlobalMrr, revenueMetricsGlobalSummary, revenueMetricsMrr, revenueMetricsSummary, revenueRecentEvents, revenueRotateToken, revenueUpdateConfig, revenueUpdateSecret, revokeDsn, revokeEnrollmentToken, revokeJoinToken, revokeProjectAccess, rollbackPgUpgrade, rollbackToDeployment, rootfsGc, rootfsReport, rotateApiKey, rotateDeploymentToken, runBackupForSource, runConnectionHealthCheck, runExternalServiceBackup, runScheduleNow, sandboxCreatePreviewLink, saveAgentToken, saveAiProviderCredential, searchLogs, sendEmail, sendMessage, setDefaultS3Source, setFlagEnvironment, setPreviewPassword, setupDns, setupDnsChallenge, setupEmailTracking, setupMfa, sleepEnvironment, smokeTestAgent, sourceSandbox, startAnalysis, startContainer, startFix, startGitProviderOauth, startOidcLoginBySlug, startPgUpgrade, startRestore, startService, statPath, stopContainer, stopSandbox, stopService, streamContainerMetrics, streamEvents, streamRunEvents, syncRepositories, tailDeploymentJobLogs, tailLogs, teardownDeployment, teardownEnvironment, testNotificationProvider, testOidcProvider, testProvider, testProviderConnection, testProviderKeyById, testProviderKeyInline, testS3ConnectionPreview, testS3SourceConnection, trackClick, trackOpen, triggerAgent, triggerProjectPipeline, triggerScan, triggerServiceHealthCheck, triggerWeeklyDigest, unlinkServiceFromProject, updateAgent, updateAiProvider, updateAlert, updateAlertRule, updateApiKey, updateAutomaticDeploy, updateBackupSchedule, updateCloudflareProvider, updateConnectionToken, updateCustomDomain, updateDashboard, updateDeploymentToken, updateEmailProvider, updateEnvironmentSettings, updateEnvironmentSubdomain, updateEnvironmentVariable, updateErrorGroup, updateFlag, updateFunnel, updateGitProviderCredentials, updateGitSettings, updateGlobalMcp, updateGlobalSkill, updateIncidentStatus, updateIpAccessControl, updateManagedDomain, updateMcp, updateNotificationEmailProvider, updateNotificationProvider, updateOidcProvider, updatePreferences, updateProject, updateProjectDeploymentConfig, updateProjectSecret, updateProjectSettings, updateProvider, updateProviderKey, updateRoute, updateS3Source, updateSelf, updateService, updateServiceResources, updateSessionDuration, updateSettings, updateSkill, updateSlackProvider, updateSpeedMetrics, updateTeam, updateTeamMemberRole, updateUser, updateWebhook, updateWebhookProvider, upgradePreviewGateway, upgradeService, uploadGlobalSkill, uploadReleaseFile, uploadSkill, uploadSourceFile, uploadSourceMap, uploadStaticBundle, upsertSecret, validateConnection, validateEmail, verifyAndEnableMfa, verifyDomain, verifyEmail, verifyManagedDomain, verifyMfaChallenge, verifyStepUp, wakeEnvironment, webhookTrigger, workflowDryRun, writeFile, writeFiles } from './sdk.gen'; +export type { AcknowledgeAlarmData, AcknowledgeAlarmErrors, AcknowledgeAlarmResponses, AcmeOrderResponse, ActivateAiProviderData, ActivateAiProviderErrors, ActivateAiProviderResponse, ActivateAiProviderResponses, ActivateApiKeyData, ActivateApiKeyErrors, ActivateApiKeyResponse, ActivateApiKeyResponses, ActivateConnectionData, ActivateConnectionErrors, ActivateConnectionResponses, ActivateProviderData, ActivateProviderErrors, ActivateProviderResponse, ActivateProviderResponses, ActiveVisitor, ActiveVisitorsQuery, ActiveVisitorsResponse, ActivityDay, ActivityEvent, ActivityGraphQuery, ActivityGraphResponse, AddClusterMemberData, AddClusterMemberErrors, AddClusterMemberRequest, AddClusterMemberResponse, AddClusterMemberResponses, AddContextData, AddContextErrors, AddContextRequest, AddContextResponses, AddEnvironmentDomainData, AddEnvironmentDomainErrors, AddEnvironmentDomainRequest, AddEnvironmentDomainResponse, AddEnvironmentDomainResponses, AddEventsData, AddEventsError, AddEventsErrors, AddEventsRequest, AddEventsResponse, AddEventsResponse2, AddEventsResponses, AddManagedDomainApiRequest, AddManagedDomainData, AddManagedDomainErrors, AddManagedDomainResponse, AddManagedDomainResponses, AddSessionReplayEventsData, AddSessionReplayEventsError, AddSessionReplayEventsErrors, AddSessionReplayEventsResponse, AddSessionReplayEventsResponses, AddTeamMemberData, AddTeamMemberErrors, AddTeamMemberResponse, AddTeamMemberResponses, AdminDrainNodeData, AdminDrainNodeErrors, AdminDrainNodeResponse, AdminDrainNodeResponses, AdminDrainStatusData, AdminDrainStatusErrors, AdminDrainStatusResponse, AdminDrainStatusResponses, AdminGateResponse, AdminGateSource, AdminGetNodeData, AdminGetNodeErrors, AdminGetNodeResponse, AdminGetNodeResponses, AdminListNodeContainersData, AdminListNodeContainersErrors, AdminListNodeContainersResponse, AdminListNodeContainersResponses, AdminListNodesData, AdminListNodesErrors, AdminListNodesResponse, AdminListNodesResponses, AdminRemoveNodeData, AdminRemoveNodeErrors, AdminRemoveNodeResponse, AdminRemoveNodeResponses, AdminUndrainNodeData, AdminUndrainNodeErrors, AdminUndrainNodeResponse, AdminUndrainNodeResponses, AgentConfigResponse, AgentRunLogResponse, AgentRunResponse, AgentRunWithLogsResponse, AgentSandboxSettings, AgentSandboxSettingsMasked, AggregatedBucketItem, AggregatedBucketsQuery, AggregatedBucketsResponse, AggregationLevel, AggregationTemporality, AiAgentBreakdownResponse, AiAgentBreakdownRow, AiAgentDescriptor, AiAgentPageRow, AiAgentPagesResponse, AiAgentTimelineResponse, AiAgentTimelineRow, AiChatLimitsSettings, AiConfigSettings, AiPageBreakdownResponse, AiPageBreakdownRow, AiStatusBreakdownResponse, AiStatusBreakdownRow, AlarmListResponse, AlarmResponse, AlarmSummaryResponse, AlertRuleResponse, AllocEntry, AnalyticsSessionEventsResponse, AnnotatedSpan, AnomalyAlgorithm, AnomalyParams, AnomalyPreviewPointResponse, AnomalyPreviewRequest, AnomalyPreviewResponse, ApiKeyListResponse, ApiKeyResponse, ApplyHostnameModeData, ApplyHostnameModeErrors, ApplyHostnameModeRequest, ApplyHostnameModeResponse, ApplyHostnameModeResponses, AppSettings, AppSettingsResponse, ArchiveConversationData, ArchiveConversationErrors, ArchiveConversationResponse, ArchiveConversationResponses, ArchiveFlagData, ArchiveFlagErrors, ArchiveFlagResponse, ArchiveFlagResponse2, ArchiveFlagResponses, ArchiveMode, AssignRoleData, AssignRoleErrors, AssignRoleRequest, AssignRoleResponses, AttachScheduleServicesData, AttachScheduleServicesError, AttachScheduleServicesErrors, AttachScheduleServicesRequest, AttachScheduleServicesResponse, AttachScheduleServicesResponse2, AttachScheduleServicesResponses, AuditLogIpInfo, AuditLogResponse, AuditLogUserInfo, AuthFlavorDto, AuthResponse, AuthStatusResponse, AuthTokenResponse, AutofixerRunResponse, AutofixerRunWithLogsResponse, AutofixRunConfig, AutoWatchParams, AvailableContainerInfo, AvailablePermissions, BackupAlertListResponse, BackupAlertResponse, BackupResponse, BackupScheduleResponse, BitbucketAuthInput, BlobCopyData, BlobCopyError, BlobCopyErrors, BlobCopyResponse, BlobCopyResponses, BlobDeleteData, BlobDeleteError, BlobDeleteErrors, BlobDeleteResponse, BlobDeleteResponses, BlobDisableData, BlobDisableErrors, BlobDisableResponse, BlobDisableResponses, BlobDownloadData, BlobDownloadError, BlobDownloadErrors, BlobDownloadResponses, BlobEnableData, BlobEnableErrors, BlobEnableResponse, BlobEnableResponses, BlobHeadData, BlobHeadError, BlobHeadErrors, BlobHeadResponses, BlobListData, BlobListError, BlobListErrors, BlobListResponse, BlobListResponses, BlobPutData, BlobPutError, BlobPutErrors, BlobPutResponse, BlobPutResponses, BlobResponse, BlobStatusData, BlobStatusErrors, BlobStatusResponse, BlobStatusResponse2, BlobStatusResponses, BlobUpdateData, BlobUpdateErrors, BlobUpdateResponse, BlobUpdateResponses, BranchInfo, BranchListResponse, BrowserCount, BrowsersQuery, BuildConfiguration, BuildLimitsSettings, CancelBackupData, CancelBackupError, CancelBackupErrors, CancelBackupResponse, CancelBackupResponse2, CancelBackupResponses, CancelData, CancelDeploymentData, CancelDeploymentErrors, CancelDeploymentResponse, CancelDeploymentResponses, CancelDomainOrderData, CancelDomainOrderErrors, CancelDomainOrderResponse, CancelDomainOrderResponses, CancelErrors, CancelPgUpgradeData, CancelPgUpgradeErrors, CancelPgUpgradeResponse, CancelPgUpgradeResponses, CancelResponses, CancelRunData, CancelRunErrors, CancelRunResponse, CancelRunResponses, CancelScheduleRunData, CancelScheduleRunError, CancelScheduleRunErrors, CancelScheduleRunResponse, CancelScheduleRunResponses, CertStatusResponse, ChallengeConfig, ChallengeError, ChallengeValidationStatus, ChangePasswordRequest, ChangePasswordSelfData, ChangePasswordSelfErrors, ChangePasswordSelfResponse, ChangePasswordSelfResponses, ChangeProjectSourceData, ChangeProjectSourceErrors, ChangeProjectSourceRequest, ChangeProjectSourceResponse, ChangeProjectSourceResponses, ChatCompletionChoice, ChatCompletionRequest, ChatCompletionResponse, ChatCompletionsData, ChatCompletionsError, ChatCompletionsErrors, ChatCompletionsResponse, ChatCompletionsResponses, ChatMessage, ChatReadinessResponse, CheckAnalyticsHasEventsData, CheckAnalyticsHasEventsErrors, CheckAnalyticsHasEventsResponse, CheckAnalyticsHasEventsResponses, CheckCommitExistsData, CheckCommitExistsErrors, CheckCommitExistsResponse, CheckCommitExistsResponses, CheckDomainStatusData, CheckDomainStatusErrors, CheckDomainStatusResponse, CheckDomainStatusResponses, CheckExplorerSupportData, CheckExplorerSupportErrors, CheckExplorerSupportResponse, CheckExplorerSupportResponses, CheckIpBlockedData, CheckIpBlockedError, CheckIpBlockedErrors, CheckIpBlockedResponses, CheckProviderDeletionSafetyData, CheckProviderDeletionSafetyErrors, CheckProviderDeletionSafetyResponse, CheckProviderDeletionSafetyResponses, ChildBackupEntryResponse, ChildBackupListResponse, ChunkUploadOptionsData, ChunkUploadOptionsResponse, ChunkUploadOptionsResponses, CleanupExpiredBackupsData, CleanupExpiredBackupsError, CleanupExpiredBackupsErrors, CleanupExpiredBackupsRequest, CleanupExpiredBackupsResponse, CleanupExpiredBackupsResponses, ClearPreviewPasswordData, ClearPreviewPasswordErrors, ClearPreviewPasswordResponse, ClearPreviewPasswordResponses, CliDeviceApproveData, CliDeviceApproveErrors, CliDeviceApproveRequest, CliDeviceApproveResponse, CliDeviceApproveResponse2, CliDeviceApproveResponses, CliDeviceDenyData, CliDeviceDenyErrors, CliDeviceDenyResponse, CliDeviceDenyResponses, CliDeviceLookupData, CliDeviceLookupErrors, CliDeviceLookupResponse, CliDeviceLookupResponse2, CliDeviceLookupResponses, CliDevicePollData, CliDevicePollErrors, CliDevicePollRequest, CliDevicePollResponse, CliDevicePollResponse2, CliDevicePollResponses, CliDeviceStartData, CliDeviceStartErrors, CliDeviceStartRequest, CliDeviceStartResponse, CliDeviceStartResponse2, CliDeviceStartResponses, ClientOptions, CliLoginRequest, CliLogoutData, CliLogoutErrors, CliLogoutResponse, CliLogoutResponses, CloudCapability, CloudflareConfig, CloudProvider, CloudSettings, CloudStatus, ClusterCapacity, ClusterDnsSettings, ClusterHealthReportResponse, ClusterMemberHealthResponse, ClusterMemberRequest, CmdBody, CmdData, CmdErrors, CmdInner, CmdKillBody, CmdKillData, CmdKillErrors, CmdKillResponse, CmdKillResponses, CmdLogsData, CmdLogsErrors, CmdLogsResponses, CmdResponse, CmdResponse2, CmdResponses, CommitExistsResponse, CommitInfo, CommitListResponse, Comparator, ComposePublicPort, ConfirmPendingActionData, ConfirmPendingActionErrors, ConfirmPendingActionResponse, ConfirmPendingActionResponses, ConnectionListQuery, ConnectionListResponse, ConnectionResponse, ConnectionTestResult, ConsoleEventPayload, ContainerActionResponse, ContainerDetailResponse, ContainerEnvironmentVariableValueResponse, ContainerInfoResponse, ContainerInventoryItem, ContainerListResponse, ContainerLogSettings, ContainerLogsQuery, ContainerMetricHistoryPoint, ContainerMetricsGetHistoryData, ContainerMetricsGetHistoryErrors, ContainerMetricsGetHistoryResponse, ContainerMetricsGetHistoryResponses, ContainerMetricsHistoryQuery, ContainerMetricsResponse, ContainerResponse, ContainerRuntimeInfo, ContainerStatsSample, ContentPart, ContextLine, ContextLogsRequest, ContextLogsResponse, ConversationDetailResponse, ConversationResponse, ConversationsQueryParams, ConversationSummary, CopyBlobRequest, CostAnalysis, CreateAgentData, CreateAgentErrors, CreateAgentResponse, CreateAgentResponses, CreateAlertData, CreateAlertError, CreateAlertErrors, CreateAlertResponse, CreateAlertResponses, CreateAlertRuleData, CreateAlertRuleErrors, CreateAlertRuleRequest, CreateAlertRuleResponse, CreateAlertRuleResponses, CreateApiKeyData, CreateApiKeyErrors, CreateApiKeyRequest, CreateApiKeyResponse, CreateApiKeyResponse2, CreateApiKeyResponses, CreateBackupScheduleData, CreateBackupScheduleError, CreateBackupScheduleErrors, CreateBackupScheduleRequest, CreateBackupScheduleResponse, CreateBackupScheduleResponses, CreateBitbucketProviderData, CreateBitbucketProviderErrors, CreateBitbucketProviderResponse, CreateBitbucketProviderResponses, CreateBitbucketRequest, CreateCloudflareProviderData, CreateCloudflareProviderErrors, CreateCloudflareProviderRequest, CreateCloudflareProviderResponse, CreateCloudflareProviderResponses, CreateConversationData, CreateConversationErrors, CreateConversationRequest, CreateConversationResponse, CreateConversationResponses, CreateCustomDomainData, CreateCustomDomainErrors, CreateCustomDomainResponse, CreateCustomDomainResponses, CreateDashboardData, CreateDashboardError, CreateDashboardErrors, CreateDashboardRequest, CreateDashboardResponse, CreateDashboardResponses, CreateDeploymentTokenData, CreateDeploymentTokenErrors, CreateDeploymentTokenRequest, CreateDeploymentTokenResponse, CreateDeploymentTokenResponse2, CreateDeploymentTokenResponses, CreateDnsProviderData, CreateDnsProviderErrors, CreateDnsProviderRequest, CreateDnsProviderResponse, CreateDnsProviderResponses, CreateDomainData, CreateDomainErrors, CreateDomainRequest, CreateDomainResponse, CreateDomainResponses, CreatedResource, CreateDsnData, CreateDsnErrors, CreateDsnRequest, CreateDsnResponse, CreateDsnResponses, CreateEmailDomainData, CreateEmailDomainErrors, CreateEmailDomainRequest, CreateEmailDomainResponse, CreateEmailDomainResponses, CreateEmailProviderData, CreateEmailProviderErrors, CreateEmailProviderRequest, CreateEmailProviderResponse, CreateEmailProviderResponses, CreateEnvironmentData, CreateEnvironmentErrors, CreateEnvironmentRequest, CreateEnvironmentResponse, CreateEnvironmentResponses, CreateEnvironmentVariableData, CreateEnvironmentVariableErrors, CreateEnvironmentVariableRequest, CreateEnvironmentVariableResponse, CreateEnvironmentVariableResponses, CreateExternalServiceRequest, CreateFlagData, CreateFlagErrors, CreateFlagRequest, CreateFlagResponse, CreateFlagResponses, CreateFunnelData, CreateFunnelErrors, CreateFunnelRequest, CreateFunnelResponse, CreateFunnelResponse2, CreateFunnelResponses, CreateFunnelStep, CreateGenericProviderData, CreateGenericProviderErrors, CreateGenericProviderResponse, CreateGenericProviderResponses, CreateGenericRequest, CreateGiteaPatProviderData, CreateGiteaPatProviderErrors, CreateGiteaPatProviderResponse, CreateGiteaPatProviderResponses, CreateGiteaPatRequest, CreateGithubPatProviderData, CreateGithubPatProviderErrors, CreateGithubPatProviderResponse, CreateGithubPatProviderResponses, CreateGitHubPatRequest, CreateGitlabOauthProviderData, CreateGitlabOauthProviderErrors, CreateGitlabOauthProviderResponse, CreateGitlabOauthProviderResponses, CreateGitLabOAuthRequest, CreateGitlabPatProviderData, CreateGitlabPatProviderErrors, CreateGitlabPatProviderResponse, CreateGitlabPatProviderResponses, CreateGitLabPatRequest, CreateGitProviderData, CreateGitProviderErrors, CreateGitProviderResponse, CreateGitProviderResponses, CreateGlobalMcpData, CreateGlobalMcpErrors, CreateGlobalMcpResponse, CreateGlobalMcpResponses, CreateGlobalSkillData, CreateGlobalSkillErrors, CreateGlobalSkillResponse, CreateGlobalSkillResponses, CreateIncidentData, CreateIncidentErrors, CreateIncidentRequest, CreateIncidentResponse, CreateIncidentResponses, CreateIntegrationBody, CreateIpAccessControlData, CreateIpAccessControlError, CreateIpAccessControlErrors, CreateIpAccessControlRequest, CreateIpAccessControlResponse, CreateIpAccessControlResponses, CreateMcpData, CreateMcpErrors, CreateMcpRequest, CreateMcpResponse, CreateMcpResponses, CreateMetricAlertRequest, CreateMonitorData, CreateMonitorErrors, CreateMonitorRequest, CreateMonitorResponse, CreateMonitorResponses, CreateNotificationEmailProviderData, CreateNotificationEmailProviderErrors, CreateNotificationEmailProviderRequest, CreateNotificationEmailProviderResponse, CreateNotificationEmailProviderResponses, CreateNotificationProviderData, CreateNotificationProviderErrors, CreateNotificationProviderResponse, CreateNotificationProviderResponses, CreateOidcProviderData, CreateOidcProviderErrors, CreateOidcProviderRequest, CreateOidcProviderResponse, CreateOidcProviderResponses, CreateOidcRoleMappingData, CreateOidcRoleMappingRequest, CreateOidcRoleMappingResponse, CreateOidcRoleMappingResponses, CreateOrRecreateOrderData, CreateOrRecreateOrderErrors, CreateOrRecreateOrderResponse, CreateOrRecreateOrderResponses, CreatePlanData, CreatePlanErrors, CreatePlanRequest, CreatePlanResponse, CreatePlanResponse2, CreatePlanResponses, CreatePrData, CreatePrErrors, CreateProjectAccessRequest, CreateProjectData, CreateProjectErrors, CreateProjectFromTemplateData, CreateProjectFromTemplateErrors, CreateProjectFromTemplateRequest, CreateProjectFromTemplateResponse, CreateProjectFromTemplateResponse2, CreateProjectFromTemplateResponses, CreateProjectReleaseData, CreateProjectReleaseErrors, CreateProjectReleaseResponse, CreateProjectReleaseResponses, CreateProjectRequest, CreateProjectResponse, CreateProjectResponses, CreateProjectSecretData, CreateProjectSecretErrors, CreateProjectSecretRequest, CreateProjectSecretResponse, CreateProjectSecretResponses, CreateProviderKeyData, CreateProviderKeyError, CreateProviderKeyErrors, CreateProviderKeyRequest, CreateProviderKeyResponse, CreateProviderKeyResponses, CreateProviderRequest, CreatePrResponse, CreatePrResponse2, CreatePrResponses, CreateReleaseData, CreateReleaseErrors, CreateReleaseResponse, CreateReleaseResponses, CreateRouteData, CreateRouteErrors, CreateRouteRequest, CreateRouteResponse, CreateRouteResponses, CreateS3SourceData, CreateS3SourceError, CreateS3SourceErrors, CreateS3SourceRequest, CreateS3SourceResponse, CreateS3SourceResponses, CreateSandboxBody, CreateSandboxData, CreateSandboxErrors, CreateSandboxResponse, CreateSandboxResponses, CreateServiceData, CreateServiceErrors, CreateServiceResponse, CreateServiceResponses, CreateSkillData, CreateSkillErrors, CreateSkillRequest, CreateSkillResponse, CreateSkillResponses, CreateSlackProviderData, CreateSlackProviderErrors, CreateSlackProviderRequest, CreateSlackProviderResponse, CreateSlackProviderResponses, CreateTeamData, CreateTeamErrors, CreateTeamMemberRequest, CreateTeamRequest, CreateTeamResponse, CreateTeamResponses, CreateUserData, CreateUserErrors, CreateUserRequest, CreateUserResponse, CreateUserResponses, CreateWebhookData, CreateWebhookErrors, CreateWebhookProviderData, CreateWebhookProviderErrors, CreateWebhookProviderRequest, CreateWebhookProviderResponse, CreateWebhookProviderResponses, CreateWebhookRequestBody, CreateWebhookResponse, CreateWebhookResponses, CronExecutionInfo, CronInfo, CrossProjectSiblingRef, CrossProjectTraceResponse, CurrentStatusResponse, CustomDomainRequest, CustomDomainResponse, CustomerMovementResponse, DashboardLayout, DashboardProjectsAnalyticsQuery, DashboardProjectsAnalyticsResponse, DashboardSection, DashboardTile, DatabaseMetricsResponse, DatabaseMetricsRow, DataImplication, DataImplicationSeverity, DeactivateApiKeyData, DeactivateApiKeyErrors, DeactivateApiKeyResponse, DeactivateApiKeyResponses, DeactivateConnectionData, DeactivateConnectionErrors, DeactivateConnectionResponses, DeactivateProviderData, DeactivateProviderErrors, DeactivateProviderResponses, DeleteAgentData, DeleteAgentErrors, DeleteAgentResponse, DeleteAgentResponses, DeleteAlertData, DeleteAlertError, DeleteAlertErrors, DeleteAlertResponse, DeleteAlertResponses, DeleteAlertRuleData, DeleteAlertRuleErrors, DeleteAlertRuleResponse, DeleteAlertRuleResponses, DeleteApiKeyData, DeleteApiKeyErrors, DeleteApiKeyResponse, DeleteApiKeyResponses, DeleteBackupData, DeleteBackupError, DeleteBackupErrors, DeleteBackupResponse, DeleteBackupResponses, DeleteBackupScheduleData, DeleteBackupScheduleError, DeleteBackupScheduleErrors, DeleteBackupScheduleResponse, DeleteBackupScheduleResponses, DeleteBlobRequest, DeleteBlobResponse, DeleteConnectionData, DeleteConnectionErrors, DeleteConnectionResponse, DeleteConnectionResponses, DeleteCustomDomainData, DeleteCustomDomainErrors, DeleteCustomDomainResponse, DeleteCustomDomainResponses, DeleteDashboardData, DeleteDashboardError, DeleteDashboardErrors, DeleteDashboardResponse, DeleteDashboardResponses, DeleteDeploymentTokenData, DeleteDeploymentTokenErrors, DeleteDeploymentTokenResponse, DeleteDeploymentTokenResponses, DeleteDnsProviderData, DeleteDnsProviderErrors, DeleteDnsProviderResponse, DeleteDnsProviderResponses, DeleteDomainData, DeleteDomainErrors, DeleteDomainResponse, DeleteDomainResponses, DeleteEmailDomainData, DeleteEmailDomainErrors, DeleteEmailDomainResponse, DeleteEmailDomainResponses, DeleteEmailProviderData, DeleteEmailProviderErrors, DeleteEmailProviderResponse, DeleteEmailProviderResponses, DeleteEnvironmentData, DeleteEnvironmentDomainData, DeleteEnvironmentDomainErrors, DeleteEnvironmentDomainResponse, DeleteEnvironmentDomainResponses, DeleteEnvironmentErrors, DeleteEnvironmentResponse, DeleteEnvironmentResponses, DeleteEnvironmentVariableData, DeleteEnvironmentVariableErrors, DeleteEnvironmentVariableResponse, DeleteEnvironmentVariableResponses, DeleteExternalImageData, DeleteExternalImageErrors, DeleteExternalImageResponse, DeleteExternalImageResponses, DeleteFunnelData, DeleteFunnelErrors, DeleteFunnelResponses, DeleteGitProviderData, DeleteGitProviderErrors, DeleteGitProviderResponse, DeleteGitProviderResponses, DeleteGlobalMcpData, DeleteGlobalMcpErrors, DeleteGlobalMcpResponse, DeleteGlobalMcpResponses, DeleteGlobalSkillData, DeleteGlobalSkillErrors, DeleteGlobalSkillResponse, DeleteGlobalSkillResponses, DeleteIpAccessControlData, DeleteIpAccessControlError, DeleteIpAccessControlErrors, DeleteIpAccessControlResponse, DeleteIpAccessControlResponses, DeleteMcpData, DeleteMcpErrors, DeleteMcpResponse, DeleteMcpResponses, DeleteMonitorData, DeleteMonitorErrors, DeleteMonitorResponse, DeleteMonitorResponses, DeleteNotificationProviderData, DeleteNotificationProviderErrors, DeleteNotificationProviderResponse, DeleteNotificationProviderResponses, DeleteOidcProviderData, DeleteOidcProviderResponse, DeleteOidcProviderResponses, DeleteOidcRoleMappingData, DeleteOidcRoleMappingResponse, DeleteOidcRoleMappingResponses, DeletePreferencesData, DeletePreferencesErrors, DeletePreferencesResponse, DeletePreferencesResponses, DeleteProjectData, DeleteProjectErrors, DeleteProjectResponse, DeleteProjectResponses, DeleteProjectSecretData, DeleteProjectSecretErrors, DeleteProjectSecretResponse, DeleteProjectSecretResponses, DeleteProviderKeyData, DeleteProviderKeyError, DeleteProviderKeyErrors, DeleteProviderKeyResponse, DeleteProviderKeyResponses, DeleteProviderSafelyData, DeleteProviderSafelyErrors, DeleteProviderSafelyResponse, DeleteProviderSafelyResponses, DeleteReleaseSourceFilesData, DeleteReleaseSourceFilesErrors, DeleteReleaseSourceFilesResponse, DeleteReleaseSourceFilesResponses, DeleteReleaseSourceMapsData, DeleteReleaseSourceMapsErrors, DeleteReleaseSourceMapsResponse, DeleteReleaseSourceMapsResponses, DeleteResponse, DeleteRouteData, DeleteRouteErrors, DeleteRouteResponse, DeleteRouteResponses, DeleteS3SourceData, DeleteS3SourceError, DeleteS3SourceErrors, DeleteS3SourceResponse, DeleteS3SourceResponses, DeleteScanData, DeleteScanError, DeleteScanErrors, DeleteScanResponse, DeleteScanResponses, DeleteSecretData, DeleteSecretErrors, DeleteSecretResponse, DeleteSecretResponses, DeleteServiceData, DeleteServiceErrors, DeleteServiceResponse, DeleteServiceResponses, DeleteSessionReplayData, DeleteSessionReplayError, DeleteSessionReplayErrors, DeleteSessionReplayResponses, DeleteSkillData, DeleteSkillErrors, DeleteSkillResponse, DeleteSkillResponses, DeleteSourceMapData, DeleteSourceMapErrors, DeleteSourceMapResponse, DeleteSourceMapResponses, DeleteStaticBundleData, DeleteStaticBundleErrors, DeleteStaticBundleResponse, DeleteStaticBundleResponses, DeleteTeamData, DeleteTeamErrors, DeleteTeamResponse, DeleteTeamResponses, DeleteUserData, DeleteUserErrors, DeleteUserResponse, DeleteUserResponses, DeleteWebhookData, DeleteWebhookErrors, DeleteWebhookResponse, DeleteWebhookResponses, DelRequest, DelResponse, DeployFromImageData, DeployFromImageErrors, DeployFromImageRequest, DeployFromImageResponse, DeployFromImageResponses, DeployFromImageUploadData, DeployFromImageUploadErrors, DeployFromImageUploadQuery, DeployFromImageUploadResponse, DeployFromImageUploadResponses, DeployFromStaticData, DeployFromStaticErrors, DeployFromStaticRequest, DeployFromStaticResponse, DeployFromStaticResponses, DeployFromUploadedSourceData, DeployFromUploadedSourceErrors, DeployFromUploadedSourceResponse, DeployFromUploadedSourceResponses, DeploymentConfig, DeploymentConfigSnapshot, DeploymentConfiguration, DeploymentContainerLogContentResponse, DeploymentContainerLogResponse, DeploymentContainerLogsListResponse, DeploymentEnvironmentResponse, DeploymentJobResponse, DeploymentJobsResponse, DeploymentListResponse, DeploymentMetadata, DeploymentMetricsGetLatestData, DeploymentMetricsGetLatestErrors, DeploymentMetricsGetLatestResponse, DeploymentMetricsGetLatestResponses, DeploymentMetricsGetRangeData, DeploymentMetricsGetRangeErrors, DeploymentMetricsGetRangeResponse, DeploymentMetricsGetRangeResponses, DeploymentMetricsToggleData, DeploymentMetricsToggleErrors, DeploymentMetricsToggleResponses, DeploymentResponse, DeploymentStateResponse, DeploymentStrategy, DeploymentTokenListResponse, DeploymentTokenResponse, DestroySandboxData, DestroySandboxErrors, DestroySandboxResponse, DestroySandboxResponses, DetachScheduleServiceData, DetachScheduleServiceError, DetachScheduleServiceErrors, DetachScheduleServiceResponse, DetachScheduleServiceResponses, DetectionConfig, DetectPublicPresetsData, DetectPublicPresetsErrors, DetectPublicPresetsResponse, DetectPublicPresetsResponses, DeviceCount, DigestSections, Direction, DisableBackupScheduleData, DisableBackupScheduleErrors, DisableBackupScheduleResponse, DisableBackupScheduleResponses, DisableBlobResponse, DisableKvResponse, DisableMfaData, DisableMfaErrors, DisableMfaRequest, DisableMfaResponse, DisableMfaResponses, DisconnectCloudData, DisconnectCloudResponse, DisconnectCloudResponses, DiscoverRequest, DiscoverResponse, DiscoverWorkloadsData, DiscoverWorkloadsErrors, DiscoverWorkloadsResponse, DiscoverWorkloadsResponses, DiskInfo, DiskSpaceAlert, DiskSpaceAlertSettings, DiskSpaceCheckResult, DnsAckRequest, DnsAckResponse, DnsChallengeRecordResult, DnsChangesResponse, DnsCompletionResponse, DnsLookupError, DnsLookupRequest, DnsLookupResponse, DnsProviderCredentials, DnsProviderResponse, DnsProviderSettings, DnsProviderSettingsMasked, DnsProviderType, DnsRecord, DnsRecordChange, DnsRecordContent, DnsRecordResponse, DnsRecordSetupResult, DnsRecordStatusResponse, DnsZone, DockerComposePresetConfig, DockerfilePresetConfig, DockerfileVariant, DockerRegistrySettings, DockerRegistrySettingsMasked, DomainAction, DomainChallengeResponse, DomainData, DomainEnvironmentResponse, DomainError, DomainErrors, DomainPlan, DomainResponse, DomainResponse2, DomainResponses, DownloadGlobalSkillArchiveData, DownloadGlobalSkillArchiveErrors, DownloadGlobalSkillArchiveResponse, DownloadGlobalSkillArchiveResponses, DownloadObjectData, DownloadObjectErrors, DownloadObjectResponse, DownloadObjectResponses, DownloadSkillArchiveData, DownloadSkillArchiveErrors, DownloadSkillArchiveResponse, DownloadSkillArchiveResponses, DrainNodeResponse, DrainStatusResponse, DropArchiveUpload, DropInspectionResponse, DropOffPoint, DropPresetCandidate, EmailConfig, EmailDomainResponse, EmailDomainWithDnsResponse, EmailProviderResponse, EmailProviderTypeRoute, EmailRequest, EmailResponse, EmailStatsResponse, EmailStatusData, EmailStatusErrors, EmailStatusResponse, EmailStatusResponse2, EmailStatusResponses, EmailTrackingResponse, EmailTrackingSetupResponse, EmailTrackingStatusResponse, EmbeddingData, EmbeddingInput, EmbeddingRequest, EmbeddingResponse, EmbeddingsData, EmbeddingsError, EmbeddingsErrors, EmbeddingsResponse, EmbeddingsResponses, EmbeddingUsage, EnableBackupScheduleData, EnableBackupScheduleErrors, EnableBackupScheduleResponse, EnableBackupScheduleResponses, EnableBlobRequest, EnableBlobResponse, EnableKvRequest, EnableKvResponse, EnablePgStatStatementsResponse, EndpointDto, EnqueuedJob, EnrichVisitorData, EnrichVisitorErrors, EnrichVisitorRequest, EnrichVisitorResponse, EnrichVisitorResponse2, EnrichVisitorResponses, EnrollCloudData, EnrollCloudRequest, EnrollCloudResponse, EnrollCloudResponses, EnrollmentTokenInfo, EnrollmentTokenListResponse, EntityInfoResponse, EntityResponse, EnvironmentConfiguration, EnvironmentDomainResponse, EnvironmentInfo, EnvironmentResponse, EnvironmentVariable, EnvironmentVariableInfo, EnvironmentVariableResponse, EnvironmentVariableValueResponse, EnvVarInput, EnvVarIntegrationInfo, EnvVarResponse, EnvVarTemplateResponse, ErrorDashboardStatsQuery, ErrorDashboardStatsResponse, ErrorEventResponse, ErrorGroupResponse, ErrorGroupStatsResponse, ErrorResponse, ErrorRow, ErrorTimeSeriesDataResponse, ErrorTimeSeriesQuery, EventActivityBucket, EventBreakdown, EventBrowserStats, EventCount, EventCountryStats, EventDetailQuery, EventDetailResponse, EventEntriesQuery, EventEntriesResponse, EventEntryInfo, EventKind, EventMetricsPayload, EventReferrerStats, EventsCountQuery, EventsResponse, EventTimeline, EventTimelineQuery, EventType, EventTypeBreakdown, EventTypeBreakdownQuery, EventTypeResponse, EventTypesResponse, EventVisitorInfo, EventVisitorsQuery, EventVisitorsResponse, ExecBody, ExecData, ExecDetachedData, ExecDetachedErrors, ExecDetachedResponse, ExecDetachedResponse2, ExecDetachedResponses, ExecErrors, ExecResponse, ExecResponse2, ExecResponses, ExecuteDeploymentOperationData, ExecuteDeploymentOperationErrors, ExecuteDeploymentOperationResponse, ExecuteDeploymentOperationResponses, ExecuteImportData, ExecuteImportErrors, ExecuteImportRequest, ExecuteImportResponse, ExecuteImportResponse2, ExecuteImportResponses, ExecuteOperationRequest, ExpireRequest, ExpireResponse, ExplorerSupportResponse, ExtendTimeoutBody, ExtendTimeoutData, ExtendTimeoutErrors, ExtendTimeoutResponse, ExtendTimeoutResponses, ExternalImageResponse, ExternalServiceBackupResponse, ExternalServiceDetails, ExternalServiceEnablePgStatStatementsData, ExternalServiceEnablePgStatStatementsErrors, ExternalServiceEnablePgStatStatementsResponse, ExternalServiceEnablePgStatStatementsResponses, ExternalServiceInfo, ExternalServiceMetricsByDatabaseData, ExternalServiceMetricsByDatabaseErrors, ExternalServiceMetricsByDatabaseResponse, ExternalServiceMetricsByDatabaseResponses, ExternalServiceMetricsCreateAlertRuleData, ExternalServiceMetricsCreateAlertRuleErrors, ExternalServiceMetricsCreateAlertRuleResponse, ExternalServiceMetricsCreateAlertRuleResponses, ExternalServiceMetricsDeleteAlertRuleData, ExternalServiceMetricsDeleteAlertRuleErrors, ExternalServiceMetricsDeleteAlertRuleResponse, ExternalServiceMetricsDeleteAlertRuleResponses, ExternalServiceMetricsGetAlertRulesData, ExternalServiceMetricsGetAlertRulesErrors, ExternalServiceMetricsGetAlertRulesResponse, ExternalServiceMetricsGetAlertRulesResponses, ExternalServiceMetricsGetLatestData, ExternalServiceMetricsGetLatestErrors, ExternalServiceMetricsGetLatestResponse, ExternalServiceMetricsGetLatestResponses, ExternalServiceMetricsGetRangeData, ExternalServiceMetricsGetRangeErrors, ExternalServiceMetricsGetRangeResponse, ExternalServiceMetricsGetRangeResponses, ExternalServiceMetricsStatusData, ExternalServiceMetricsStatusErrors, ExternalServiceMetricsStatusResponse, ExternalServiceMetricsStatusResponses, ExternalServiceMetricsToggleData, ExternalServiceMetricsToggleErrors, ExternalServiceMetricsToggleResponses, ExternalServiceMetricsUpdateAlertRuleData, ExternalServiceMetricsUpdateAlertRuleErrors, ExternalServiceMetricsUpdateAlertRuleResponse, ExternalServiceMetricsUpdateAlertRuleResponses, ExternalServiceResetPgStatStatementsData, ExternalServiceResetPgStatStatementsErrors, ExternalServiceResetPgStatStatementsResponse, ExternalServiceResetPgStatStatementsResponses, ExternalServiceSummary, FieldResponse, FinalizeOrderData, FinalizeOrderErrors, FinalizeOrderResponse, FinalizeOrderResponses, FinalizeProjectReleaseData, FinalizeProjectReleaseErrors, FinalizeProjectReleaseResponse, FinalizeProjectReleaseResponses, FindConversationData, FindConversationErrors, FindConversationResponse, FindConversationResponses, FiringSeriesEntry, FlagEnvironmentResponse, FlagListResponse, FlagResponse, FlagSnapshot, FlagSnapshotResponse, FlagValueType, ForecastAlgorithm, ForecastParams, FullError, FullEvent, FullRequest, FunnelMetricsResponse, FunnelResponse, GatewayStatus, GenAiEvent, GenAiSpanDetail, GenAiTraceDetailResponse, GenAiTraceSummariesResponse, GenAiTraceSummary, GeneralStatsQuery, GeneralStatsResponse, GenerateDockerfileRequest, GenerateDockerfileResponse, GenerateJoinTokenData, GenerateJoinTokenErrors, GenerateJoinTokenResponse, GenerateJoinTokenResponse2, GenerateJoinTokenResponses, GeneratePresetDockerfileData, GeneratePresetDockerfileErrors, GeneratePresetDockerfileResponse, GeneratePresetDockerfileResponses, GeoLocationResponse, GeoRestrictionsConfig, GetAccessInfoData, GetAccessInfoErrors, GetAccessInfoResponse, GetAccessInfoResponses, GetActiveVisitorsData, GetActiveVisitorsErrors, GetActiveVisitorsResponse, GetActiveVisitorsResponses, GetActivityGraphData, GetActivityGraphErrors, GetActivityGraphResponse, GetActivityGraphResponses, GetAdminGateData, GetAdminGateErrors, GetAdminGateResponse, GetAdminGateResponses, GetAgentData, GetAgentErrors, GetAgentResponse, GetAgentResponses, GetAggregatedBucketsData, GetAggregatedBucketsErrors, GetAggregatedBucketsResponse, GetAggregatedBucketsResponses, GetAiAgentBreakdownData, GetAiAgentBreakdownError, GetAiAgentBreakdownErrors, GetAiAgentBreakdownResponse, GetAiAgentBreakdownResponses, GetAiAgentPagesData, GetAiAgentPagesError, GetAiAgentPagesErrors, GetAiAgentPagesResponse, GetAiAgentPagesResponses, GetAiAgentTimelineData, GetAiAgentTimelineError, GetAiAgentTimelineErrors, GetAiAgentTimelineResponse, GetAiAgentTimelineResponses, GetAiPageBreakdownData, GetAiPageBreakdownError, GetAiPageBreakdownErrors, GetAiPageBreakdownResponse, GetAiPageBreakdownResponses, GetAiStatusBreakdownData, GetAiStatusBreakdownError, GetAiStatusBreakdownErrors, GetAiStatusBreakdownResponse, GetAiStatusBreakdownResponses, GetAlertData, GetAlertError, GetAlertErrors, GetAlertResponse, GetAlertResponses, GetAlertRuleData, GetAlertRuleErrors, GetAlertRuleResponse, GetAlertRuleResponses, GetAllRepositoriesByNameData, GetAllRepositoriesByNameErrors, GetAllRepositoriesByNameResponse, GetAllRepositoriesByNameResponses, GetAnalyticsActiveVisitorsData, GetAnalyticsActiveVisitorsErrors, GetAnalyticsActiveVisitorsResponse, GetAnalyticsActiveVisitorsResponses, GetAnalyticsEventsCountData, GetAnalyticsEventsCountErrors, GetAnalyticsEventsCountResponse, GetAnalyticsEventsCountResponses, GetAnalyticsSessionEventsData, GetAnalyticsSessionEventsErrors, GetAnalyticsSessionEventsResponse, GetAnalyticsSessionEventsResponses, GetAnalyticsVisitorSessionsData, GetAnalyticsVisitorSessionsErrors, GetAnalyticsVisitorSessionsResponse, GetAnalyticsVisitorSessionsResponses, GetApiKeyData, GetApiKeyErrors, GetApiKeyPermissionsData, GetApiKeyPermissionsErrors, GetApiKeyPermissionsResponse, GetApiKeyPermissionsResponses, GetApiKeyResponse, GetApiKeyResponses, GetAuditLogData, GetAuditLogErrors, GetAuditLogResponse, GetAuditLogResponses, GetBackupData, GetBackupError, GetBackupErrors, GetBackupResponse, GetBackupResponses, GetBackupScheduleData, GetBackupScheduleErrors, GetBackupScheduleResponse, GetBackupScheduleResponses, GetBranchesByRepositoryIdData, GetBranchesByRepositoryIdErrors, GetBranchesByRepositoryIdResponse, GetBranchesByRepositoryIdResponses, GetBucketedIncidentsData, GetBucketedIncidentsErrors, GetBucketedIncidentsResponse, GetBucketedIncidentsResponses, GetBucketedStatusData, GetBucketedStatusErrors, GetBucketedStatusResponse, GetBucketedStatusResponses, GetChallengeTokenData, GetChallengeTokenErrors, GetChallengeTokenResponse, GetChallengeTokenResponses, GetChatReadinessData, GetChatReadinessErrors, GetChatReadinessResponse, GetChatReadinessResponses, GetCliStatusData, GetCliStatusErrors, GetCliStatusResponses, GetCloudCapabilityData, GetCloudCapabilityResponse, GetCloudCapabilityResponses, GetCloudStatusData, GetCloudStatusResponse, GetCloudStatusResponses, GetClusterHealthData, GetClusterHealthErrors, GetClusterHealthResponse, GetClusterHealthResponses, GetClusterMemberData, GetClusterMemberErrors, GetClusterMemberResponse, GetClusterMemberResponses, GetCmdData, GetCmdErrors, GetCmdResponse, GetCmdResponses, GetContainerDetailData, GetContainerDetailErrors, GetContainerDetailResponse, GetContainerDetailResponses, GetContainerEnvironmentVariableData, GetContainerEnvironmentVariableErrors, GetContainerEnvironmentVariableResponse, GetContainerEnvironmentVariableResponses, GetContainerInfoData, GetContainerInfoErrors, GetContainerInfoResponse, GetContainerInfoResponses, GetContainerLogsByIdData, GetContainerLogsByIdErrors, GetContainerLogsData, GetContainerLogsErrors, GetContainerMetricsData, GetContainerMetricsErrors, GetContainerMetricsResponse, GetContainerMetricsResponses, GetConversationData, GetConversationDetailData, GetConversationDetailError, GetConversationDetailErrors, GetConversationDetailResponse, GetConversationDetailResponses, GetConversationErrors, GetConversationResponse, GetConversationResponses, GetConversationsData, GetConversationsError, GetConversationsErrors, GetConversationsResponse, GetConversationsResponses, GetCronByIdData, GetCronByIdErrors, GetCronByIdResponse, GetCronByIdResponses, GetCronExecutionsData, GetCronExecutionsErrors, GetCronExecutionsResponse, GetCronExecutionsResponses, GetCrossProjectTraceSiblingsData, GetCrossProjectTraceSiblingsError, GetCrossProjectTraceSiblingsErrors, GetCrossProjectTraceSiblingsResponse, GetCrossProjectTraceSiblingsResponses, GetCurrentMonitorStatusData, GetCurrentMonitorStatusErrors, GetCurrentMonitorStatusResponse, GetCurrentMonitorStatusResponses, GetCurrentUserData, GetCurrentUserErrors, GetCurrentUserResponse, GetCurrentUserResponses, GetCustomDomainData, GetCustomDomainErrors, GetCustomDomainResponse, GetCustomDomainResponses, GetDashboardData, GetDashboardError, GetDashboardErrors, GetDashboardProjectsAnalyticsData, GetDashboardProjectsAnalyticsErrors, GetDashboardProjectsAnalyticsResponse, GetDashboardProjectsAnalyticsResponses, GetDashboardResponse, GetDashboardResponses, GetDeliveryData, GetDeliveryErrors, GetDeliveryResponse, GetDeliveryResponses, GetDeploymentContainerLogContentData, GetDeploymentContainerLogContentErrors, GetDeploymentContainerLogContentResponse, GetDeploymentContainerLogContentResponses, GetDeploymentData, GetDeploymentErrors, GetDeploymentJobLogsData, GetDeploymentJobLogsErrors, GetDeploymentJobLogsResponse, GetDeploymentJobLogsResponses, GetDeploymentJobsData, GetDeploymentJobsErrors, GetDeploymentJobsResponse, GetDeploymentJobsResponses, GetDeploymentOperationsData, GetDeploymentOperationsErrors, GetDeploymentOperationsResponse, GetDeploymentOperationsResponses, GetDeploymentOperationStatusData, GetDeploymentOperationStatusErrors, GetDeploymentOperationStatusResponse, GetDeploymentOperationStatusResponses, GetDeploymentResponse, GetDeploymentResponses, GetDeploymentsParams, GetDeploymentTokenData, GetDeploymentTokenErrors, GetDeploymentTokenResponse, GetDeploymentTokenResponses, GetDiskStatusData, GetDiskStatusErrors, GetDiskStatusResponse, GetDiskStatusResponses, GetDnsChangesData, GetDnsChangesErrors, GetDnsChangesResponse, GetDnsChangesResponses, GetDnsProviderData, GetDnsProviderErrors, GetDnsProviderResponse, GetDnsProviderResponses, GetDomainByHostData, GetDomainByHostErrors, GetDomainByHostResponse, GetDomainByHostResponses, GetDomainByIdData, GetDomainByIdErrors, GetDomainByIdResponse, GetDomainByIdResponses, GetDomainByNameData, GetDomainByNameErrors, GetDomainByNameResponse, GetDomainByNameResponses, GetDomainData, GetDomainDnsRecordsData, GetDomainDnsRecordsErrors, GetDomainDnsRecordsResponse, GetDomainDnsRecordsResponses, GetDomainErrors, GetDomainOrderData, GetDomainOrderErrors, GetDomainOrderResponse, GetDomainOrderResponses, GetDomainResponse, GetDomainResponses, GetEmailData, GetEmailErrors, GetEmailEventsData, GetEmailEventsErrors, GetEmailEventsResponse, GetEmailEventsResponses, GetEmailLinksData, GetEmailLinksErrors, GetEmailLinksResponse, GetEmailLinksResponses, GetEmailProviderData, GetEmailProviderErrors, GetEmailProviderResponse, GetEmailProviderResponses, GetEmailResponse, GetEmailResponses, GetEmailStatsData, GetEmailStatsErrors, GetEmailStatsResponse, GetEmailStatsResponses, GetEmailTrackingData, GetEmailTrackingErrors, GetEmailTrackingResponse, GetEmailTrackingResponses, GetEmailTrackingStatusData, GetEmailTrackingStatusErrors, GetEmailTrackingStatusResponse, GetEmailTrackingStatusResponses, GetEntityInfoData, GetEntityInfoErrors, GetEntityInfoResponse, GetEntityInfoResponses, GetEnvironmentCronsData, GetEnvironmentCronsErrors, GetEnvironmentCronsResponse, GetEnvironmentCronsResponses, GetEnvironmentData, GetEnvironmentDomainsData, GetEnvironmentDomainsErrors, GetEnvironmentDomainsResponse, GetEnvironmentDomainsResponses, GetEnvironmentErrors, GetEnvironmentResponse, GetEnvironmentResponses, GetEnvironmentsData, GetEnvironmentsErrors, GetEnvironmentsResponse, GetEnvironmentsResponses, GetEnvironmentVariablesData, GetEnvironmentVariablesErrors, GetEnvironmentVariablesQuery, GetEnvironmentVariablesResponse, GetEnvironmentVariablesResponses, GetEnvironmentVariableValueData, GetEnvironmentVariableValueErrors, GetEnvironmentVariableValueResponse, GetEnvironmentVariableValueResponses, GetErrorDashboardStatsData, GetErrorDashboardStatsErrors, GetErrorDashboardStatsResponse, GetErrorDashboardStatsResponses, GetErrorEventData, GetErrorEventErrors, GetErrorEventResponse, GetErrorEventResponses, GetErrorGroupData, GetErrorGroupErrors, GetErrorGroupResponse, GetErrorGroupResponses, GetErrorStatsData, GetErrorStatsErrors, GetErrorStatsResponse, GetErrorStatsResponses, GetErrorTimeSeriesData, GetErrorTimeSeriesErrors, GetErrorTimeSeriesResponse, GetErrorTimeSeriesResponses, GetEventDetailData, GetEventDetailErrors, GetEventDetailResponse, GetEventDetailResponses, GetEventEntriesData, GetEventEntriesErrors, GetEventEntriesResponse, GetEventEntriesResponses, GetEventsCountData, GetEventsCountErrors, GetEventsCountResponse, GetEventsCountResponses, GetEventsTimelineData, GetEventsTimelineErrors, GetEventsTimelineResponse, GetEventsTimelineResponses, GetEventTypeBreakdownData, GetEventTypeBreakdownErrors, GetEventTypeBreakdownResponse, GetEventTypeBreakdownResponses, GetEventVisitorsData, GetEventVisitorsErrors, GetEventVisitorsResponse, GetEventVisitorsResponses, GetExternalImageData, GetExternalImageErrors, GetExternalImageResponse, GetExternalImageResponses, GetFileData, GetFileErrors, GetFileResponse, GetFileResponses, GetFlagData, GetFlagErrors, GetFlagResponse, GetFlagResponses, GetFlagSnapshotData, GetFlagSnapshotErrors, GetFlagSnapshotResponse, GetFlagSnapshotResponses, GetFunnelMetricsData, GetFunnelMetricsErrors, GetFunnelMetricsQuery, GetFunnelMetricsResponse, GetFunnelMetricsResponses, GetGenaiTraceData, GetGenaiTraceError, GetGenaiTraceErrors, GetGenaiTraceResponse, GetGenaiTraceResponses, GetGeneralStatsData, GetGeneralStatsErrors, GetGeneralStatsResponse, GetGeneralStatsResponses, GetGitProviderData, GetGitProviderErrors, GetGitProviderResponse, GetGitProviderResponses, GetGlobalEventsData, GetGlobalEventsErrors, GetGlobalEventsResponse, GetGlobalEventsResponses, GetGlobalEventStatsData, GetGlobalEventStatsErrors, GetGlobalEventStatsResponse, GetGlobalEventStatsResponses, GetGlobalMcpData, GetGlobalMcpErrors, GetGlobalMcpResponse, GetGlobalMcpResponses, GetGlobalSandboxStatusData, GetGlobalSandboxStatusErrors, GetGlobalSandboxStatusResponse, GetGlobalSandboxStatusResponses, GetGlobalSkillData, GetGlobalSkillErrors, GetGlobalSkillResponse, GetGlobalSkillResponses, GetGroupedPageMetricsData, GetGroupedPageMetricsError, GetGroupedPageMetricsErrors, GetGroupedPageMetricsResponse, GetGroupedPageMetricsResponses, GetHealthData, GetHealthError, GetHealthErrors, GetHealthResponse, GetHealthResponses, GetHourlyVisitsData, GetHourlyVisitsErrors, GetHourlyVisitsResponse, GetHourlyVisitsResponses, GetHttpChallengeDebugData, GetHttpChallengeDebugErrors, GetHttpChallengeDebugResponse, GetHttpChallengeDebugResponses, GetImportStatusData, GetImportStatusErrors, GetImportStatusResponse, GetImportStatusResponses, GetIncidentData, GetIncidentErrors, GetIncidentResponse, GetIncidentResponses, GetIncidentUpdatesData, GetIncidentUpdatesErrors, GetIncidentUpdatesResponse, GetIncidentUpdatesResponses, GetIpAccessControlData, GetIpAccessControlError, GetIpAccessControlErrors, GetIpAccessControlResponse, GetIpAccessControlResponses, GetIpGeolocationData, GetIpGeolocationError, GetIpGeolocationErrors, GetIpGeolocationResponse, GetIpGeolocationResponses, GetJoinTokenStatusData, GetJoinTokenStatusErrors, GetJoinTokenStatusResponse, GetJoinTokenStatusResponses, GetLastDeploymentData, GetLastDeploymentErrors, GetLastDeploymentResponse, GetLastDeploymentResponses, GetLatestScanData, GetLatestScanError, GetLatestScanErrors, GetLatestScanResponse, GetLatestScanResponses, GetLatestScansPerEnvironmentData, GetLatestScansPerEnvironmentError, GetLatestScansPerEnvironmentErrors, GetLatestScansPerEnvironmentResponse, GetLatestScansPerEnvironmentResponses, GetLiveVisitorsListData, GetLiveVisitorsListErrors, GetLiveVisitorsListResponse, GetLiveVisitorsListResponses, GetLogContextData, GetLogContextError, GetLogContextErrors, GetLogContextResponse, GetLogContextResponses, GetMcpData, GetMcpErrors, GetMcpResponse, GetMcpResponses, GetMetricsOverTimeData, GetMetricsOverTimeError, GetMetricsOverTimeErrors, GetMetricsOverTimeResponse, GetMetricsOverTimeResponses, GetMonitorData, GetMonitorErrors, GetMonitorResponse, GetMonitorResponses, GetNotificationProviderData, GetNotificationProviderErrors, GetNotificationProviderResponse, GetNotificationProviderResponses, GetOnDemandCertStatusData, GetOnDemandCertStatusErrors, GetOnDemandCertStatusResponse, GetOnDemandCertStatusResponses, GetOrCreateDsnData, GetOrCreateDsnErrors, GetOrCreateDsnRequest, GetOrCreateDsnResponse, GetOrCreateDsnResponses, GetPageFlowData, GetPageFlowErrors, GetPageFlowResponse, GetPageFlowResponses, GetPageHourlySessionsData, GetPageHourlySessionsErrors, GetPageHourlySessionsResponse, GetPageHourlySessionsResponses, GetPagePathDetailData, GetPagePathDetailErrors, GetPagePathDetailResponse, GetPagePathDetailResponses, GetPagePathsData, GetPagePathsErrors, GetPagePathsResponse, GetPagePathsResponses, GetPagePathsSparklinesData, GetPagePathsSparklinesErrors, GetPagePathsSparklinesResponse, GetPagePathsSparklinesResponses, GetPagePathVisitorsData, GetPagePathVisitorsErrors, GetPagePathVisitorsResponse, GetPagePathVisitorsResponses, GetPendingActionData, GetPendingActionErrors, GetPendingActionResponse, GetPendingActionResponses, GetPerformanceMetricsData, GetPerformanceMetricsError, GetPerformanceMetricsErrors, GetPerformanceMetricsResponse, GetPerformanceMetricsResponses, GetPgUpgradeData, GetPgUpgradeErrors, GetPgUpgradeLogsData, GetPgUpgradeLogsErrors, GetPgUpgradeLogsResponse, GetPgUpgradeLogsResponses, GetPgUpgradeResponse, GetPgUpgradeResponses, GetPipelineStatsData, GetPipelineStatsError, GetPipelineStatsErrors, GetPipelineStatsResponse, GetPipelineStatsResponses, GetPlatformInfoData, GetPlatformInfoErrors, GetPlatformInfoResponse, GetPlatformInfoResponses, GetPostgresWalHealthData, GetPostgresWalHealthErrors, GetPostgresWalHealthResponse, GetPostgresWalHealthResponses, GetPreferencesData, GetPreferencesErrors, GetPreferencesResponse, GetPreferencesResponses, GetPreviewGatewayLogsData, GetPreviewGatewayLogsResponse, GetPreviewGatewayLogsResponses, GetPreviewGatewaySettingsData, GetPreviewGatewaySettingsResponse, GetPreviewGatewaySettingsResponses, GetPreviewGatewayStatusData, GetPreviewGatewayStatusResponse, GetPreviewGatewayStatusResponses, GetPricingData, GetPricingError, GetPricingErrors, GetPricingResponse, GetPricingResponses, GetPrivateIpData, GetPrivateIpErrors, GetPrivateIpResponses, GetProjectAlarmsSummaryData, GetProjectAlarmsSummaryErrors, GetProjectAlarmsSummaryResponse, GetProjectAlarmsSummaryResponses, GetProjectBySlugData, GetProjectBySlugErrors, GetProjectBySlugResponse, GetProjectBySlugResponses, GetProjectData, GetProjectDeploymentsData, GetProjectDeploymentsErrors, GetProjectDeploymentsResponse, GetProjectDeploymentsResponses, GetProjectErrors, GetProjectResponse, GetProjectResponses, GetProjectsData, GetProjectSecretsQuery, GetProjectsErrors, GetProjectServiceEnvironmentVariablesData, GetProjectServiceEnvironmentVariablesErrors, GetProjectServiceEnvironmentVariablesResponse, GetProjectServiceEnvironmentVariablesResponses, GetProjectSessionReplaysData, GetProjectSessionReplaysError, GetProjectSessionReplaysErrors, GetProjectSessionReplaysQuery, GetProjectSessionReplaysResponse, GetProjectSessionReplaysResponse2, GetProjectSessionReplaysResponses, GetProjectsHealthData, GetProjectsHealthError, GetProjectsHealthErrors, GetProjectsHealthResponse, GetProjectsHealthResponses, GetProjectsMonitorHealthData, GetProjectsMonitorHealthErrors, GetProjectsMonitorHealthResponse, GetProjectsMonitorHealthResponses, GetProjectsResponse, GetProjectsResponses, GetProjectStatisticsData, GetProjectStatisticsErrors, GetProjectStatisticsResponse, GetProjectStatisticsResponses, GetProjectTemplateData, GetProjectTemplateErrors, GetProjectTemplateResponse, GetProjectTemplateResponses, GetPropertyBreakdownData, GetPropertyBreakdownErrors, GetPropertyBreakdownResponse, GetPropertyBreakdownResponses, GetPropertyTimelineData, GetPropertyTimelineErrors, GetPropertyTimelineResponse, GetPropertyTimelineResponses, GetProviderConnectionsData, GetProviderConnectionsErrors, GetProviderConnectionsResponse, GetProviderConnectionsResponses, GetProviderMetadataData, GetProviderMetadataErrors, GetProviderMetadataResponse, GetProviderMetadataResponses, GetProvidersMetadataData, GetProvidersMetadataErrors, GetProvidersMetadataResponse, GetProvidersMetadataResponses, GetProxyLogByIdData, GetProxyLogByIdError, GetProxyLogByIdErrors, GetProxyLogByIdResponse, GetProxyLogByIdResponses, GetProxyLogByRequestIdData, GetProxyLogByRequestIdError, GetProxyLogByRequestIdErrors, GetProxyLogByRequestIdResponse, GetProxyLogByRequestIdResponses, GetProxyLogsData, GetProxyLogsError, GetProxyLogsErrors, GetProxyLogsResponse, GetProxyLogsResponses, GetPublicBranchesData, GetPublicBranchesErrors, GetPublicBranchesResponse, GetPublicBranchesResponses, GetPublicIpData, GetPublicIpErrors, GetPublicIpResponses, GetPublicRepositoryData, GetPublicRepositoryErrors, GetPublicRepositoryResponse, GetPublicRepositoryResponses, GetQuotaData, GetQuotaError, GetQuotaErrors, GetQuotaResponse, GetQuotaResponses, GetRecentActivityData, GetRecentActivityErrors, GetRecentActivityResponse, GetRecentActivityResponses, GetRemoteExternalImageData, GetRemoteExternalImageErrors, GetRemoteExternalImageResponse, GetRemoteExternalImageResponses, GetRepositoryBranchesData, GetRepositoryBranchesErrors, GetRepositoryBranchesResponse, GetRepositoryBranchesResponses, GetRepositoryByIdData, GetRepositoryByIdErrors, GetRepositoryByIdResponse, GetRepositoryByIdResponses, GetRepositoryByNameData, GetRepositoryByNameErrors, GetRepositoryByNameResponse, GetRepositoryByNameResponses, GetRepositoryPresetByNameData, GetRepositoryPresetByNameErrors, GetRepositoryPresetByNameResponse, GetRepositoryPresetByNameResponses, GetRepositoryPresetLiveData, GetRepositoryPresetLiveErrors, GetRepositoryPresetLiveResponse, GetRepositoryPresetLiveResponses, GetRepositoryTagsData, GetRepositoryTagsErrors, GetRepositoryTagsResponse, GetRepositoryTagsResponses, GetRequest, GetResolvedEnvironmentVariablesData, GetResolvedEnvironmentVariablesErrors, GetResolvedEnvironmentVariablesResponse, GetResolvedEnvironmentVariablesResponses, GetResolvedEnvironmentVariableValueData, GetResolvedEnvironmentVariableValueErrors, GetResolvedEnvironmentVariableValueResponse, GetResolvedEnvironmentVariableValueResponses, GetResponse, GetRestoreCapabilitiesData, GetRestoreCapabilitiesError, GetRestoreCapabilitiesErrors, GetRestoreCapabilitiesResponse, GetRestoreCapabilitiesResponses, GetRestoreRunData, GetRestoreRunError, GetRestoreRunErrors, GetRestoreRunResponse, GetRestoreRunResponses, GetRouteData, GetRouteErrors, GetRouteResponse, GetRouteResponses, GetRunData, GetRunErrors, GetRunResponse, GetRunResponses, GetRunWithLogsData, GetRunWithLogsErrors, GetRunWithLogsResponse, GetRunWithLogsResponses, GetS3CredentialsData, GetS3CredentialsErrors, GetS3CredentialsResponse, GetS3CredentialsResponses, GetS3SourceData, GetS3SourceError, GetS3SourceErrors, GetS3SourceResponse, GetS3SourceResponses, GetSandboxData, GetSandboxErrors, GetSandboxResponse, GetSandboxResponses, GetSandboxStatusData, GetSandboxStatusErrors, GetSandboxStatusResponse, GetSandboxStatusResponses, GetScanByDeploymentData, GetScanByDeploymentError, GetScanByDeploymentErrors, GetScanByDeploymentResponse, GetScanByDeploymentResponses, GetScanData, GetScanError, GetScanErrors, GetScanResponse, GetScanResponses, GetScanVulnerabilitiesData, GetScanVulnerabilitiesError, GetScanVulnerabilitiesErrors, GetScanVulnerabilitiesResponse, GetScanVulnerabilitiesResponses, GetServiceBySlugData, GetServiceBySlugErrors, GetServiceBySlugResponse, GetServiceBySlugResponses, GetServiceData, GetServiceEnvironmentVariableData, GetServiceEnvironmentVariableErrors, GetServiceEnvironmentVariableResponse, GetServiceEnvironmentVariableResponses, GetServiceEnvironmentVariablesData, GetServiceEnvironmentVariablesErrors, GetServiceEnvironmentVariablesResponse, GetServiceEnvironmentVariablesResponses, GetServiceErrors, GetServiceHealthStatusData, GetServiceHealthStatusErrors, GetServiceHealthStatusResponse, GetServiceHealthStatusResponses, GetServicePreviewEnvironmentVariableNamesData, GetServicePreviewEnvironmentVariableNamesErrors, GetServicePreviewEnvironmentVariableNamesResponse, GetServicePreviewEnvironmentVariableNamesResponses, GetServicePreviewEnvironmentVariablesMaskedData, GetServicePreviewEnvironmentVariablesMaskedErrors, GetServicePreviewEnvironmentVariablesMaskedResponse, GetServicePreviewEnvironmentVariablesMaskedResponses, GetServiceResponse, GetServiceResponses, GetServiceRuntimeData, GetServiceRuntimeErrors, GetServiceRuntimeResponse, GetServiceRuntimeResponses, GetServiceStatsData, GetServiceStatsErrors, GetServiceStatsResponse, GetServiceStatsResponses, GetServiceTypeParametersData, GetServiceTypeParametersErrors, GetServiceTypeParametersResponses, GetServiceTypesData, GetServiceTypesErrors, GetServiceTypesResponse, GetServiceTypesResponses, GetSessionDetailsData, GetSessionDetailsErrors, GetSessionDetailsResponse, GetSessionDetailsResponses, GetSessionEventsData, GetSessionEventsErrors, GetSessionEventsResponse, GetSessionEventsResponses, GetSessionLogsData, GetSessionLogsErrors, GetSessionLogsResponse, GetSessionLogsResponses, GetSessionReplayData, GetSessionReplayError, GetSessionReplayErrors, GetSessionReplayEventsData, GetSessionReplayEventsError, GetSessionReplayEventsErrors, GetSessionReplayEventsResponse, GetSessionReplayEventsResponses, GetSessionReplayResponse, GetSessionReplayResponse2, GetSessionReplayResponses, GetSettingsData, GetSettingsErrors, GetSettingsResponse, GetSettingsResponses, GetSkillData, GetSkillErrors, GetSkillResponse, GetSkillResponses, GetSlowQueriesData, GetSlowQueriesErrors, GetSlowQueriesResponse, GetSlowQueriesResponses, GetStaticBundleData, GetStaticBundleErrors, GetStaticBundleResponse, GetStaticBundleResponses, GetStatusOverviewData, GetStatusOverviewErrors, GetStatusOverviewResponse, GetStatusOverviewResponses, GetTagsByRepositoryIdData, GetTagsByRepositoryIdErrors, GetTagsByRepositoryIdResponse, GetTagsByRepositoryIdResponses, GetTeamData, GetTeamErrors, GetTeamResponse, GetTeamResponses, GetTimeBucketStatsData, GetTimeBucketStatsError, GetTimeBucketStatsErrors, GetTimeBucketStatsResponse, GetTimeBucketStatsResponses, GetTodayStatsData, GetTodayStatsError, GetTodayStatsErrors, GetTodayStatsResponse, GetTodayStatsResponses, GetTraceData, GetTraceError, GetTraceErrors, GetTraceResponse, GetTraceResponses, GetUnifiedTraceData, GetUnifiedTraceError, GetUnifiedTraceErrors, GetUnifiedTraceResponse, GetUnifiedTraceResponses, GetUniqueCountsData, GetUniqueCountsErrors, GetUniqueCountsResponse, GetUniqueCountsResponses, GetUniqueEventsData, GetUniqueEventsErrors, GetUniqueEventsQuery, GetUniqueEventsResponse, GetUniqueEventsResponses, GetUpdateStatusData, GetUpdateStatusErrors, GetUpdateStatusResponse, GetUpdateStatusResponses, GetUptimeHistoryData, GetUptimeHistoryErrors, GetUptimeHistoryResponse, GetUptimeHistoryResponses, GetUsageByProviderData, GetUsageByProviderError, GetUsageByProviderErrors, GetUsageByProviderResponse, GetUsageByProviderResponses, GetUsageRecentData, GetUsageRecentError, GetUsageRecentErrors, GetUsageRecentResponse, GetUsageRecentResponses, GetUsageSummaryData, GetUsageSummaryError, GetUsageSummaryErrors, GetUsageSummaryResponse, GetUsageSummaryResponses, GetUsageTimeseriesData, GetUsageTimeseriesError, GetUsageTimeseriesErrors, GetUsageTimeseriesResponse, GetUsageTimeseriesResponses, GetUsageTopModelsData, GetUsageTopModelsError, GetUsageTopModelsErrors, GetUsageTopModelsResponse, GetUsageTopModelsResponses, GetVisitorByGuidData, GetVisitorByGuidErrors, GetVisitorByGuidResponse, GetVisitorByGuidResponses, GetVisitorByIdData, GetVisitorByIdErrors, GetVisitorByIdResponse, GetVisitorByIdResponses, GetVisitorDetailsData, GetVisitorDetailsErrors, GetVisitorDetailsResponse, GetVisitorDetailsResponses, GetVisitorFacetsData, GetVisitorFacetsErrors, GetVisitorFacetsResponse, GetVisitorFacetsResponses, GetVisitorInfoData, GetVisitorInfoErrors, GetVisitorInfoResponse, GetVisitorInfoResponses, GetVisitorJourneyData, GetVisitorJourneyErrors, GetVisitorJourneyResponse, GetVisitorJourneyResponses, GetVisitorsData, GetVisitorsErrors, GetVisitorSessionsData, GetVisitorSessionsError, GetVisitorSessionsErrors, GetVisitorSessionsQuery, GetVisitorSessionsResponse, GetVisitorSessionsResponse2, GetVisitorSessionsResponses, GetVisitorsResponse, GetVisitorsResponses, GetVisitorStatsData, GetVisitorStatsErrors, GetVisitorStatsResponse, GetVisitorStatsResponses, GetWebhookData, GetWebhookErrors, GetWebhookResponse, GetWebhookResponses, GitPushEvent, GitRefResponse, GitSourcePlan, GlobalConversationResponse, GlobalEventStatsResponse, GlobalMrrResponse, GlobalRecentEventResponse, GlobalRevenueSummaryResponse, GrantProjectAccessData, GrantProjectAccessErrors, GrantProjectAccessResponse, GrantProjectAccessResponses, GroupedPageMetric, GroupedPageMetricsQuery, GroupedPageMetricsResponse, HandleGitProviderOauthCallbackData, HandleGitProviderOauthCallbackErrors, HasAnalyticsEventsData, HasAnalyticsEventsErrors, HasAnalyticsEventsResponse, HasAnalyticsEventsResponse2, HasAnalyticsEventsResponses, HasErrorGroupsData, HasErrorGroupsErrors, HasErrorGroupsResponse, HasErrorGroupsResponse2, HasErrorGroupsResponses, HasEventsQuery, HasEventsResponse, HasMetricsQuery, HasMetricsResponse, HasPerformanceMetricsData, HasPerformanceMetricsError, HasPerformanceMetricsErrors, HasPerformanceMetricsResponse, HasPerformanceMetricsResponses, HealthCheckConfiguration, HealthCheckEntryResponse, HealthResponse, HealthStatus, HealthSummary, HeartbeatApiRequest, HeartbeatResponse, HierarchyLevel, HistogramSummary, HostnameChange, HostnamePreviewResponse, HourlyPageSessions, HourlyVisitsQuery, HttpChallengeDebugResponse, ImportCredentials, ImportExecutionStatus, ImportExternalServiceData, ImportExternalServiceErrors, ImportExternalServiceRequest, ImportExternalServiceResponse, ImportExternalServiceResponses, ImportOutcomeResponse, ImportPlan, ImportRowErrorResponse, ImportSelector, ImportSource, ImportSourceCapabilities, ImportSourceInfo, ImportStatusResponse, IncidentBucket, IncidentBucketedResponse, IncidentResponse, IncidentUpdateResponse, IncrRequest, IncrResponse, IngestLogsByPathData, IngestLogsByPathError, IngestLogsByPathErrors, IngestLogsByPathResponses, IngestLogsData, IngestLogsError, IngestLogsErrors, IngestLogsResponses, IngestMetricsByPathData, IngestMetricsByPathError, IngestMetricsByPathErrors, IngestMetricsByPathResponses, IngestMetricsData, IngestMetricsError, IngestMetricsErrors, IngestMetricsResponses, IngestSentryEnvelopeData, IngestSentryEnvelopeErrors, IngestSentryEnvelopeResponses, IngestSentryEventData, IngestSentryEventErrors, IngestSentryEventResponse, IngestSentryEventResponses, IngestTracesByPathData, IngestTracesByPathError, IngestTracesByPathErrors, IngestTracesByPathResponses, IngestTracesData, IngestTracesError, IngestTracesErrors, IngestTracesResponses, InitAuthResponse, InitSessionReplayData, InitSessionReplayError, InitSessionReplayErrors, InitSessionReplayResponse, InitSessionReplayResponses, Insight, InsightSeverity, InsightsResponse, InsightStatus, InspectDropArchiveData, InspectDropArchiveErrors, InspectDropArchiveResponse, InspectDropArchiveResponses, IntegrationResponse, IpAccessControlQuery, IpAccessControlResponse, JobLogsData, JobLogsErrors, JobLogsResponses, JobStatusData, JobStatusErrors, JobStatusResponse, JobStatusResponse2, JobStatusResponses, JobSummaryResponse, JoinTokenStatusResponse, JourneyEvent, JourneySession, KeysRequest, KeysResponse, KillJobBody, KillJobData, KillJobErrors, KillJobResponse, KillJobResponses, KnownAiAgentsResponse, KvDelData, KvDelErrors, KvDelResponse, KvDelResponses, KvDisableData, KvDisableErrors, KvDisableResponse, KvDisableResponses, KvEnableData, KvEnableErrors, KvEnableResponse, KvEnableResponses, KvExpireData, KvExpireErrors, KvExpireResponse, KvExpireResponses, KvGetData, KvGetErrors, KvGetResponse, KvGetResponses, KvIncrData, KvIncrErrors, KvIncrResponse, KvIncrResponses, KvKeysData, KvKeysErrors, KvKeysResponse, KvKeysResponses, KvSetData, KvSetErrors, KvSetResponse, KvSetResponses, KvStatusData, KvStatusErrors, KvStatusResponse, KvStatusResponse2, KvStatusResponses, KvTtlData, KvTtlErrors, KvTtlResponse, KvTtlResponses, KvUpdateData, KvUpdateErrors, KvUpdateResponse, KvUpdateResponses, LatestRunForSourceData, LatestRunForSourceErrors, LatestRunForSourceResponse, LatestRunForSourceResponses, LemonSqueezyConfig, LetsEncryptSettings, LineContext, LinkCustomDomainToCertificateData, LinkCustomDomainToCertificateErrors, LinkCustomDomainToCertificateResponse, LinkCustomDomainToCertificateResponses, LinkServiceRequest, LinkServiceToProjectData, LinkServiceToProjectErrors, LinkServiceToProjectResponse, LinkServiceToProjectResponses, ListAgentRunsData, ListAgentRunsErrors, ListAgentRunsResponse, ListAgentRunsResponses, ListAgentsData, ListAgentsErrors, ListAgentsResponse, ListAgentsResponse2, ListAgentsResponses, ListAiProvidersData, ListAiProvidersErrors, ListAiProvidersResponse, ListAiProvidersResponses, ListAlertRulesData, ListAlertRulesErrors, ListAlertRulesResponse, ListAlertRulesResponses, ListAlertsData, ListAlertsError, ListAlertsErrors, ListAlertsResponse, ListAlertsResponses, ListAllConversationsData, ListAllConversationsErrors, ListAllConversationsResponse, ListAllConversationsResponses, ListAllRunsData, ListAllRunsErrors, ListAllRunsResponse, ListAllRunsResponses, ListApiKeysData, ListApiKeysErrors, ListApiKeysQuery, ListApiKeysResponse, ListApiKeysResponses, ListAuditLogsData, ListAuditLogsErrors, ListAuditLogsQuery, ListAuditLogsResponse, ListAuditLogsResponses, ListAvailableContainersData, ListAvailableContainersErrors, ListAvailableContainersResponse, ListAvailableContainersResponses, ListBackupAlertsData, ListBackupAlertsError, ListBackupAlertsErrors, ListBackupAlertsResponse, ListBackupAlertsResponses, ListBackupChildrenData, ListBackupChildrenError, ListBackupChildrenErrors, ListBackupChildrenResponse, ListBackupChildrenResponses, ListBackupSchedulesData, ListBackupSchedulesError, ListBackupSchedulesErrors, ListBackupSchedulesResponse, ListBackupSchedulesResponses, ListBackupsForScheduleData, ListBackupsForScheduleErrors, ListBackupsForScheduleResponse, ListBackupsForScheduleResponses, ListBlobsQuery, ListBlobsResponse, ListCommitsByRepositoryIdData, ListCommitsByRepositoryIdErrors, ListCommitsByRepositoryIdResponse, ListCommitsByRepositoryIdResponses, ListConnectionsData, ListConnectionsErrors, ListConnectionsResponse, ListConnectionsResponses, ListContainersAtPathData, ListContainersAtPathErrors, ListContainersAtPathResponse, ListContainersAtPathResponses, ListContainersData, ListContainersErrors, ListContainersResponse, ListContainersResponses, ListConversationsData, ListConversationsErrors, ListConversationsResponse, ListConversationsResponses, ListCustomDomainsForProjectData, ListCustomDomainsForProjectErrors, ListCustomDomainsForProjectResponse, ListCustomDomainsForProjectResponses, ListCustomDomainsResponse, ListDashboardsData, ListDashboardsError, ListDashboardsErrors, ListDashboardsResponse, ListDashboardsResponses, ListDeliveriesData, ListDeliveriesErrors, ListDeliveriesResponse, ListDeliveriesResponses, ListDeploymentContainerLogsData, ListDeploymentContainerLogsErrors, ListDeploymentContainerLogsResponse, ListDeploymentContainerLogsResponses, ListDeploymentTokensData, ListDeploymentTokensErrors, ListDeploymentTokensQuery, ListDeploymentTokensResponse, ListDeploymentTokensResponses, ListDnsProvidersData, ListDnsProvidersErrors, ListDnsProvidersResponse, ListDnsProvidersResponses, ListDomainsData, ListDomainsErrors, ListDomainsResponse, ListDomainsResponse2, ListDomainsResponses, ListDsnsData, ListDsnsErrors, ListDsnsResponse, ListDsnsResponses, ListEmailDomainsData, ListEmailDomainsErrors, ListEmailDomainsResponse, ListEmailDomainsResponses, ListEmailProvidersData, ListEmailProvidersErrors, ListEmailProvidersResponse, ListEmailProvidersResponses, ListEmailsData, ListEmailsErrors, ListEmailsResponse, ListEmailsResponses, ListEnrollmentTokensData, ListEnrollmentTokensErrors, ListEnrollmentTokensResponse, ListEnrollmentTokensResponses, ListEntitiesData, ListEntitiesErrors, ListEntitiesQuery, ListEntitiesResponse, ListEntitiesResponses, ListErrorEventsData, ListErrorEventsErrors, ListErrorEventsQuery, ListErrorEventsResponse, ListErrorEventsResponses, ListErrorGroupsData, ListErrorGroupsErrors, ListErrorGroupsQuery, ListErrorGroupsResponse, ListErrorGroupsResponses, ListEventsData, ListEventsResponse, ListEventsResponses, ListEventTypesData, ListEventTypesResponse, ListEventTypesResponses, ListExternalImagesData, ListExternalImagesErrors, ListExternalImagesResponse, ListExternalImagesResponses, ListExternalPluginsData, ListExternalPluginsErrors, ListExternalPluginsResponse, ListExternalPluginsResponses, ListExternalServiceBackupsData, ListExternalServiceBackupsError, ListExternalServiceBackupsErrors, ListExternalServiceBackupsResponse, ListExternalServiceBackupsResponses, ListFlagsData, ListFlagsErrors, ListFlagsResponse, ListFlagsResponses, ListFunnelsData, ListFunnelsErrors, ListFunnelsResponse, ListFunnelsResponses, ListGitProvidersData, ListGitProvidersErrors, ListGitProvidersResponse, ListGitProvidersResponses, ListGlobalMcpsData, ListGlobalMcpsErrors, ListGlobalMcpsResponse, ListGlobalMcpsResponses, ListGlobalSkillsData, ListGlobalSkillsErrors, ListGlobalSkillsResponse, ListGlobalSkillsResponses, ListIncidentsData, ListIncidentsErrors, ListIncidentsResponses, ListInsightsData, ListInsightsError, ListInsightsErrors, ListInsightsResponse, ListInsightsResponses, ListIpAccessControlData, ListIpAccessControlError, ListIpAccessControlErrors, ListIpAccessControlResponse, ListIpAccessControlResponses, ListJobsData, ListJobsErrors, ListJobsResponse, ListJobsResponse2, ListJobsResponses, ListKnownAiAgentsData, ListKnownAiAgentsError, ListKnownAiAgentsErrors, ListKnownAiAgentsResponse, ListKnownAiAgentsResponses, ListManagedDomainsData, ListManagedDomainsErrors, ListManagedDomainsResponse, ListManagedDomainsResponses, ListMcpsData, ListMcpsErrors, ListMcpsResponse, ListMcpsResponse2, ListMcpsResponses, ListMetricLabelKeysData, ListMetricLabelKeysError, ListMetricLabelKeysErrors, ListMetricLabelKeysResponse, ListMetricLabelKeysResponses, ListMetricLabelValuesData, ListMetricLabelValuesError, ListMetricLabelValuesErrors, ListMetricLabelValuesResponse, ListMetricLabelValuesResponses, ListMetricNamesData, ListMetricNamesError, ListMetricNamesErrors, ListMetricNamesResponse, ListMetricNamesResponses, ListModelsData, ListModelsError, ListModelsErrors, ListModelsResponse, ListModelsResponses, ListMonitorsData, ListMonitorsErrors, ListMonitorsResponse, ListMonitorsResponses, ListNotificationProvidersData, ListNotificationProvidersErrors, ListNotificationProvidersResponse, ListNotificationProvidersResponses, ListOidcProvidersData, ListOidcProvidersResponse, ListOidcProvidersResponses, ListOidcProviderUsersData, ListOidcProviderUsersErrors, ListOidcProviderUsersResponse, ListOidcProviderUsersResponses, ListOidcRoleMappingsData, ListOidcRoleMappingsResponse, ListOidcRoleMappingsResponses, ListOnDemandCertsData, ListOnDemandCertsErrors, ListOnDemandCertsResponse, ListOnDemandCertsResponse2, ListOnDemandCertsResponses, ListOrdersData, ListOrdersErrors, ListOrdersResponse, ListOrdersResponse2, ListOrdersResponses, ListPeersData, ListPeersErrors, ListPeersResponse, ListPeersResponses, ListPendingActionsData, ListPendingActionsErrors, ListPendingActionsResponse, ListPendingActionsResponses, ListPgUpgradesData, ListPgUpgradesErrors, ListPgUpgradesResponse, ListPgUpgradesResponses, ListPresetsData, ListPresetsErrors, ListPresetsResponse, ListPresetsResponse2, ListPresetsResponses, ListProjectAccessData, ListProjectAccessErrors, ListProjectAccessResponse, ListProjectAccessResponses, ListProjectAlarmsData, ListProjectAlarmsErrors, ListProjectAlarmsResponse, ListProjectAlarmsResponses, ListProjectScansData, ListProjectScansError, ListProjectScansErrors, ListProjectScansResponse, ListProjectScansResponses, ListProjectSecretsData, ListProjectSecretsErrors, ListProjectSecretsResponse, ListProjectSecretsResponses, ListProjectServicesData, ListProjectServicesErrors, ListProjectServicesResponse, ListProjectServicesResponses, ListProjectTemplatesData, ListProjectTemplatesErrors, ListProjectTemplatesResponse, ListProjectTemplatesResponses, ListProjectTemplateTagsData, ListProjectTemplateTagsErrors, ListProjectTemplateTagsResponse, ListProjectTemplateTagsResponses, ListProviderKeysData, ListProviderKeysError, ListProviderKeysErrors, ListProviderKeysResponse, ListProviderKeysResponses, ListProviderZonesData, ListProviderZonesErrors, ListProviderZonesResponse, ListProviderZonesResponses, ListPublicProvidersData, ListPublicProvidersResponse, ListPublicProvidersResponses, ListReleaseFilesData, ListReleaseFilesErrors, ListReleaseFilesResponse, ListReleaseFilesResponses, ListReleasesData, ListReleasesErrors, ListReleasesResponse, ListReleasesResponses, ListRemoteExternalImagesData, ListRemoteExternalImagesErrors, ListRemoteExternalImagesResponse, ListRemoteExternalImagesResponses, ListRepositoriesByConnectionData, ListRepositoriesByConnectionErrors, ListRepositoriesByConnectionResponse, ListRepositoriesByConnectionResponses, ListRepositoriesByProviderData, ListRepositoriesByProviderErrors, ListRepositoriesByProviderResponse, ListRepositoriesByProviderResponses, ListRestoreRunsForServiceData, ListRestoreRunsForServiceResponse, ListRestoreRunsForServiceResponses, ListRootContainersData, ListRootContainersErrors, ListRootContainersResponse, ListRootContainersResponses, ListRoutesData, ListRoutesErrors, ListRoutesResponse, ListRoutesResponses, ListRunsResponse, ListS3SourcesData, ListS3SourcesError, ListS3SourcesErrors, ListS3SourcesResponse, ListS3SourcesResponses, ListSandboxesData, ListSandboxesResponse, ListSandboxesResponse2, ListSandboxesResponses, ListScansQuery, ListScheduleRunJobsData, ListScheduleRunJobsError, ListScheduleRunJobsErrors, ListScheduleRunJobsResponse, ListScheduleRunJobsResponses, ListScheduleRunsData, ListScheduleRunsError, ListScheduleRunsErrors, ListScheduleRunsResponse, ListScheduleRunsResponses, ListScheduleServicesData, ListScheduleServicesError, ListScheduleServicesErrors, ListScheduleServicesResponse, ListScheduleServicesResponses, ListSecretsData, ListSecretsErrors, ListSecretsResponse, ListSecretsResponse2, ListSecretsResponses, ListServiceHealthStatusesData, ListServiceHealthStatusesErrors, ListServiceHealthStatusesResponse, ListServiceHealthStatusesResponses, ListServiceProjectsData, ListServiceProjectsErrors, ListServiceProjectsResponse, ListServiceProjectsResponses, ListServiceSchedulesData, ListServiceSchedulesError, ListServiceSchedulesErrors, ListServiceSchedulesResponse, ListServiceSchedulesResponses, ListServicesData, ListServicesErrors, ListServicesResponse, ListServicesResponses, ListSkillsData, ListSkillsErrors, ListSkillsResponse, ListSkillsResponse2, ListSkillsResponses, ListSourceBackupsData, ListSourceBackupsError, ListSourceBackupsErrors, ListSourceBackupsResponse, ListSourceBackupsResponses, ListSourceFilesData, ListSourceFilesErrors, ListSourceFilesResponse, ListSourceFilesResponses, ListSourceMapsData, ListSourceMapsErrors, ListSourceMapsResponse, ListSourceMapsResponses, ListSourcesData, ListSourcesErrors, ListSourcesResponse, ListSourcesResponses, ListStaticBundlesData, ListStaticBundlesErrors, ListStaticBundlesResponse, ListStaticBundlesResponses, ListSyncedRepositoriesData, ListSyncedRepositoriesErrors, ListSyncedRepositoriesResponse, ListSyncedRepositoriesResponses, ListTagsResponse, ListTeamMembersData, ListTeamMembersErrors, ListTeamMembersResponse, ListTeamMembersResponses, ListTeamProjectsData, ListTeamProjectsErrors, ListTeamProjectsResponse, ListTeamProjectsResponses, ListTeamsData, ListTeamsErrors, ListTeamsResponse, ListTeamsResponses, ListTemplatesQuery, ListTemplatesResponse, ListUsersData, ListUsersErrors, ListUsersResponse, ListUsersResponses, ListVulnerabilitiesQuery, ListWebhooksData, ListWebhooksErrors, ListWebhooksResponse, ListWebhooksResponses, LiveVisitorInfo, LiveVisitorsListResponse, LocationCount, LocationGranularity, LocationInfo, LoginData, LoginErrors, LoginRequest, LoginResponse, LoginResponses, LogLevel, LogoutData, LogoutErrors, LogoutResponses, LogRecord, LogSearchLine, LogSeverity, LogSource, LogsQuery, LogsResponse, LogStream, LookupDnsARecordsData, LookupDnsARecordsError, LookupDnsARecordsErrors, LookupDnsARecordsResponse, LookupDnsARecordsResponses, ManagedDomainResponse, ManualAction, ManualActionTiming, McpDefinitionResponse, MessageContent, MessagePart, MessageResponse, MeteredMode, MetricAggregation, MetricBucket, MetricDataPoint, MetricsOverTimeResponse, MetricsQuery, MetricsRangeQuery, MetricsStatusResponse, MetricsStoreKind, MetricsSummaryResponse, MetricType, MfaRequiredResponse, MfaSetupResponse, MfaVerificationRequest, MigrationStep, MigrationSummary, MintEnrollmentTokenData, MintEnrollmentTokenErrors, MintEnrollmentTokenRequest, MintEnrollmentTokenResponse, MintEnrollmentTokenResponse2, MintEnrollmentTokenResponses, MiscResult, MkdirBody, MkdirData, MkdirErrors, MkdirResponse, MkdirResponses, ModelInfo, ModelListResponse, ModelPricing, ModelUsage, MonitoringSettings, MonitoringSettingsMasked, MonitorResponse, MonitorStatus, MrrBucketResponse, MultiNodeSettings, MultiNodeSettingsMasked, MxResult, NavEntry, NavSection, NetworkConfiguration, NetworkMode, NixpacksPresetConfig, NixpacksProvider, NodeContainerListResponse, NodeContainerResponse, NodeCostInfo, NodeHeartbeatData, NodeHeartbeatErrors, NodeHeartbeatResponse, NodeHeartbeatResponses, NodeInfoResponse, NodeListResponse, NodeMetricsGetRangeData, NodeMetricsGetRangeErrors, NodeMetricsGetRangeResponse, NodeMetricsGetRangeResponses, NotificationPreferencesResponse, NotificationProviderResponse, ObservabilityCompressionSettings, ObservabilityEvent, ObservabilityFullEventData, ObservabilityFullEventError, ObservabilityFullEventErrors, ObservabilityFullEventResponse, ObservabilityFullEventResponses, ObservabilityListEventsData, ObservabilityListEventsError, ObservabilityListEventsErrors, ObservabilityListEventsResponse, ObservabilityListEventsResponses, ObservabilityRetentionSettings, OidcCallbackData, OidcProviderResponse, OidcProvidersListResponse, OidcProviderSummary, OidcProviderUserResponse, OidcRoleMappingResponse, OidcTestConnectionResponse, OnDemandCertAttemptResponse, OnDemandCertRow, OnDemandTlsSettings, OpenAiError, OpenAiErrorResponse, OperatingSystemCount, OperationResultResponse, OperationResultsResponse, OtelDashboardResponse, OtelDashboardsResponse, OtelMetricAlertRuleResponse, OtelMetricAlertsResponse, OtelMetricLabelKeysResponse, OtelMetricLabelValuesResponse, OtelMetricNamesResponse, OtelMetricsResponse, OutlierAlgorithm, OutlierParams, OverprovisioningAssessment, OverprovisioningVerdict, PageActivityBucket, PageCountryStats, PageFlowEntry, PageFlowQuery, PageFlowResponse, PageHourlySessionsQuery, PageHourlySessionsResponse, PagePathDetailQuery, PagePathDetailResponse, PagePathInfo, PagePathSparkline, PagePathSparklinePoint, PagePathsQuery, PagePathsResponse, PagePathsSparklineQuery, PagePathsSparklineResponse, PagePathVisitorsQuery, PagePathVisitorsResponse, PageReferrerStats, PagesComparisonResponse, PageSessionComparison, PageSessionStats, PageSessionStatsQuery, PageTransition, PageVisit, PageVisitorSession, PaginatedEmailsResponse, PaginatedEntitiesResponse, PaginatedErrorEventsResponse, PaginatedErrorGroupsResponse, PaginatedEventsResponse, PaginatedExternalImagesResponse, PaginatedProjectList, PaginatedStaticBundlesResponse, Pagination, PaginationMeta, PaginationParams, PasswordProtectionConfig, PatchAdminGateData, PatchAdminGateErrors, PatchAdminGateResponse, PatchAdminGateResponses, PatchPreviewGatewaySettingsData, PatchPreviewGatewaySettingsResponse, PatchPreviewGatewaySettingsResponses, PatchSettingsRequest, PathVisitors, PathVisitorsAnalyticsQuery, PathVisitorsResponse, PauseDeploymentData, PauseDeploymentErrors, PauseDeploymentResponse, PauseDeploymentResponses, PauseSandboxData, PauseSandboxErrors, PauseSandboxResponse, PauseSandboxResponses, PeerEntry, PeerListResponse, PendingActionResponse, PerformanceMetricsQuery, PerformanceMetricsResponse, PermissionInfo, PgUpgradeLogResponse, PgUpgradeResponse, PipelineStats, PipelineStatsResponse, PlanComplexity, PlanMetadata, PlanRestoreData, PlanRestoreError, PlanRestoreErrors, PlanRestoreResponse, PlanRestoreResponses, PlanSourceBackup, PlanTarget, PlatformInfo, PluginManifest, PortMapping, PostDnsAckData, PostDnsAckErrors, PostDnsAckResponse, PostDnsAckResponses, PostgresWalHealth, PresetConfigSchema, PresetInfo, PresetResponse, PreviewAlertData, PreviewAlertError, PreviewAlertErrors, PreviewAlertResponse, PreviewAlertResponses, PreviewFunnelMetricsData, PreviewFunnelMetricsErrors, PreviewFunnelMetricsResponse, PreviewFunnelMetricsResponses, PreviewGatewaySettings, PreviewGatewaySettingsMasked, PreviewGatewaySettingsResponse, PreviewHostnameModeData, PreviewHostnameModeErrors, PreviewHostnameModeResponse, PreviewHostnameModeResponses, PreviewShareLinkBody, PreviewShareLinkResponse, PricingResponse, ProblemDetails, ProjectAccessResponse, ProjectConfiguration, ProjectDashboardAnalytics, ProjectDsnResponse, ProjectHealthSummary, ProjectInfo, ProjectMonitorHealth, ProjectPresetResponse, ProjectQuery, ProjectRef, ProjectResponse, ProjectSecretEnvironmentInfo, ProjectSecretResponse, ProjectServiceInfo, ProjectsHealthResponse, ProjectsMonitorHealthResponse, ProjectStatisticsResponse, ProjectStatsBreakdown, ProjectType, ProjectUsageInfoResponse, PromoteClusterMemberData, PromoteClusterMemberErrors, PromoteClusterMemberResponses, PromoteDeploymentData, PromoteDeploymentErrors, PromoteDeploymentRequest, PromoteDeploymentResponse, PromoteDeploymentResponses, PropertyBreakdownItem, PropertyBreakdownQuery, PropertyBreakdownResponse, PropertyColumn, PropertyTimelineItem, PropertyTimelineQuery, PropertyTimelineResponse, Protocol, ProviderCatalogDto, ProviderCatalogResponse, ProviderConfig, ProviderConfigMasked, ProviderDeletionCheckResponse, ProviderDescriptor, ProviderKeyResponse, ProviderMetadata, ProviderResponse, ProviderUsage, ProvisionDomainData, ProvisionDomainErrors, ProvisionDomainResponse, ProvisionDomainResponses, ProvisionResponse, ProxyLogResponse, ProxyLogsPaginatedResponse, PublicHostnameStrategy, PublicPresetResponse, PublicRepositoryInfo, PurgeLogsRequest, PurgeProjectLogsData, PurgeProjectLogsError, PurgeProjectLogsErrors, PurgeProjectLogsResponses, PushedExternalImageResponse, PushExternalImageData, PushExternalImageErrors, PushExternalImageResponse, PushExternalImageResponses, PushImageRequest, QueryDataData, QueryDataErrors, QueryDataRequest, QueryDataResponse, QueryDataResponse2, QueryDataResponses, QueryGenaiTracesData, QueryGenaiTracesError, QueryGenaiTracesErrors, QueryGenaiTracesResponse, QueryGenaiTracesResponses, QueryLogsData, QueryLogsError, QueryLogsErrors, QueryLogsResponse, QueryLogsResponses, QueryMetricsData, QueryMetricsError, QueryMetricsErrors, QueryMetricsResponse, QueryMetricsResponses, QueryTracesData, QueryTracesError, QueryTracesErrors, QueryTracesResponse, QueryTracesResponses, QueryTraceSummariesData, QueryTraceSummariesError, QueryTraceSummariesErrors, QueryTraceSummariesResponse, QueryTraceSummariesResponses, QuotaResponse, RateLimitConfig, RateLimitSettings, ReachabilityStatus, ReadFileData, ReadFileErrors, ReadFileResponse, ReadFileResponse2, ReadFileResponses, ReAnalyzeData, ReAnalyzeErrors, ReAnalyzeResponses, RebuildSandboxImageData, RebuildSandboxImageErrors, RebuildSandboxImageResponses, RecentActivityQuery, RecentActivityResponse, RecentEventResponse, RecentQueryParams, RecordConsoleEventData, RecordConsoleEventErrors, RecordConsoleEventResponses, RecordEventMetricsData, RecordEventMetricsErrors, RecordEventMetricsResponse, RecordEventMetricsResponses, RecordExposureRequest, RecordExposureResponse, RecordFlagExposureData, RecordFlagExposureErrors, RecordFlagExposureResponse, RecordFlagExposureResponses, RecordListResponse, RecordSpeedMetricsData, RecordSpeedMetricsError, RecordSpeedMetricsErrors, RecordSpeedMetricsResponse, RecordSpeedMetricsResponses, RecoveryTarget, ReferrerCount, ReferrersAnalyticsQuery, RefreshRouteTableData, RefreshRouteTableErrors, RefreshRouteTableResponse, RefreshRouteTableResponses, RegenerateDsnData, RegenerateDsnErrors, RegenerateDsnRequest, RegenerateDsnResponse, RegenerateDsnResponses, RegisterExternalImageData, RegisterExternalImageErrors, RegisterExternalImageResponse, RegisterExternalImageResponses, RegisterImageRequest, RegisterNodeApiRequest, RegisterNodeData, RegisterNodeErrors, RegisterNodeResponse, RegisterNodeResponse2, RegisterNodeResponses, RegisterRequest, ReinstallGitlabWebhookData, ReinstallGitlabWebhookErrors, ReinstallGitlabWebhookResponse, ReinstallGitlabWebhookResponses, ReinstallWebhookResponse, RejectPendingActionData, RejectPendingActionErrors, RejectPendingActionResponse, RejectPendingActionResponses, ReleaseListResponse, ReloadPluginsData, ReloadPluginsErrors, ReloadPluginsResponse, ReloadPluginsResponses, ReloadResponse, RemoteDeploymentResponse, RemoveClusterMemberData, RemoveClusterMemberErrors, RemoveClusterMemberResponse, RemoveClusterMemberResponses, RemoveManagedDomainData, RemoveManagedDomainErrors, RemoveManagedDomainResponse, RemoveManagedDomainResponses, RemoveNodeResponse, RemoveRoleData, RemoveRoleErrors, RemoveRoleResponse, RemoveRoleResponses, RemoveTeamMemberData, RemoveTeamMemberErrors, RemoveTeamMemberResponse, RemoveTeamMemberResponses, RenameConversationData, RenameConversationErrors, RenameConversationRequest, RenameConversationResponse, RenameConversationResponses, RenewDomainData, RenewDomainErrors, RenewDomainResponse, RenewDomainResponses, RepositoryListQuery, RepositoryListResponse, RepositoryPresetResponse, RepositoryResponse, RepositorySyncStartedResponse, RequestPasswordResetData, RequestPasswordResetErrors, RequestPasswordResetResponse, RequestPasswordResetResponses, RequestRow, ResetPasswordData, ResetPasswordErrors, ResetPasswordRequest, ResetPasswordResponse, ResetPasswordResponses, ResetPgStatStatementsRequest, ResetPgStatStatementsResponse, ResizeSandboxBody, ResizeSandboxData, ResizeSandboxErrors, ResizeSandboxResponse, ResizeSandboxResponses, ResolveAlarmData, ResolveAlarmErrors, ResolveAlarmResponses, ResolvedEnvVarResponse, ResolvedEnvVarSource, ResourceCounts, ResourceFootprint, ResourceInfo, ResourceLimitApplyResult, ResourceLimits, ResourceLimitsResponse, ResourceLimitsUpdateResponse, ResourcesBody, RestartContainerData, RestartContainerErrors, RestartContainerResponse, RestartContainerResponses, RestartPreviewGatewayData, RestartPreviewGatewayResponse, RestartPreviewGatewayResponses, RestartSandboxData, RestartSandboxErrors, RestartSandboxResponse, RestartSandboxResponses, RestoreCapabilities, RestoreCapabilitiesResponse, RestoreFlagData, RestoreFlagErrors, RestoreFlagResponse, RestoreFlagResponses, RestorePlan, RestoreRequestMode, RestoreRunView, RestoreUserData, RestoreUserErrors, RestoreUserResponse, RestoreUserResponses, ResumeDeploymentData, ResumeDeploymentErrors, ResumeDeploymentResponse, ResumeDeploymentResponses, ResumeSandboxData, ResumeSandboxErrors, ResumeSandboxResponse, ResumeSandboxResponses, RetentionCleanupFailure, RetentionCleanupReport, RetryClusterData, RetryClusterErrors, RetryClusterRequest, RetryClusterResponse, RetryClusterResponses, RetryDeliveryData, RetryDeliveryErrors, RetryDeliveryResponse, RetryDeliveryResponses, RetryPgUpgradeData, RetryPgUpgradeErrors, RetryPgUpgradeResponse, RetryPgUpgradeResponses, RetryRunData, RetryRunErrors, RetryRunResponse, RetryRunResponses, RevealGlobalMcpConfigData, RevealGlobalMcpConfigErrors, RevealGlobalMcpConfigResponse, RevealGlobalMcpConfigResponses, RevealMcpConfigData, RevealMcpConfigErrors, RevealMcpConfigResponse, RevealMcpConfigResponses, RevealNotificationProviderConfigData, RevealNotificationProviderConfigErrors, RevealNotificationProviderConfigResponse, RevealNotificationProviderConfigResponses, RevealServiceParameterData, RevealServiceParameterErrors, RevealServiceParameterResponse, RevealServiceParameterResponses, RevenueCreateIntegrationData, RevenueCreateIntegrationErrors, RevenueCreateIntegrationResponse, RevenueCreateIntegrationResponses, RevenueDeleteIntegrationData, RevenueDeleteIntegrationResponse, RevenueDeleteIntegrationResponses, RevenueGlobalEventsData, RevenueGlobalEventsResponse, RevenueGlobalEventsResponses, RevenueImportInvoicesCsvData, RevenueImportInvoicesCsvErrors, RevenueImportInvoicesCsvResponse, RevenueImportInvoicesCsvResponses, RevenueImportSubscriptionsCsvData, RevenueImportSubscriptionsCsvErrors, RevenueImportSubscriptionsCsvResponse, RevenueImportSubscriptionsCsvResponses, RevenueListIntegrationsData, RevenueListIntegrationsResponse, RevenueListIntegrationsResponses, RevenueListProvidersData, RevenueListProvidersResponse, RevenueListProvidersResponses, RevenueMetricsCustomersData, RevenueMetricsCustomersResponse, RevenueMetricsCustomersResponses, RevenueMetricsGlobalMrrData, RevenueMetricsGlobalMrrResponse, RevenueMetricsGlobalMrrResponses, RevenueMetricsGlobalSummaryData, RevenueMetricsGlobalSummaryResponse, RevenueMetricsGlobalSummaryResponses, RevenueMetricsMrrData, RevenueMetricsMrrResponse, RevenueMetricsMrrResponses, RevenueMetricsSummaryData, RevenueMetricsSummaryResponse, RevenueMetricsSummaryResponses, RevenueRecentEventsData, RevenueRecentEventsResponse, RevenueRecentEventsResponses, RevenueRotateTokenData, RevenueRotateTokenResponse, RevenueRotateTokenResponses, RevenueRow, RevenueUpdateConfigData, RevenueUpdateConfigErrors, RevenueUpdateConfigResponse, RevenueUpdateConfigResponses, RevenueUpdateSecretData, RevenueUpdateSecretErrors, RevenueUpdateSecretResponse, RevenueUpdateSecretResponses, RevokeDsnData, RevokeDsnErrors, RevokeDsnResponse, RevokeDsnResponses, RevokeEnrollmentTokenData, RevokeEnrollmentTokenErrors, RevokeEnrollmentTokenResponse, RevokeEnrollmentTokenResponses, RevokeJoinTokenData, RevokeJoinTokenErrors, RevokeJoinTokenResponse, RevokeJoinTokenResponses, RevokeProjectAccessData, RevokeProjectAccessErrors, RevokeProjectAccessResponse, RevokeProjectAccessResponses, RiskLevel, RoleInfo, RollbackPgUpgradeData, RollbackPgUpgradeErrors, RollbackPgUpgradeResponse, RollbackPgUpgradeResponses, RollbackToDeploymentData, RollbackToDeploymentErrors, RollbackToDeploymentResponse, RollbackToDeploymentResponses, RootfsCacheEntry, RootfsGcData, RootfsGcReport, RootfsGcResponses, RootfsReport, RootfsReportData, RootfsReportResponses, RootfsVmEntry, RotateApiKeyData, RotateApiKeyErrors, RotateApiKeyResponse, RotateApiKeyResponses, RotateDeploymentTokenData, RotateDeploymentTokenErrors, RotateDeploymentTokenResponse, RotateDeploymentTokenResponses, RouteRefreshResponse, RouteResponse, RouteRole, RouteUser, RouteUserWithRoles, RunBackupForSourceData, RunBackupForSourceError, RunBackupForSourceErrors, RunBackupForSourceResponse, RunBackupForSourceResponses, RunBackupRequest, RunConnectionHealthCheckData, RunConnectionHealthCheckErrors, RunConnectionHealthCheckResponse, RunConnectionHealthCheckResponses, RunExternalServiceBackupData, RunExternalServiceBackupError, RunExternalServiceBackupErrors, RunExternalServiceBackupRequest, RunExternalServiceBackupResponse, RunExternalServiceBackupResponses, RunScheduleNowData, RunScheduleNowError, RunScheduleNowErrors, RunScheduleNowResponse, RunScheduleNowResponses, S3ConnectionTestResponse, S3CredentialsResponse, S3SourceResponse, S3SourceResponseWritable, SandboxCreatePreviewLinkData, SandboxCreatePreviewLinkErrors, SandboxCreatePreviewLinkResponse, SandboxCreatePreviewLinkResponses, SandboxDomainResponse, SandboxEvent, SandboxEventsResponse, SandboxInner, SandboxResponse, SandboxRoute, SandboxStatusResponse, SaveAgentTokenData, SaveAgentTokenErrors, SaveAgentTokenRequest, SaveAgentTokenResponse, SaveAgentTokenResponse2, SaveAgentTokenResponses, SaveAiProviderCredentialData, SaveAiProviderCredentialErrors, SaveAiProviderCredentialResponse, SaveAiProviderCredentialResponses, SaveCredentialRequest, SaveCredentialResponse, ScalewayCredentialsRequest, ScanResponse, ScheduleRunEntry, ScheduleRunJobEntry, ScheduleRunListResponse, ScheduleRunResponse, ScheduleRunSummary, ScheduleRunSummaryList, ScreenshotSettings, SearchLogsData, SearchLogsError, SearchLogsErrors, SearchLogsRequest, SearchLogsResponse, SearchLogsResponse2, SearchLogsResponses, SearchMode, Seasonality, SecretResponse, SecurityConfig, SecurityHeadersConfig, SecurityHeadersSettings, SendEmailData, SendEmailErrors, SendEmailRequestBody, SendEmailResponse, SendEmailResponseBody, SendEmailResponses, SendMessageData, SendMessageErrors, SendMessageRequest, SendMessageResponses, SensitiveConfigValueResponse, SensitiveMcpConfigValueResponse, SensitiveValueResponse, SentryChunkUploadResponse, SentryCreateReleaseRequest, SentryEventRequest, SentryEventResponse, SentryReleaseFileResponse, SentryReleaseProjectRef, SentryReleaseResponse, SeriesStateEntry, ServiceAccessInfo, ServiceAction, ServiceAlertRuleResponse, ServiceBackupEntryResponse, ServiceBackupListResponse, ServiceCreateAlertRuleRequest, ServiceHealthResponse, ServiceHealthStatusBatchResponse, ServiceHealthStatusEntryResponse, ServiceMemberInfo, ServiceParameter, ServicePlan, ServiceResourceLimits, ServiceRuntimeReport, ServiceStatsReport, ServiceTypeInfo, ServiceTypeRoute, ServiceUpdateAlertRuleRequest, SesCredentialsRequest, SessionDetails, SessionDetailsQuery, SessionEvent, SessionEventDto, SessionEventsQuery, SessionEventsResponse, SessionLogsQuery, SessionLogsResponse, SessionReplayEventsRequest, SessionReplayInfoDto, SessionReplayInitRequest, SessionReplayInitResponse, SessionReplayWithEventsDto, SessionReplayWithVisitorDto, SessionRequestLog, SessionSummary, SetDefaultS3SourceData, SetDefaultS3SourceError, SetDefaultS3SourceErrors, SetDefaultS3SourceResponse, SetDefaultS3SourceResponses, SetFlagEnvironmentData, SetFlagEnvironmentErrors, SetFlagEnvironmentRequest, SetFlagEnvironmentResponse, SetFlagEnvironmentResponses, SetPreviewPasswordBody, SetPreviewPasswordData, SetPreviewPasswordErrors, SetPreviewPasswordResponse, SetPreviewPasswordResponse2, SetPreviewPasswordResponses, SetRequest, SetResponse, SettingsUpdateResponse, SetupDnsChallengeData, SetupDnsChallengeErrors, SetupDnsChallengeRequest, SetupDnsChallengeResponse, SetupDnsChallengeResponse2, SetupDnsChallengeResponses, SetupDnsData, SetupDnsErrors, SetupDnsRequest, SetupDnsResponse, SetupDnsResponse2, SetupDnsResponses, SetupEmailTrackingData, SetupEmailTrackingErrors, SetupEmailTrackingResponse, SetupEmailTrackingResponses, SetupMfaData, SetupMfaErrors, SetupMfaResponse, SetupMfaResponses, SiblingRef, SkillDefinitionResponse, SlackConfig, SleepEnvironmentData, SleepEnvironmentErrors, SleepEnvironmentResponse, SleepEnvironmentResponses, SlowQueriesResponse, SlowQueryRow, SmartFilter, SmokeTestAgentData, SmokeTestAgentErrors, SmokeTestAgentResponse, SmokeTestAgentResponses, SmokeTestResponse, SmtpCredentialsRequest, SmtpEncryptionRoute, SmtpResult, SourceArchiveUpload, SourceBackupEntry, SourceBackupIndexResponse, SourceBody, SourceFileListResponse, SourceFileResponse, SourceMapListResponse, SourceMapResponse, SourceSandboxData, SourceSandboxErrors, SourceSandboxResponse, SourceSandboxResponses, SourceType, SpanEvent, SpanKind, SpanRecord, SpanRow, SpanStatusCode, SpeedMetricsPayload, SpeedSegmentFilters, StaleSlot, StartAnalysisData, StartAnalysisErrors, StartAnalysisRequest, StartAnalysisResponse, StartAnalysisResponses, StartContainerData, StartContainerErrors, StartContainerResponse, StartContainerResponses, StartFixData, StartFixErrors, StartFixResponses, StartGitProviderOauthData, StartGitProviderOauthErrors, StartOidcLoginBySlugData, StartOidcLoginBySlugErrors, StartPgUpgradeData, StartPgUpgradeErrors, StartPgUpgradeRequest, StartPgUpgradeResponse, StartPgUpgradeResponses, StartRestoreData, StartRestoreError, StartRestoreErrors, StartRestoreRequest, StartRestoreResponse, StartRestoreResponses, StartServiceData, StartServiceErrors, StartServiceResponse, StartServiceResponses, StaticBundleResponse, StaticParams, StaticPresetConfig, StatPathData, StatPathErrors, StatPathResponse, StatPathResponses, StatResponse, StatsFilters, StatusBucket, StatusBucketedResponse, StatusCodeCount, StatusCodesQuery, StatusPageOverview, StepConversionResponse, StepResourceType, StepResult, StepUpResponse, StopContainerData, StopContainerErrors, StopContainerResponse, StopContainerResponses, StopSandboxData, StopSandboxErrors, StopSandboxResponse, StopSandboxResponses, StopSequence, StopServiceData, StopServiceErrors, StopServiceResponse, StopServiceResponses, StorageQuota, StreamContainerMetricsData, StreamContainerMetricsErrors, StreamContainerMetricsResponses, StreamEventsData, StreamEventsErrors, StreamEventsResponses, StreamRunEventsData, StreamRunEventsErrors, StreamRunEventsResponses, StripeConfig, SyncedRepositoryListQuery, SyncRepositoriesData, SyncRepositoriesErrors, SyncRepositoriesResponse, SyncRepositoriesResponses, SyntaxResult, TagInfo, TagListResponse, TailDeploymentJobLogsData, TailDeploymentJobLogsErrors, TailLogsData, TailLogsError, TailLogsErrors, TailLogsRequest, TailLogsResponses, TargetRecommendation, TeamListResponse, TeamMemberResponse, TeamResponse, TeamRole, TeardownDeploymentData, TeardownDeploymentErrors, TeardownDeploymentResponse, TeardownDeploymentResponses, TeardownEnvironmentData, TeardownEnvironmentErrors, TeardownEnvironmentResponse, TeardownEnvironmentResponses, TemplateResponse, TestEmailRequest, TestEmailResponse, TestNotificationProviderData, TestNotificationProviderErrors, TestNotificationProviderResponse, TestNotificationProviderResponses, TestOidcProviderData, TestOidcProviderResponse, TestOidcProviderResponses, TestProviderConnectionData, TestProviderConnectionErrors, TestProviderConnectionResponse, TestProviderConnectionResponses, TestProviderData, TestProviderErrors, TestProviderKeyByIdData, TestProviderKeyByIdError, TestProviderKeyByIdErrors, TestProviderKeyByIdResponse, TestProviderKeyByIdResponses, TestProviderKeyInlineData, TestProviderKeyInlineError, TestProviderKeyInlineErrors, TestProviderKeyInlineResponse, TestProviderKeyInlineResponses, TestProviderKeyRequest, TestProviderKeyResponse, TestProviderResponse, TestProviderResponse2, TestProviderResponses, TestS3ConnectionPreviewData, TestS3ConnectionPreviewError, TestS3ConnectionPreviewErrors, TestS3ConnectionPreviewResponse, TestS3ConnectionPreviewResponses, TestS3SourceConnectionData, TestS3SourceConnectionError, TestS3SourceConnectionErrors, TestS3SourceConnectionResponse, TestS3SourceConnectionResponses, TimeBucketStats, TimeBucketStatsResponse, TimeseriesBucket, TimeseriesQueryParams, TlsMode, TodayStatsResponse, ToggleDeploymentMetricsRequest, ToggleServiceMetricsRequest, TokenRenewalRequest, ToolCallEvent, ToolInfo, ToolResultEvent, TopModelsQueryParams, TraceProjectRef, TracesResponse, TraceSummariesResponse, TraceSummary, TrackClickData, TrackClickErrors, TrackedLinkResponse, TrackingEventResponse, TrackOpenData, TrackOpenErrors, TrackOpenResponses, TriggerAgentData, TriggerAgentErrors, TriggerAgentRequest, TriggerAgentResponse, TriggerAgentResponses, TriggerDigestResponse, TriggerPipelinePayload, TriggerPipelineResponse, TriggerProjectPipelineData, TriggerProjectPipelineErrors, TriggerProjectPipelineResponse, TriggerProjectPipelineResponses, TriggerScanData, TriggerScanError, TriggerScanErrors, TriggerScanRequest, TriggerScanResponse, TriggerScanResponse2, TriggerScanResponses, TriggerServiceHealthCheckData, TriggerServiceHealthCheckErrors, TriggerServiceHealthCheckResponse, TriggerServiceHealthCheckResponses, TriggerWeeklyDigestData, TriggerWeeklyDigestErrors, TriggerWeeklyDigestResponse, TriggerWeeklyDigestResponses, TtlRequest, TtlResponse, TxtRecord, UiManifest, UiRoute, UndrainNodeResponse, UnifiedTrace, UniqueCountsQuery, UniqueCountsResponse, UnlinkServiceFromProjectData, UnlinkServiceFromProjectErrors, UnlinkServiceFromProjectResponse, UnlinkServiceFromProjectResponses, UnsupportedFeature, UpdateAdminGateRequest, UpdateAgentData, UpdateAgentErrors, UpdateAgentResponse, UpdateAgentResponses, UpdateAiProviderData, UpdateAiProviderErrors, UpdateAiProviderRequest, UpdateAiProviderResponse, UpdateAiProviderResponse2, UpdateAiProviderResponses, UpdateAlertData, UpdateAlertError, UpdateAlertErrors, UpdateAlertResponse, UpdateAlertResponses, UpdateAlertRuleData, UpdateAlertRuleErrors, UpdateAlertRuleRequest, UpdateAlertRuleResponse, UpdateAlertRuleResponses, UpdateApiKeyData, UpdateApiKeyErrors, UpdateApiKeyRequest, UpdateApiKeyResponse, UpdateApiKeyResponses, UpdateAutomaticDeployData, UpdateAutomaticDeployErrors, UpdateAutomaticDeployRequest, UpdateAutomaticDeployResponse, UpdateAutomaticDeployResponses, UpdateBackupScheduleData, UpdateBackupScheduleError, UpdateBackupScheduleErrors, UpdateBackupScheduleRequest, UpdateBackupScheduleResponse, UpdateBackupScheduleResponses, UpdateBlobRequest, UpdateBlobResponse, UpdateCloudflareProviderData, UpdateCloudflareProviderErrors, UpdateCloudflareProviderRequest, UpdateCloudflareProviderResponse, UpdateCloudflareProviderResponses, UpdateConfigBody, UpdateConnectionTokenData, UpdateConnectionTokenErrors, UpdateConnectionTokenResponse, UpdateConnectionTokenResponses, UpdateCustomDomainData, UpdateCustomDomainErrors, UpdateCustomDomainRequest, UpdateCustomDomainResponse, UpdateCustomDomainResponses, UpdateDashboardData, UpdateDashboardError, UpdateDashboardErrors, UpdateDashboardRequest, UpdateDashboardResponse, UpdateDashboardResponses, UpdateDeploymentConfigRequest, UpdateDeploymentTokenData, UpdateDeploymentTokenErrors, UpdateDeploymentTokenRequest, UpdateDeploymentTokenResponse, UpdateDeploymentTokenResponses, UpdateDnsProviderRequest, UpdateEmailProviderData, UpdateEmailProviderErrors, UpdateEmailProviderRequest, UpdateEmailProviderResponse, UpdateEmailProviderResponses, UpdateEnvironmentSettingsData, UpdateEnvironmentSettingsErrors, UpdateEnvironmentSettingsRequest, UpdateEnvironmentSettingsResponse, UpdateEnvironmentSettingsResponses, UpdateEnvironmentSubdomainData, UpdateEnvironmentSubdomainErrors, UpdateEnvironmentSubdomainRequest, UpdateEnvironmentSubdomainResponse, UpdateEnvironmentSubdomainResponses, UpdateEnvironmentVariableData, UpdateEnvironmentVariableErrors, UpdateEnvironmentVariableRequest, UpdateEnvironmentVariableResponse, UpdateEnvironmentVariableResponses, UpdateErrorGroupData, UpdateErrorGroupErrors, UpdateErrorGroupRequest, UpdateErrorGroupResponses, UpdateExternalServiceRequest, UpdateFlagData, UpdateFlagErrors, UpdateFlagRequest, UpdateFlagResponse, UpdateFlagResponses, UpdateFunnelData, UpdateFunnelErrors, UpdateFunnelResponses, UpdateGitProviderCredentialsData, UpdateGitProviderCredentialsErrors, UpdateGitProviderCredentialsResponse, UpdateGitProviderCredentialsResponses, UpdateGitSettingsData, UpdateGitSettingsErrors, UpdateGitSettingsRequest, UpdateGitSettingsResponse, UpdateGitSettingsResponses, UpdateGlobalMcpData, UpdateGlobalMcpErrors, UpdateGlobalMcpResponse, UpdateGlobalMcpResponses, UpdateGlobalSkillData, UpdateGlobalSkillErrors, UpdateGlobalSkillResponse, UpdateGlobalSkillResponses, UpdateIncidentStatusData, UpdateIncidentStatusErrors, UpdateIncidentStatusRequest, UpdateIncidentStatusResponse, UpdateIncidentStatusResponses, UpdateIpAccessControlData, UpdateIpAccessControlError, UpdateIpAccessControlErrors, UpdateIpAccessControlRequest, UpdateIpAccessControlResponse, UpdateIpAccessControlResponses, UpdateKvRequest, UpdateKvResponse, UpdateManagedDomainApiRequest, UpdateManagedDomainData, UpdateManagedDomainErrors, UpdateManagedDomainResponse, UpdateManagedDomainResponses, UpdateMcpData, UpdateMcpErrors, UpdateMcpRequest, UpdateMcpResponse, UpdateMcpResponses, UpdateMemberRoleRequest, UpdateMetricAlertRequest, UpdateNotificationEmailProviderData, UpdateNotificationEmailProviderErrors, UpdateNotificationEmailProviderRequest, UpdateNotificationEmailProviderResponse, UpdateNotificationEmailProviderResponses, UpdateNotificationProviderData, UpdateNotificationProviderErrors, UpdateNotificationProviderResponse, UpdateNotificationProviderResponses, UpdateOidcProviderData, UpdateOidcProviderRequest, UpdateOidcProviderResponse, UpdateOidcProviderResponses, UpdatePreferencesData, UpdatePreferencesErrors, UpdatePreferencesRequest, UpdatePreferencesResponse, UpdatePreferencesResponses, UpdateProjectData, UpdateProjectDeploymentConfigData, UpdateProjectDeploymentConfigErrors, UpdateProjectDeploymentConfigResponse, UpdateProjectDeploymentConfigResponses, UpdateProjectErrors, UpdateProjectResponse, UpdateProjectResponses, UpdateProjectSecretData, UpdateProjectSecretErrors, UpdateProjectSecretRequest, UpdateProjectSecretResponse, UpdateProjectSecretResponses, UpdateProjectSettingsData, UpdateProjectSettingsErrors, UpdateProjectSettingsRequest, UpdateProjectSettingsResponse, UpdateProjectSettingsResponses, UpdateProviderCredentialsRequest, UpdateProviderData, UpdateProviderErrors, UpdateProviderKeyData, UpdateProviderKeyError, UpdateProviderKeyErrors, UpdateProviderKeyRequest, UpdateProviderKeyResponse, UpdateProviderKeyResponses, UpdateProviderRequest, UpdateProviderResponse, UpdateProviderResponses, UpdateRouteData, UpdateRouteErrors, UpdateRouteRequest, UpdateRouteResponse, UpdateRouteResponses, UpdateS3SourceData, UpdateS3SourceError, UpdateS3SourceErrors, UpdateS3SourceRequest, UpdateS3SourceResponse, UpdateS3SourceResponses, UpdateSecretBody, UpdateSelfData, UpdateSelfErrors, UpdateSelfRequest, UpdateSelfResponse, UpdateSelfResponses, UpdateServiceData, UpdateServiceErrors, UpdateServiceResourcesData, UpdateServiceResourcesErrors, UpdateServiceResourcesResponse, UpdateServiceResourcesResponses, UpdateServiceResponse, UpdateServiceResponses, UpdateSessionDurationData, UpdateSessionDurationError, UpdateSessionDurationErrors, UpdateSessionDurationRequest, UpdateSessionDurationResponse, UpdateSessionDurationResponse2, UpdateSessionDurationResponses, UpdateSettingsData, UpdateSettingsErrors, UpdateSettingsResponse, UpdateSettingsResponses, UpdateSkillData, UpdateSkillErrors, UpdateSkillRequest, UpdateSkillResponse, UpdateSkillResponses, UpdateSlackProviderData, UpdateSlackProviderErrors, UpdateSlackProviderRequest, UpdateSlackProviderResponse, UpdateSlackProviderResponses, UpdateSpeedMetricsData, UpdateSpeedMetricsError, UpdateSpeedMetricsErrors, UpdateSpeedMetricsPayload, UpdateSpeedMetricsResponse, UpdateSpeedMetricsResponses, UpdateStatusResponse, UpdateTeamData, UpdateTeamErrors, UpdateTeamMemberRoleData, UpdateTeamMemberRoleErrors, UpdateTeamMemberRoleResponse, UpdateTeamMemberRoleResponses, UpdateTeamRequest, UpdateTeamResponse, UpdateTeamResponses, UpdateTokenRequest, UpdateTokenResponse, UpdateUserData, UpdateUserErrors, UpdateUserRequest, UpdateUserResponse, UpdateUserResponses, UpdateWebhookData, UpdateWebhookErrors, UpdateWebhookProviderData, UpdateWebhookProviderErrors, UpdateWebhookProviderRequest, UpdateWebhookProviderResponse, UpdateWebhookProviderResponses, UpdateWebhookRequestBody, UpdateWebhookResponse, UpdateWebhookResponses, UpgradeExternalServiceRequest, UpgradePreviewGatewayData, UpgradePreviewGatewayResponse, UpgradePreviewGatewayResponses, UpgradeRequest, UpgradeServiceData, UpgradeServiceErrors, UpgradeServiceResponse, UpgradeServiceResponses, UploadGlobalSkillData, UploadGlobalSkillErrors, UploadGlobalSkillResponse, UploadGlobalSkillResponses, UploadReleaseFileData, UploadReleaseFileErrors, UploadReleaseFileResponse, UploadReleaseFileResponses, UploadSkillData, UploadSkillErrors, UploadSkillResponse, UploadSkillResponses, UploadSourceFileData, UploadSourceFileErrors, UploadSourceFileResponse, UploadSourceFileResponses, UploadSourceMapData, UploadSourceMapErrors, UploadSourceMapResponse, UploadSourceMapResponses, UploadStaticBundleData, UploadStaticBundleErrors, UploadStaticBundleResponse, UploadStaticBundleResponses, UpsertAgentRequest, UpsertSecretData, UpsertSecretErrors, UpsertSecretRequest, UpsertSecretResponse, UpsertSecretResponses, UptimeDataPoint, UptimeHistoryResponse, UsageFilter, UsageInfo, UsageLogEntry, UsageLogPage, UsageQueryParams, UsageSource, UsageSummary, UserResponse, ValidateConnectionData, ValidateConnectionErrors, ValidateConnectionResponse, ValidateConnectionResponses, ValidateEmailData, ValidateEmailErrors, ValidateEmailRequest, ValidateEmailResponse, ValidateEmailResponse2, ValidateEmailResponses, ValidationLevel, ValidationReport, ValidationResponse, ValidationResult, ValidationStatus, ValidationSummary, VerifyAndEnableMfaData, VerifyAndEnableMfaErrors, VerifyAndEnableMfaResponse, VerifyAndEnableMfaResponses, VerifyDomainData, VerifyDomainErrors, VerifyDomainResponse, VerifyDomainResponses, VerifyEmailData, VerifyEmailErrors, VerifyEmailResponse, VerifyEmailResponses, VerifyManagedDomainData, VerifyManagedDomainErrors, VerifyManagedDomainResponse, VerifyManagedDomainResponses, VerifyMfaChallengeData, VerifyMfaChallengeErrors, VerifyMfaChallengeResponse, VerifyMfaChallengeResponses, VerifyMfaRequest, VerifyStepUpData, VerifyStepUpErrors, VerifyStepUpRequest, VerifyStepUpResponse, VerifyStepUpResponses, ViewItem, ViewsOverTime, ViewsOverTimeQuery, VisitorDetails, VisitorFacets, VisitorFacetsQuery, VisitorFacetValue, VisitorInfo, VisitorJourneyQuery, VisitorJourneyResponse, VisitorLocationsQuery, VisitorRecord, VisitorSegmentFilters, VisitorSessionsQuery, VisitorSessionsResponse, VisitorsListQuery, VisitorsResponse, VisitorStats, VisitorWithGeolocation, VolumeMount, VolumeType, VulnerabilityResponse, WakeEnvironmentData, WakeEnvironmentErrors, WakeEnvironmentResponse, WakeEnvironmentResponses, WalWarning, WalWarningSeverity, WebhookConfig, WebhookDeliveryResponse, WebhookResponse, WebhookTriggerData, WebhookTriggerErrors, WebhookTriggerRequest, WebhookTriggerResponse, WebhookTriggerResponse2, WebhookTriggerResponses, WorkflowDryRunData, WorkflowDryRunErrors, WorkflowDryRunRequest, WorkflowDryRunResponse, WorkflowDryRunResponses, WorkloadDescriptor, WorkloadId, WorkloadStatus, WorkloadType, WriteFileBody, WriteFileData, WriteFileErrors, WriteFileResponse, WriteFileResponses, WriteFilesBody, WriteFilesData, WriteFilesErrors, WriteFilesResponse, WriteFilesResponse2, WriteFilesResponses, ZoneListResponse } from './types.gen'; diff --git a/apps/temps-cli/src/api/sdk.gen.ts b/apps/temps-cli/src/api/sdk.gen.ts index 0fb6aa08b..49a148879 100644 --- a/apps/temps-cli/src/api/sdk.gen.ts +++ b/apps/temps-cli/src/api/sdk.gen.ts @@ -2,7 +2,7 @@ import { type Client, type ClientMeta, formDataBodySerializer, type Options as Options2, type RequestResult, type ServerSentEventsResult, type TDataShape } from './client'; import { client } from './client.gen'; -import type { AcknowledgeAlarmData, AcknowledgeAlarmErrors, AcknowledgeAlarmResponses, ActivateAiProviderData, ActivateAiProviderErrors, ActivateAiProviderResponses, ActivateApiKeyData, ActivateApiKeyErrors, ActivateApiKeyResponses, ActivateConnectionData, ActivateConnectionErrors, ActivateConnectionResponses, ActivateProviderData, ActivateProviderErrors, ActivateProviderResponses, AddClusterMemberData, AddClusterMemberErrors, AddClusterMemberResponses, AddContextData, AddContextErrors, AddContextResponses, AddEnvironmentDomainData, AddEnvironmentDomainErrors, AddEnvironmentDomainResponses, AddEventsData, AddEventsErrors, AddEventsResponses, AddManagedDomainData, AddManagedDomainErrors, AddManagedDomainResponses, AddSessionReplayEventsData, AddSessionReplayEventsErrors, AddSessionReplayEventsResponses, AddTeamMemberData, AddTeamMemberErrors, AddTeamMemberResponses, AdminDrainNodeData, AdminDrainNodeErrors, AdminDrainNodeResponses, AdminDrainStatusData, AdminDrainStatusErrors, AdminDrainStatusResponses, AdminGetNodeData, AdminGetNodeErrors, AdminGetNodeResponses, AdminListNodeContainersData, AdminListNodeContainersErrors, AdminListNodeContainersResponses, AdminListNodesData, AdminListNodesErrors, AdminListNodesResponses, AdminRemoveNodeData, AdminRemoveNodeErrors, AdminRemoveNodeResponses, AdminUndrainNodeData, AdminUndrainNodeErrors, AdminUndrainNodeResponses, ApplyHostnameModeData, ApplyHostnameModeErrors, ApplyHostnameModeResponses, ArchiveConversationData, ArchiveConversationErrors, ArchiveConversationResponses, ArchiveFlagData, ArchiveFlagErrors, ArchiveFlagResponses, AssignRoleData, AssignRoleErrors, AssignRoleResponses, AttachScheduleServicesData, AttachScheduleServicesErrors, AttachScheduleServicesResponses, BlobCopyData, BlobCopyErrors, BlobCopyResponses, BlobDeleteData, BlobDeleteErrors, BlobDeleteResponses, BlobDisableData, BlobDisableErrors, BlobDisableResponses, BlobDownloadData, BlobDownloadErrors, BlobDownloadResponses, BlobEnableData, BlobEnableErrors, BlobEnableResponses, BlobHeadData, BlobHeadErrors, BlobHeadResponses, BlobListData, BlobListErrors, BlobListResponses, BlobPutData, BlobPutErrors, BlobPutResponses, BlobStatusData, BlobStatusErrors, BlobStatusResponses, BlobUpdateData, BlobUpdateErrors, BlobUpdateResponses, CancelBackupData, CancelBackupErrors, CancelBackupResponses, CancelData, CancelDeploymentData, CancelDeploymentErrors, CancelDeploymentResponses, CancelDomainOrderData, CancelDomainOrderErrors, CancelDomainOrderResponses, CancelErrors, CancelPgUpgradeData, CancelPgUpgradeErrors, CancelPgUpgradeResponses, CancelResponses, CancelRunData, CancelRunErrors, CancelRunResponses, CancelScheduleRunData, CancelScheduleRunErrors, CancelScheduleRunResponses, ChangePasswordSelfData, ChangePasswordSelfErrors, ChangePasswordSelfResponses, ChangeProjectSourceData, ChangeProjectSourceErrors, ChangeProjectSourceResponses, ChatCompletionsData, ChatCompletionsErrors, ChatCompletionsResponses, CheckAnalyticsHasEventsData, CheckAnalyticsHasEventsErrors, CheckAnalyticsHasEventsResponses, CheckCommitExistsData, CheckCommitExistsErrors, CheckCommitExistsResponses, CheckDomainStatusData, CheckDomainStatusErrors, CheckDomainStatusResponses, CheckExplorerSupportData, CheckExplorerSupportErrors, CheckExplorerSupportResponses, CheckIpBlockedData, CheckIpBlockedErrors, CheckIpBlockedResponses, CheckProviderDeletionSafetyData, CheckProviderDeletionSafetyErrors, CheckProviderDeletionSafetyResponses, ChunkUploadOptionsData, ChunkUploadOptionsResponses, CleanupExpiredBackupsData, CleanupExpiredBackupsErrors, CleanupExpiredBackupsResponses, ClearPreviewPasswordData, ClearPreviewPasswordErrors, ClearPreviewPasswordResponses, CliDeviceApproveData, CliDeviceApproveErrors, CliDeviceApproveResponses, CliDeviceDenyData, CliDeviceDenyErrors, CliDeviceDenyResponses, CliDeviceLookupData, CliDeviceLookupErrors, CliDeviceLookupResponses, CliDevicePollData, CliDevicePollErrors, CliDevicePollResponses, CliDeviceStartData, CliDeviceStartErrors, CliDeviceStartResponses, CliLogoutData, CliLogoutErrors, CliLogoutResponses, CmdData, CmdErrors, CmdKillData, CmdKillErrors, CmdKillResponses, CmdLogsData, CmdLogsErrors, CmdLogsResponses, CmdResponses, ConfirmPendingActionData, ConfirmPendingActionErrors, ConfirmPendingActionResponses, ContainerMetricsGetHistoryData, ContainerMetricsGetHistoryErrors, ContainerMetricsGetHistoryResponses, CreateAgentData, CreateAgentErrors, CreateAgentResponses, CreateAlertData, CreateAlertErrors, CreateAlertResponses, CreateAlertRuleData, CreateAlertRuleErrors, CreateAlertRuleResponses, CreateApiKeyData, CreateApiKeyErrors, CreateApiKeyResponses, CreateBackupScheduleData, CreateBackupScheduleErrors, CreateBackupScheduleResponses, CreateBitbucketProviderData, CreateBitbucketProviderErrors, CreateBitbucketProviderResponses, CreateCloudflareProviderData, CreateCloudflareProviderErrors, CreateCloudflareProviderResponses, CreateConversationData, CreateConversationErrors, CreateConversationResponses, CreateCustomDomainData, CreateCustomDomainErrors, CreateCustomDomainResponses, CreateDashboardData, CreateDashboardErrors, CreateDashboardResponses, CreateDeploymentTokenData, CreateDeploymentTokenErrors, CreateDeploymentTokenResponses, CreateDnsProviderData, CreateDnsProviderErrors, CreateDnsProviderResponses, CreateDomainData, CreateDomainErrors, CreateDomainResponses, CreateDsnData, CreateDsnErrors, CreateDsnResponses, CreateEmailDomainData, CreateEmailDomainErrors, CreateEmailDomainResponses, CreateEmailProviderData, CreateEmailProviderErrors, CreateEmailProviderResponses, CreateEnvironmentData, CreateEnvironmentErrors, CreateEnvironmentResponses, CreateEnvironmentVariableData, CreateEnvironmentVariableErrors, CreateEnvironmentVariableResponses, CreateFlagData, CreateFlagErrors, CreateFlagResponses, CreateFunnelData, CreateFunnelErrors, CreateFunnelResponses, CreateGenericProviderData, CreateGenericProviderErrors, CreateGenericProviderResponses, CreateGiteaPatProviderData, CreateGiteaPatProviderErrors, CreateGiteaPatProviderResponses, CreateGithubPatProviderData, CreateGithubPatProviderErrors, CreateGithubPatProviderResponses, CreateGitlabOauthProviderData, CreateGitlabOauthProviderErrors, CreateGitlabOauthProviderResponses, CreateGitlabPatProviderData, CreateGitlabPatProviderErrors, CreateGitlabPatProviderResponses, CreateGitProviderData, CreateGitProviderErrors, CreateGitProviderResponses, CreateGlobalMcpData, CreateGlobalMcpErrors, CreateGlobalMcpResponses, CreateGlobalSkillData, CreateGlobalSkillErrors, CreateGlobalSkillResponses, CreateIncidentData, CreateIncidentErrors, CreateIncidentResponses, CreateIpAccessControlData, CreateIpAccessControlErrors, CreateIpAccessControlResponses, CreateMcpData, CreateMcpErrors, CreateMcpResponses, CreateMonitorData, CreateMonitorErrors, CreateMonitorResponses, CreateNotificationEmailProviderData, CreateNotificationEmailProviderErrors, CreateNotificationEmailProviderResponses, CreateNotificationProviderData, CreateNotificationProviderErrors, CreateNotificationProviderResponses, CreateOidcProviderData, CreateOidcProviderErrors, CreateOidcProviderResponses, CreateOidcRoleMappingData, CreateOidcRoleMappingResponses, CreateOrRecreateOrderData, CreateOrRecreateOrderErrors, CreateOrRecreateOrderResponses, CreatePlanData, CreatePlanErrors, CreatePlanResponses, CreatePrData, CreatePrErrors, CreateProjectData, CreateProjectErrors, CreateProjectFromTemplateData, CreateProjectFromTemplateErrors, CreateProjectFromTemplateResponses, CreateProjectReleaseData, CreateProjectReleaseErrors, CreateProjectReleaseResponses, CreateProjectResponses, CreateProjectSecretData, CreateProjectSecretErrors, CreateProjectSecretResponses, CreateProviderKeyData, CreateProviderKeyErrors, CreateProviderKeyResponses, CreatePrResponses, CreateReleaseData, CreateReleaseErrors, CreateReleaseResponses, CreateRouteData, CreateRouteErrors, CreateRouteResponses, CreateS3SourceData, CreateS3SourceErrors, CreateS3SourceResponses, CreateSandboxData, CreateSandboxErrors, CreateSandboxResponses, CreateServiceData, CreateServiceErrors, CreateServiceResponses, CreateSkillData, CreateSkillErrors, CreateSkillResponses, CreateSlackProviderData, CreateSlackProviderErrors, CreateSlackProviderResponses, CreateTeamData, CreateTeamErrors, CreateTeamResponses, CreateUserData, CreateUserErrors, CreateUserResponses, CreateWebhookData, CreateWebhookErrors, CreateWebhookProviderData, CreateWebhookProviderErrors, CreateWebhookProviderResponses, CreateWebhookResponses, DeactivateApiKeyData, DeactivateApiKeyErrors, DeactivateApiKeyResponses, DeactivateConnectionData, DeactivateConnectionErrors, DeactivateConnectionResponses, DeactivateProviderData, DeactivateProviderErrors, DeactivateProviderResponses, DeleteAgentData, DeleteAgentErrors, DeleteAgentResponses, DeleteAlertData, DeleteAlertErrors, DeleteAlertResponses, DeleteAlertRuleData, DeleteAlertRuleErrors, DeleteAlertRuleResponses, DeleteApiKeyData, DeleteApiKeyErrors, DeleteApiKeyResponses, DeleteBackupData, DeleteBackupErrors, DeleteBackupResponses, DeleteBackupScheduleData, DeleteBackupScheduleErrors, DeleteBackupScheduleResponses, DeleteConnectionData, DeleteConnectionErrors, DeleteConnectionResponses, DeleteCustomDomainData, DeleteCustomDomainErrors, DeleteCustomDomainResponses, DeleteDashboardData, DeleteDashboardErrors, DeleteDashboardResponses, DeleteDeploymentTokenData, DeleteDeploymentTokenErrors, DeleteDeploymentTokenResponses, DeleteDnsProviderData, DeleteDnsProviderErrors, DeleteDnsProviderResponses, DeleteDomainData, DeleteDomainErrors, DeleteDomainResponses, DeleteEmailDomainData, DeleteEmailDomainErrors, DeleteEmailDomainResponses, DeleteEmailProviderData, DeleteEmailProviderErrors, DeleteEmailProviderResponses, DeleteEnvironmentData, DeleteEnvironmentDomainData, DeleteEnvironmentDomainErrors, DeleteEnvironmentDomainResponses, DeleteEnvironmentErrors, DeleteEnvironmentResponses, DeleteEnvironmentVariableData, DeleteEnvironmentVariableErrors, DeleteEnvironmentVariableResponses, DeleteExternalImageData, DeleteExternalImageErrors, DeleteExternalImageResponses, DeleteFunnelData, DeleteFunnelErrors, DeleteFunnelResponses, DeleteGitProviderData, DeleteGitProviderErrors, DeleteGitProviderResponses, DeleteGlobalMcpData, DeleteGlobalMcpErrors, DeleteGlobalMcpResponses, DeleteGlobalSkillData, DeleteGlobalSkillErrors, DeleteGlobalSkillResponses, DeleteIpAccessControlData, DeleteIpAccessControlErrors, DeleteIpAccessControlResponses, DeleteMcpData, DeleteMcpErrors, DeleteMcpResponses, DeleteMonitorData, DeleteMonitorErrors, DeleteMonitorResponses, DeleteNotificationProviderData, DeleteNotificationProviderErrors, DeleteNotificationProviderResponses, DeleteOidcProviderData, DeleteOidcProviderResponses, DeleteOidcRoleMappingData, DeleteOidcRoleMappingResponses, DeletePreferencesData, DeletePreferencesErrors, DeletePreferencesResponses, DeleteProjectData, DeleteProjectErrors, DeleteProjectResponses, DeleteProjectSecretData, DeleteProjectSecretErrors, DeleteProjectSecretResponses, DeleteProviderKeyData, DeleteProviderKeyErrors, DeleteProviderKeyResponses, DeleteProviderSafelyData, DeleteProviderSafelyErrors, DeleteProviderSafelyResponses, DeleteReleaseSourceFilesData, DeleteReleaseSourceFilesErrors, DeleteReleaseSourceFilesResponses, DeleteReleaseSourceMapsData, DeleteReleaseSourceMapsErrors, DeleteReleaseSourceMapsResponses, DeleteRouteData, DeleteRouteErrors, DeleteRouteResponses, DeleteS3SourceData, DeleteS3SourceErrors, DeleteS3SourceResponses, DeleteScanData, DeleteScanErrors, DeleteScanResponses, DeleteSecretData, DeleteSecretErrors, DeleteSecretResponses, DeleteServiceData, DeleteServiceErrors, DeleteServiceResponses, DeleteSessionReplayData, DeleteSessionReplayErrors, DeleteSessionReplayResponses, DeleteSkillData, DeleteSkillErrors, DeleteSkillResponses, DeleteSourceMapData, DeleteSourceMapErrors, DeleteSourceMapResponses, DeleteStaticBundleData, DeleteStaticBundleErrors, DeleteStaticBundleResponses, DeleteTeamData, DeleteTeamErrors, DeleteTeamResponses, DeleteUserData, DeleteUserErrors, DeleteUserResponses, DeleteWebhookData, DeleteWebhookErrors, DeleteWebhookResponses, DeployFromImageData, DeployFromImageErrors, DeployFromImageResponses, DeployFromImageUploadData, DeployFromImageUploadErrors, DeployFromImageUploadResponses, DeployFromStaticData, DeployFromStaticErrors, DeployFromStaticResponses, DeployFromUploadedSourceData, DeployFromUploadedSourceErrors, DeployFromUploadedSourceResponses, DeploymentMetricsGetLatestData, DeploymentMetricsGetLatestErrors, DeploymentMetricsGetLatestResponses, DeploymentMetricsGetRangeData, DeploymentMetricsGetRangeErrors, DeploymentMetricsGetRangeResponses, DeploymentMetricsToggleData, DeploymentMetricsToggleErrors, DeploymentMetricsToggleResponses, DestroySandboxData, DestroySandboxErrors, DestroySandboxResponses, DetachScheduleServiceData, DetachScheduleServiceErrors, DetachScheduleServiceResponses, DetectPublicPresetsData, DetectPublicPresetsErrors, DetectPublicPresetsResponses, DisableBackupScheduleData, DisableBackupScheduleErrors, DisableBackupScheduleResponses, DisableMfaData, DisableMfaErrors, DisableMfaResponses, DiscoverWorkloadsData, DiscoverWorkloadsErrors, DiscoverWorkloadsResponses, DomainData, DomainErrors, DomainResponses, DownloadGlobalSkillArchiveData, DownloadGlobalSkillArchiveErrors, DownloadGlobalSkillArchiveResponses, DownloadObjectData, DownloadObjectErrors, DownloadObjectResponses, DownloadSkillArchiveData, DownloadSkillArchiveErrors, DownloadSkillArchiveResponses, EmailStatusData, EmailStatusErrors, EmailStatusResponses, EmbeddingsData, EmbeddingsErrors, EmbeddingsResponses, EnableBackupScheduleData, EnableBackupScheduleErrors, EnableBackupScheduleResponses, EnrichVisitorData, EnrichVisitorErrors, EnrichVisitorResponses, ExecData, ExecDetachedData, ExecDetachedErrors, ExecDetachedResponses, ExecErrors, ExecResponses, ExecuteDeploymentOperationData, ExecuteDeploymentOperationErrors, ExecuteDeploymentOperationResponses, ExecuteImportData, ExecuteImportErrors, ExecuteImportResponses, ExtendTimeoutData, ExtendTimeoutErrors, ExtendTimeoutResponses, ExternalServiceEnablePgStatStatementsData, ExternalServiceEnablePgStatStatementsErrors, ExternalServiceEnablePgStatStatementsResponses, ExternalServiceMetricsByDatabaseData, ExternalServiceMetricsByDatabaseErrors, ExternalServiceMetricsByDatabaseResponses, ExternalServiceMetricsCreateAlertRuleData, ExternalServiceMetricsCreateAlertRuleErrors, ExternalServiceMetricsCreateAlertRuleResponses, ExternalServiceMetricsDeleteAlertRuleData, ExternalServiceMetricsDeleteAlertRuleErrors, ExternalServiceMetricsDeleteAlertRuleResponses, ExternalServiceMetricsGetAlertRulesData, ExternalServiceMetricsGetAlertRulesErrors, ExternalServiceMetricsGetAlertRulesResponses, ExternalServiceMetricsGetLatestData, ExternalServiceMetricsGetLatestErrors, ExternalServiceMetricsGetLatestResponses, ExternalServiceMetricsGetRangeData, ExternalServiceMetricsGetRangeErrors, ExternalServiceMetricsGetRangeResponses, ExternalServiceMetricsStatusData, ExternalServiceMetricsStatusErrors, ExternalServiceMetricsStatusResponses, ExternalServiceMetricsToggleData, ExternalServiceMetricsToggleErrors, ExternalServiceMetricsToggleResponses, ExternalServiceMetricsUpdateAlertRuleData, ExternalServiceMetricsUpdateAlertRuleErrors, ExternalServiceMetricsUpdateAlertRuleResponses, ExternalServiceResetPgStatStatementsData, ExternalServiceResetPgStatStatementsErrors, ExternalServiceResetPgStatStatementsResponses, FinalizeOrderData, FinalizeOrderErrors, FinalizeOrderResponses, FinalizeProjectReleaseData, FinalizeProjectReleaseErrors, FinalizeProjectReleaseResponses, FindConversationData, FindConversationErrors, FindConversationResponses, GenerateJoinTokenData, GenerateJoinTokenErrors, GenerateJoinTokenResponses, GeneratePresetDockerfileData, GeneratePresetDockerfileErrors, GeneratePresetDockerfileResponses, GetAccessInfoData, GetAccessInfoErrors, GetAccessInfoResponses, GetActiveVisitorsData, GetActiveVisitorsErrors, GetActiveVisitorsResponses, GetActivityGraphData, GetActivityGraphErrors, GetActivityGraphResponses, GetAdminGateData, GetAdminGateErrors, GetAdminGateResponses, GetAgentData, GetAgentErrors, GetAgentResponses, GetAggregatedBucketsData, GetAggregatedBucketsErrors, GetAggregatedBucketsResponses, GetAiAgentBreakdownData, GetAiAgentBreakdownErrors, GetAiAgentBreakdownResponses, GetAiAgentPagesData, GetAiAgentPagesErrors, GetAiAgentPagesResponses, GetAiAgentTimelineData, GetAiAgentTimelineErrors, GetAiAgentTimelineResponses, GetAiPageBreakdownData, GetAiPageBreakdownErrors, GetAiPageBreakdownResponses, GetAiStatusBreakdownData, GetAiStatusBreakdownErrors, GetAiStatusBreakdownResponses, GetAlertData, GetAlertErrors, GetAlertResponses, GetAlertRuleData, GetAlertRuleErrors, GetAlertRuleResponses, GetAllRepositoriesByNameData, GetAllRepositoriesByNameErrors, GetAllRepositoriesByNameResponses, GetAnalyticsActiveVisitorsData, GetAnalyticsActiveVisitorsErrors, GetAnalyticsActiveVisitorsResponses, GetAnalyticsEventsCountData, GetAnalyticsEventsCountErrors, GetAnalyticsEventsCountResponses, GetAnalyticsSessionEventsData, GetAnalyticsSessionEventsErrors, GetAnalyticsSessionEventsResponses, GetAnalyticsVisitorSessionsData, GetAnalyticsVisitorSessionsErrors, GetAnalyticsVisitorSessionsResponses, GetApiKeyData, GetApiKeyErrors, GetApiKeyPermissionsData, GetApiKeyPermissionsErrors, GetApiKeyPermissionsResponses, GetApiKeyResponses, GetAuditLogData, GetAuditLogErrors, GetAuditLogResponses, GetBackupData, GetBackupErrors, GetBackupResponses, GetBackupScheduleData, GetBackupScheduleErrors, GetBackupScheduleResponses, GetBranchesByRepositoryIdData, GetBranchesByRepositoryIdErrors, GetBranchesByRepositoryIdResponses, GetBucketedIncidentsData, GetBucketedIncidentsErrors, GetBucketedIncidentsResponses, GetBucketedStatusData, GetBucketedStatusErrors, GetBucketedStatusResponses, GetChallengeTokenData, GetChallengeTokenErrors, GetChallengeTokenResponses, GetChatReadinessData, GetChatReadinessErrors, GetChatReadinessResponses, GetCliStatusData, GetCliStatusErrors, GetCliStatusResponses, GetClusterHealthData, GetClusterHealthErrors, GetClusterHealthResponses, GetClusterMemberData, GetClusterMemberErrors, GetClusterMemberResponses, GetCmdData, GetCmdErrors, GetCmdResponses, GetContainerDetailData, GetContainerDetailErrors, GetContainerDetailResponses, GetContainerEnvironmentVariableData, GetContainerEnvironmentVariableErrors, GetContainerEnvironmentVariableResponses, GetContainerInfoData, GetContainerInfoErrors, GetContainerInfoResponses, GetContainerLogsByIdData, GetContainerLogsByIdErrors, GetContainerLogsData, GetContainerLogsErrors, GetContainerMetricsData, GetContainerMetricsErrors, GetContainerMetricsResponses, GetConversationData, GetConversationDetailData, GetConversationDetailErrors, GetConversationDetailResponses, GetConversationErrors, GetConversationResponses, GetConversationsData, GetConversationsErrors, GetConversationsResponses, GetCronByIdData, GetCronByIdErrors, GetCronByIdResponses, GetCronExecutionsData, GetCronExecutionsErrors, GetCronExecutionsResponses, GetCrossProjectTraceSiblingsData, GetCrossProjectTraceSiblingsErrors, GetCrossProjectTraceSiblingsResponses, GetCurrentMonitorStatusData, GetCurrentMonitorStatusErrors, GetCurrentMonitorStatusResponses, GetCurrentUserData, GetCurrentUserErrors, GetCurrentUserResponses, GetCustomDomainData, GetCustomDomainErrors, GetCustomDomainResponses, GetDashboardData, GetDashboardErrors, GetDashboardProjectsAnalyticsData, GetDashboardProjectsAnalyticsErrors, GetDashboardProjectsAnalyticsResponses, GetDashboardResponses, GetDeliveryData, GetDeliveryErrors, GetDeliveryResponses, GetDeploymentContainerLogContentData, GetDeploymentContainerLogContentErrors, GetDeploymentContainerLogContentResponses, GetDeploymentData, GetDeploymentErrors, GetDeploymentJobLogsData, GetDeploymentJobLogsErrors, GetDeploymentJobLogsResponses, GetDeploymentJobsData, GetDeploymentJobsErrors, GetDeploymentJobsResponses, GetDeploymentOperationsData, GetDeploymentOperationsErrors, GetDeploymentOperationsResponses, GetDeploymentOperationStatusData, GetDeploymentOperationStatusErrors, GetDeploymentOperationStatusResponses, GetDeploymentResponses, GetDeploymentTokenData, GetDeploymentTokenErrors, GetDeploymentTokenResponses, GetDiskStatusData, GetDiskStatusErrors, GetDiskStatusResponses, GetDnsChangesData, GetDnsChangesErrors, GetDnsChangesResponses, GetDnsProviderData, GetDnsProviderErrors, GetDnsProviderResponses, GetDomainByHostData, GetDomainByHostErrors, GetDomainByHostResponses, GetDomainByIdData, GetDomainByIdErrors, GetDomainByIdResponses, GetDomainByNameData, GetDomainByNameErrors, GetDomainByNameResponses, GetDomainData, GetDomainDnsRecordsData, GetDomainDnsRecordsErrors, GetDomainDnsRecordsResponses, GetDomainErrors, GetDomainOrderData, GetDomainOrderErrors, GetDomainOrderResponses, GetDomainResponses, GetEmailData, GetEmailErrors, GetEmailEventsData, GetEmailEventsErrors, GetEmailEventsResponses, GetEmailLinksData, GetEmailLinksErrors, GetEmailLinksResponses, GetEmailProviderData, GetEmailProviderErrors, GetEmailProviderResponses, GetEmailResponses, GetEmailStatsData, GetEmailStatsErrors, GetEmailStatsResponses, GetEmailTrackingData, GetEmailTrackingErrors, GetEmailTrackingResponses, GetEmailTrackingStatusData, GetEmailTrackingStatusErrors, GetEmailTrackingStatusResponses, GetEntityInfoData, GetEntityInfoErrors, GetEntityInfoResponses, GetEnvironmentCronsData, GetEnvironmentCronsErrors, GetEnvironmentCronsResponses, GetEnvironmentData, GetEnvironmentDomainsData, GetEnvironmentDomainsErrors, GetEnvironmentDomainsResponses, GetEnvironmentErrors, GetEnvironmentResponses, GetEnvironmentsData, GetEnvironmentsErrors, GetEnvironmentsResponses, GetEnvironmentVariablesData, GetEnvironmentVariablesErrors, GetEnvironmentVariablesResponses, GetEnvironmentVariableValueData, GetEnvironmentVariableValueErrors, GetEnvironmentVariableValueResponses, GetErrorDashboardStatsData, GetErrorDashboardStatsErrors, GetErrorDashboardStatsResponses, GetErrorEventData, GetErrorEventErrors, GetErrorEventResponses, GetErrorGroupData, GetErrorGroupErrors, GetErrorGroupResponses, GetErrorStatsData, GetErrorStatsErrors, GetErrorStatsResponses, GetErrorTimeSeriesData, GetErrorTimeSeriesErrors, GetErrorTimeSeriesResponses, GetEventDetailData, GetEventDetailErrors, GetEventDetailResponses, GetEventEntriesData, GetEventEntriesErrors, GetEventEntriesResponses, GetEventsCountData, GetEventsCountErrors, GetEventsCountResponses, GetEventsTimelineData, GetEventsTimelineErrors, GetEventsTimelineResponses, GetEventTypeBreakdownData, GetEventTypeBreakdownErrors, GetEventTypeBreakdownResponses, GetEventVisitorsData, GetEventVisitorsErrors, GetEventVisitorsResponses, GetExternalImageData, GetExternalImageErrors, GetExternalImageResponses, GetFileData, GetFileErrors, GetFileResponses, GetFlagData, GetFlagErrors, GetFlagResponses, GetFlagSnapshotData, GetFlagSnapshotErrors, GetFlagSnapshotResponses, GetFunnelMetricsData, GetFunnelMetricsErrors, GetFunnelMetricsResponses, GetGenaiTraceData, GetGenaiTraceErrors, GetGenaiTraceResponses, GetGeneralStatsData, GetGeneralStatsErrors, GetGeneralStatsResponses, GetGitProviderData, GetGitProviderErrors, GetGitProviderResponses, GetGlobalEventsData, GetGlobalEventsErrors, GetGlobalEventsResponses, GetGlobalEventStatsData, GetGlobalEventStatsErrors, GetGlobalEventStatsResponses, GetGlobalMcpData, GetGlobalMcpErrors, GetGlobalMcpResponses, GetGlobalSandboxStatusData, GetGlobalSandboxStatusErrors, GetGlobalSandboxStatusResponses, GetGlobalSkillData, GetGlobalSkillErrors, GetGlobalSkillResponses, GetGroupedPageMetricsData, GetGroupedPageMetricsErrors, GetGroupedPageMetricsResponses, GetHealthData, GetHealthErrors, GetHealthResponses, GetHourlyVisitsData, GetHourlyVisitsErrors, GetHourlyVisitsResponses, GetHttpChallengeDebugData, GetHttpChallengeDebugErrors, GetHttpChallengeDebugResponses, GetImportStatusData, GetImportStatusErrors, GetImportStatusResponses, GetIncidentData, GetIncidentErrors, GetIncidentResponses, GetIncidentUpdatesData, GetIncidentUpdatesErrors, GetIncidentUpdatesResponses, GetIpAccessControlData, GetIpAccessControlErrors, GetIpAccessControlResponses, GetIpGeolocationData, GetIpGeolocationErrors, GetIpGeolocationResponses, GetJoinTokenStatusData, GetJoinTokenStatusErrors, GetJoinTokenStatusResponses, GetLastDeploymentData, GetLastDeploymentErrors, GetLastDeploymentResponses, GetLatestScanData, GetLatestScanErrors, GetLatestScanResponses, GetLatestScansPerEnvironmentData, GetLatestScansPerEnvironmentErrors, GetLatestScansPerEnvironmentResponses, GetLiveVisitorsListData, GetLiveVisitorsListErrors, GetLiveVisitorsListResponses, GetLogContextData, GetLogContextErrors, GetLogContextResponses, GetMcpData, GetMcpErrors, GetMcpResponses, GetMetricsOverTimeData, GetMetricsOverTimeErrors, GetMetricsOverTimeResponses, GetMonitorData, GetMonitorErrors, GetMonitorResponses, GetNotificationProviderData, GetNotificationProviderErrors, GetNotificationProviderResponses, GetOnDemandCertStatusData, GetOnDemandCertStatusErrors, GetOnDemandCertStatusResponses, GetOrCreateDsnData, GetOrCreateDsnErrors, GetOrCreateDsnResponses, GetPageFlowData, GetPageFlowErrors, GetPageFlowResponses, GetPageHourlySessionsData, GetPageHourlySessionsErrors, GetPageHourlySessionsResponses, GetPagePathDetailData, GetPagePathDetailErrors, GetPagePathDetailResponses, GetPagePathsData, GetPagePathsErrors, GetPagePathsResponses, GetPagePathsSparklinesData, GetPagePathsSparklinesErrors, GetPagePathsSparklinesResponses, GetPagePathVisitorsData, GetPagePathVisitorsErrors, GetPagePathVisitorsResponses, GetPendingActionData, GetPendingActionErrors, GetPendingActionResponses, GetPerformanceMetricsData, GetPerformanceMetricsErrors, GetPerformanceMetricsResponses, GetPgUpgradeData, GetPgUpgradeErrors, GetPgUpgradeLogsData, GetPgUpgradeLogsErrors, GetPgUpgradeLogsResponses, GetPgUpgradeResponses, GetPipelineStatsData, GetPipelineStatsErrors, GetPipelineStatsResponses, GetPlatformInfoData, GetPlatformInfoErrors, GetPlatformInfoResponses, GetPostgresWalHealthData, GetPostgresWalHealthErrors, GetPostgresWalHealthResponses, GetPreferencesData, GetPreferencesErrors, GetPreferencesResponses, GetPreviewGatewayLogsData, GetPreviewGatewayLogsResponses, GetPreviewGatewaySettingsData, GetPreviewGatewaySettingsResponses, GetPreviewGatewayStatusData, GetPreviewGatewayStatusResponses, GetPricingData, GetPricingErrors, GetPricingResponses, GetPrivateIpData, GetPrivateIpErrors, GetPrivateIpResponses, GetProjectAlarmsSummaryData, GetProjectAlarmsSummaryErrors, GetProjectAlarmsSummaryResponses, GetProjectBySlugData, GetProjectBySlugErrors, GetProjectBySlugResponses, GetProjectData, GetProjectDeploymentsData, GetProjectDeploymentsErrors, GetProjectDeploymentsResponses, GetProjectErrors, GetProjectResponses, GetProjectsData, GetProjectsErrors, GetProjectServiceEnvironmentVariablesData, GetProjectServiceEnvironmentVariablesErrors, GetProjectServiceEnvironmentVariablesResponses, GetProjectSessionReplaysData, GetProjectSessionReplaysErrors, GetProjectSessionReplaysResponses, GetProjectsHealthData, GetProjectsHealthErrors, GetProjectsHealthResponses, GetProjectsMonitorHealthData, GetProjectsMonitorHealthErrors, GetProjectsMonitorHealthResponses, GetProjectsResponses, GetProjectStatisticsData, GetProjectStatisticsErrors, GetProjectStatisticsResponses, GetProjectTemplateData, GetProjectTemplateErrors, GetProjectTemplateResponses, GetPropertyBreakdownData, GetPropertyBreakdownErrors, GetPropertyBreakdownResponses, GetPropertyTimelineData, GetPropertyTimelineErrors, GetPropertyTimelineResponses, GetProviderConnectionsData, GetProviderConnectionsErrors, GetProviderConnectionsResponses, GetProviderMetadataData, GetProviderMetadataErrors, GetProviderMetadataResponses, GetProvidersMetadataData, GetProvidersMetadataErrors, GetProvidersMetadataResponses, GetProxyLogByIdData, GetProxyLogByIdErrors, GetProxyLogByIdResponses, GetProxyLogByRequestIdData, GetProxyLogByRequestIdErrors, GetProxyLogByRequestIdResponses, GetProxyLogsData, GetProxyLogsErrors, GetProxyLogsResponses, GetPublicBranchesData, GetPublicBranchesErrors, GetPublicBranchesResponses, GetPublicIpData, GetPublicIpErrors, GetPublicIpResponses, GetPublicRepositoryData, GetPublicRepositoryErrors, GetPublicRepositoryResponses, GetQuotaData, GetQuotaErrors, GetQuotaResponses, GetRecentActivityData, GetRecentActivityErrors, GetRecentActivityResponses, GetRemoteExternalImageData, GetRemoteExternalImageErrors, GetRemoteExternalImageResponses, GetRepositoryBranchesData, GetRepositoryBranchesErrors, GetRepositoryBranchesResponses, GetRepositoryByIdData, GetRepositoryByIdErrors, GetRepositoryByIdResponses, GetRepositoryByNameData, GetRepositoryByNameErrors, GetRepositoryByNameResponses, GetRepositoryPresetByNameData, GetRepositoryPresetByNameErrors, GetRepositoryPresetByNameResponses, GetRepositoryPresetLiveData, GetRepositoryPresetLiveErrors, GetRepositoryPresetLiveResponses, GetRepositoryTagsData, GetRepositoryTagsErrors, GetRepositoryTagsResponses, GetResolvedEnvironmentVariablesData, GetResolvedEnvironmentVariablesErrors, GetResolvedEnvironmentVariablesResponses, GetResolvedEnvironmentVariableValueData, GetResolvedEnvironmentVariableValueErrors, GetResolvedEnvironmentVariableValueResponses, GetRestoreCapabilitiesData, GetRestoreCapabilitiesErrors, GetRestoreCapabilitiesResponses, GetRestoreRunData, GetRestoreRunErrors, GetRestoreRunResponses, GetRouteData, GetRouteErrors, GetRouteResponses, GetRunData, GetRunErrors, GetRunResponses, GetRunWithLogsData, GetRunWithLogsErrors, GetRunWithLogsResponses, GetS3CredentialsData, GetS3CredentialsErrors, GetS3CredentialsResponses, GetS3SourceData, GetS3SourceErrors, GetS3SourceResponses, GetSandboxData, GetSandboxErrors, GetSandboxResponses, GetSandboxStatusData, GetSandboxStatusErrors, GetSandboxStatusResponses, GetScanByDeploymentData, GetScanByDeploymentErrors, GetScanByDeploymentResponses, GetScanData, GetScanErrors, GetScanResponses, GetScanVulnerabilitiesData, GetScanVulnerabilitiesErrors, GetScanVulnerabilitiesResponses, GetServiceBySlugData, GetServiceBySlugErrors, GetServiceBySlugResponses, GetServiceData, GetServiceEnvironmentVariableData, GetServiceEnvironmentVariableErrors, GetServiceEnvironmentVariableResponses, GetServiceEnvironmentVariablesData, GetServiceEnvironmentVariablesErrors, GetServiceEnvironmentVariablesResponses, GetServiceErrors, GetServiceHealthStatusData, GetServiceHealthStatusErrors, GetServiceHealthStatusResponses, GetServicePreviewEnvironmentVariableNamesData, GetServicePreviewEnvironmentVariableNamesErrors, GetServicePreviewEnvironmentVariableNamesResponses, GetServicePreviewEnvironmentVariablesMaskedData, GetServicePreviewEnvironmentVariablesMaskedErrors, GetServicePreviewEnvironmentVariablesMaskedResponses, GetServiceResponses, GetServiceRuntimeData, GetServiceRuntimeErrors, GetServiceRuntimeResponses, GetServiceStatsData, GetServiceStatsErrors, GetServiceStatsResponses, GetServiceTypeParametersData, GetServiceTypeParametersErrors, GetServiceTypeParametersResponses, GetServiceTypesData, GetServiceTypesErrors, GetServiceTypesResponses, GetSessionDetailsData, GetSessionDetailsErrors, GetSessionDetailsResponses, GetSessionEventsData, GetSessionEventsErrors, GetSessionEventsResponses, GetSessionLogsData, GetSessionLogsErrors, GetSessionLogsResponses, GetSessionReplayData, GetSessionReplayErrors, GetSessionReplayEventsData, GetSessionReplayEventsErrors, GetSessionReplayEventsResponses, GetSessionReplayResponses, GetSettingsData, GetSettingsErrors, GetSettingsResponses, GetSkillData, GetSkillErrors, GetSkillResponses, GetSlowQueriesData, GetSlowQueriesErrors, GetSlowQueriesResponses, GetStaticBundleData, GetStaticBundleErrors, GetStaticBundleResponses, GetStatusOverviewData, GetStatusOverviewErrors, GetStatusOverviewResponses, GetTagsByRepositoryIdData, GetTagsByRepositoryIdErrors, GetTagsByRepositoryIdResponses, GetTeamData, GetTeamErrors, GetTeamResponses, GetTimeBucketStatsData, GetTimeBucketStatsErrors, GetTimeBucketStatsResponses, GetTodayStatsData, GetTodayStatsErrors, GetTodayStatsResponses, GetTraceData, GetTraceErrors, GetTraceResponses, GetUnifiedTraceData, GetUnifiedTraceErrors, GetUnifiedTraceResponses, GetUniqueCountsData, GetUniqueCountsErrors, GetUniqueCountsResponses, GetUniqueEventsData, GetUniqueEventsErrors, GetUniqueEventsResponses, GetUpdateStatusData, GetUpdateStatusErrors, GetUpdateStatusResponses, GetUptimeHistoryData, GetUptimeHistoryErrors, GetUptimeHistoryResponses, GetUsageByProviderData, GetUsageByProviderErrors, GetUsageByProviderResponses, GetUsageRecentData, GetUsageRecentErrors, GetUsageRecentResponses, GetUsageSummaryData, GetUsageSummaryErrors, GetUsageSummaryResponses, GetUsageTimeseriesData, GetUsageTimeseriesErrors, GetUsageTimeseriesResponses, GetUsageTopModelsData, GetUsageTopModelsErrors, GetUsageTopModelsResponses, GetVisitorByGuidData, GetVisitorByGuidErrors, GetVisitorByGuidResponses, GetVisitorByIdData, GetVisitorByIdErrors, GetVisitorByIdResponses, GetVisitorDetailsData, GetVisitorDetailsErrors, GetVisitorDetailsResponses, GetVisitorFacetsData, GetVisitorFacetsErrors, GetVisitorFacetsResponses, GetVisitorInfoData, GetVisitorInfoErrors, GetVisitorInfoResponses, GetVisitorJourneyData, GetVisitorJourneyErrors, GetVisitorJourneyResponses, GetVisitorsData, GetVisitorsErrors, GetVisitorSessionsData, GetVisitorSessionsErrors, GetVisitorSessionsResponses, GetVisitorsResponses, GetVisitorStatsData, GetVisitorStatsErrors, GetVisitorStatsResponses, GetWebhookData, GetWebhookErrors, GetWebhookResponses, GrantProjectAccessData, GrantProjectAccessErrors, GrantProjectAccessResponses, HandleGitProviderOauthCallbackData, HandleGitProviderOauthCallbackErrors, HasAnalyticsEventsData, HasAnalyticsEventsErrors, HasAnalyticsEventsResponses, HasErrorGroupsData, HasErrorGroupsErrors, HasErrorGroupsResponses, HasPerformanceMetricsData, HasPerformanceMetricsErrors, HasPerformanceMetricsResponses, ImportExternalServiceData, ImportExternalServiceErrors, ImportExternalServiceResponses, IngestLogsByPathData, IngestLogsByPathErrors, IngestLogsByPathResponses, IngestLogsData, IngestLogsErrors, IngestLogsResponses, IngestMetricsByPathData, IngestMetricsByPathErrors, IngestMetricsByPathResponses, IngestMetricsData, IngestMetricsErrors, IngestMetricsResponses, IngestSentryEnvelopeData, IngestSentryEnvelopeErrors, IngestSentryEnvelopeResponses, IngestSentryEventData, IngestSentryEventErrors, IngestSentryEventResponses, IngestTracesByPathData, IngestTracesByPathErrors, IngestTracesByPathResponses, IngestTracesData, IngestTracesErrors, IngestTracesResponses, InitSessionReplayData, InitSessionReplayErrors, InitSessionReplayResponses, InspectDropArchiveData, InspectDropArchiveErrors, InspectDropArchiveResponses, JobLogsData, JobLogsErrors, JobLogsResponses, JobStatusData, JobStatusErrors, JobStatusResponses, KillJobData, KillJobErrors, KillJobResponses, KvDelData, KvDelErrors, KvDelResponses, KvDisableData, KvDisableErrors, KvDisableResponses, KvEnableData, KvEnableErrors, KvEnableResponses, KvExpireData, KvExpireErrors, KvExpireResponses, KvGetData, KvGetErrors, KvGetResponses, KvIncrData, KvIncrErrors, KvIncrResponses, KvKeysData, KvKeysErrors, KvKeysResponses, KvSetData, KvSetErrors, KvSetResponses, KvStatusData, KvStatusErrors, KvStatusResponses, KvTtlData, KvTtlErrors, KvTtlResponses, KvUpdateData, KvUpdateErrors, KvUpdateResponses, LatestRunForSourceData, LatestRunForSourceErrors, LatestRunForSourceResponses, LinkCustomDomainToCertificateData, LinkCustomDomainToCertificateErrors, LinkCustomDomainToCertificateResponses, LinkServiceToProjectData, LinkServiceToProjectErrors, LinkServiceToProjectResponses, ListAgentRunsData, ListAgentRunsErrors, ListAgentRunsResponses, ListAgentsData, ListAgentsErrors, ListAgentsResponses, ListAiProvidersData, ListAiProvidersErrors, ListAiProvidersResponses, ListAlertRulesData, ListAlertRulesErrors, ListAlertRulesResponses, ListAlertsData, ListAlertsErrors, ListAlertsResponses, ListAllConversationsData, ListAllConversationsErrors, ListAllConversationsResponses, ListAllRunsData, ListAllRunsErrors, ListAllRunsResponses, ListApiKeysData, ListApiKeysErrors, ListApiKeysResponses, ListAuditLogsData, ListAuditLogsErrors, ListAuditLogsResponses, ListAvailableContainersData, ListAvailableContainersErrors, ListAvailableContainersResponses, ListBackupAlertsData, ListBackupAlertsErrors, ListBackupAlertsResponses, ListBackupChildrenData, ListBackupChildrenErrors, ListBackupChildrenResponses, ListBackupSchedulesData, ListBackupSchedulesErrors, ListBackupSchedulesResponses, ListBackupsForScheduleData, ListBackupsForScheduleErrors, ListBackupsForScheduleResponses, ListCommitsByRepositoryIdData, ListCommitsByRepositoryIdErrors, ListCommitsByRepositoryIdResponses, ListConnectionsData, ListConnectionsErrors, ListConnectionsResponses, ListContainersAtPathData, ListContainersAtPathErrors, ListContainersAtPathResponses, ListContainersData, ListContainersErrors, ListContainersResponses, ListConversationsData, ListConversationsErrors, ListConversationsResponses, ListCustomDomainsForProjectData, ListCustomDomainsForProjectErrors, ListCustomDomainsForProjectResponses, ListDashboardsData, ListDashboardsErrors, ListDashboardsResponses, ListDeliveriesData, ListDeliveriesErrors, ListDeliveriesResponses, ListDeploymentContainerLogsData, ListDeploymentContainerLogsErrors, ListDeploymentContainerLogsResponses, ListDeploymentTokensData, ListDeploymentTokensErrors, ListDeploymentTokensResponses, ListDnsProvidersData, ListDnsProvidersErrors, ListDnsProvidersResponses, ListDomainsData, ListDomainsErrors, ListDomainsResponses, ListDsnsData, ListDsnsErrors, ListDsnsResponses, ListEmailDomainsData, ListEmailDomainsErrors, ListEmailDomainsResponses, ListEmailProvidersData, ListEmailProvidersErrors, ListEmailProvidersResponses, ListEmailsData, ListEmailsErrors, ListEmailsResponses, ListEnrollmentTokensData, ListEnrollmentTokensErrors, ListEnrollmentTokensResponses, ListEntitiesData, ListEntitiesErrors, ListEntitiesResponses, ListErrorEventsData, ListErrorEventsErrors, ListErrorEventsResponses, ListErrorGroupsData, ListErrorGroupsErrors, ListErrorGroupsResponses, ListEventsData, ListEventsResponses, ListEventTypesData, ListEventTypesResponses, ListExternalImagesData, ListExternalImagesErrors, ListExternalImagesResponses, ListExternalPluginsData, ListExternalPluginsErrors, ListExternalPluginsResponses, ListExternalServiceBackupsData, ListExternalServiceBackupsErrors, ListExternalServiceBackupsResponses, ListFlagsData, ListFlagsErrors, ListFlagsResponses, ListFunnelsData, ListFunnelsErrors, ListFunnelsResponses, ListGitProvidersData, ListGitProvidersErrors, ListGitProvidersResponses, ListGlobalMcpsData, ListGlobalMcpsErrors, ListGlobalMcpsResponses, ListGlobalSkillsData, ListGlobalSkillsErrors, ListGlobalSkillsResponses, ListIncidentsData, ListIncidentsErrors, ListIncidentsResponses, ListInsightsData, ListInsightsErrors, ListInsightsResponses, ListIpAccessControlData, ListIpAccessControlErrors, ListIpAccessControlResponses, ListJobsData, ListJobsErrors, ListJobsResponses, ListKnownAiAgentsData, ListKnownAiAgentsErrors, ListKnownAiAgentsResponses, ListManagedDomainsData, ListManagedDomainsErrors, ListManagedDomainsResponses, ListMcpsData, ListMcpsErrors, ListMcpsResponses, ListMetricLabelKeysData, ListMetricLabelKeysErrors, ListMetricLabelKeysResponses, ListMetricLabelValuesData, ListMetricLabelValuesErrors, ListMetricLabelValuesResponses, ListMetricNamesData, ListMetricNamesErrors, ListMetricNamesResponses, ListModelsData, ListModelsErrors, ListModelsResponses, ListMonitorsData, ListMonitorsErrors, ListMonitorsResponses, ListNotificationProvidersData, ListNotificationProvidersErrors, ListNotificationProvidersResponses, ListOidcProvidersData, ListOidcProvidersResponses, ListOidcProviderUsersData, ListOidcProviderUsersErrors, ListOidcProviderUsersResponses, ListOidcRoleMappingsData, ListOidcRoleMappingsResponses, ListOnDemandCertsData, ListOnDemandCertsErrors, ListOnDemandCertsResponses, ListOrdersData, ListOrdersErrors, ListOrdersResponses, ListPeersData, ListPeersErrors, ListPeersResponses, ListPendingActionsData, ListPendingActionsErrors, ListPendingActionsResponses, ListPgUpgradesData, ListPgUpgradesErrors, ListPgUpgradesResponses, ListPresetsData, ListPresetsErrors, ListPresetsResponses, ListProjectAccessData, ListProjectAccessErrors, ListProjectAccessResponses, ListProjectAlarmsData, ListProjectAlarmsErrors, ListProjectAlarmsResponses, ListProjectScansData, ListProjectScansErrors, ListProjectScansResponses, ListProjectSecretsData, ListProjectSecretsErrors, ListProjectSecretsResponses, ListProjectServicesData, ListProjectServicesErrors, ListProjectServicesResponses, ListProjectTemplatesData, ListProjectTemplatesErrors, ListProjectTemplatesResponses, ListProjectTemplateTagsData, ListProjectTemplateTagsErrors, ListProjectTemplateTagsResponses, ListProviderKeysData, ListProviderKeysErrors, ListProviderKeysResponses, ListProviderZonesData, ListProviderZonesErrors, ListProviderZonesResponses, ListPublicProvidersData, ListPublicProvidersResponses, ListReleaseFilesData, ListReleaseFilesErrors, ListReleaseFilesResponses, ListReleasesData, ListReleasesErrors, ListReleasesResponses, ListRemoteExternalImagesData, ListRemoteExternalImagesErrors, ListRemoteExternalImagesResponses, ListRepositoriesByConnectionData, ListRepositoriesByConnectionErrors, ListRepositoriesByConnectionResponses, ListRepositoriesByProviderData, ListRepositoriesByProviderErrors, ListRepositoriesByProviderResponses, ListRestoreRunsForServiceData, ListRestoreRunsForServiceResponses, ListRootContainersData, ListRootContainersErrors, ListRootContainersResponses, ListRoutesData, ListRoutesErrors, ListRoutesResponses, ListS3SourcesData, ListS3SourcesErrors, ListS3SourcesResponses, ListSandboxesData, ListSandboxesResponses, ListScheduleRunJobsData, ListScheduleRunJobsErrors, ListScheduleRunJobsResponses, ListScheduleRunsData, ListScheduleRunsErrors, ListScheduleRunsResponses, ListScheduleServicesData, ListScheduleServicesErrors, ListScheduleServicesResponses, ListSecretsData, ListSecretsErrors, ListSecretsResponses, ListServiceHealthStatusesData, ListServiceHealthStatusesErrors, ListServiceHealthStatusesResponses, ListServiceProjectsData, ListServiceProjectsErrors, ListServiceProjectsResponses, ListServiceSchedulesData, ListServiceSchedulesErrors, ListServiceSchedulesResponses, ListServicesData, ListServicesErrors, ListServicesResponses, ListSkillsData, ListSkillsErrors, ListSkillsResponses, ListSourceBackupsData, ListSourceBackupsErrors, ListSourceBackupsResponses, ListSourceFilesData, ListSourceFilesErrors, ListSourceFilesResponses, ListSourceMapsData, ListSourceMapsErrors, ListSourceMapsResponses, ListSourcesData, ListSourcesErrors, ListSourcesResponses, ListStaticBundlesData, ListStaticBundlesErrors, ListStaticBundlesResponses, ListSyncedRepositoriesData, ListSyncedRepositoriesErrors, ListSyncedRepositoriesResponses, ListTeamMembersData, ListTeamMembersErrors, ListTeamMembersResponses, ListTeamProjectsData, ListTeamProjectsErrors, ListTeamProjectsResponses, ListTeamsData, ListTeamsErrors, ListTeamsResponses, ListUsersData, ListUsersErrors, ListUsersResponses, ListWebhooksData, ListWebhooksErrors, ListWebhooksResponses, LoginData, LoginErrors, LoginResponses, LogoutData, LogoutErrors, LogoutResponses, LookupDnsARecordsData, LookupDnsARecordsErrors, LookupDnsARecordsResponses, MintEnrollmentTokenData, MintEnrollmentTokenErrors, MintEnrollmentTokenResponses, MkdirData, MkdirErrors, MkdirResponses, NodeHeartbeatData, NodeHeartbeatErrors, NodeHeartbeatResponses, NodeMetricsGetRangeData, NodeMetricsGetRangeErrors, NodeMetricsGetRangeResponses, ObservabilityFullEventData, ObservabilityFullEventErrors, ObservabilityFullEventResponses, ObservabilityListEventsData, ObservabilityListEventsErrors, ObservabilityListEventsResponses, OidcCallbackData, PatchAdminGateData, PatchAdminGateErrors, PatchAdminGateResponses, PatchPreviewGatewaySettingsData, PatchPreviewGatewaySettingsResponses, PauseDeploymentData, PauseDeploymentErrors, PauseDeploymentResponses, PauseSandboxData, PauseSandboxErrors, PauseSandboxResponses, PlanRestoreData, PlanRestoreErrors, PlanRestoreResponses, PostDnsAckData, PostDnsAckErrors, PostDnsAckResponses, PreviewAlertData, PreviewAlertErrors, PreviewAlertResponses, PreviewFunnelMetricsData, PreviewFunnelMetricsErrors, PreviewFunnelMetricsResponses, PreviewHostnameModeData, PreviewHostnameModeErrors, PreviewHostnameModeResponses, PromoteClusterMemberData, PromoteClusterMemberErrors, PromoteClusterMemberResponses, PromoteDeploymentData, PromoteDeploymentErrors, PromoteDeploymentResponses, ProvisionDomainData, ProvisionDomainErrors, ProvisionDomainResponses, PurgeProjectLogsData, PurgeProjectLogsErrors, PurgeProjectLogsResponses, PushExternalImageData, PushExternalImageErrors, PushExternalImageResponses, QueryDataData, QueryDataErrors, QueryDataResponses, QueryGenaiTracesData, QueryGenaiTracesErrors, QueryGenaiTracesResponses, QueryLogsData, QueryLogsErrors, QueryLogsResponses, QueryMetricsData, QueryMetricsErrors, QueryMetricsResponses, QueryTracesData, QueryTracesErrors, QueryTracesResponses, QueryTraceSummariesData, QueryTraceSummariesErrors, QueryTraceSummariesResponses, ReadFileData, ReadFileErrors, ReadFileResponses, ReAnalyzeData, ReAnalyzeErrors, ReAnalyzeResponses, RebuildSandboxImageData, RebuildSandboxImageErrors, RebuildSandboxImageResponses, RecordConsoleEventData, RecordConsoleEventErrors, RecordConsoleEventResponses, RecordEventMetricsData, RecordEventMetricsErrors, RecordEventMetricsResponses, RecordFlagExposureData, RecordFlagExposureErrors, RecordFlagExposureResponses, RecordSpeedMetricsData, RecordSpeedMetricsErrors, RecordSpeedMetricsResponses, RefreshRouteTableData, RefreshRouteTableErrors, RefreshRouteTableResponses, RegenerateDsnData, RegenerateDsnErrors, RegenerateDsnResponses, RegisterExternalImageData, RegisterExternalImageErrors, RegisterExternalImageResponses, RegisterNodeData, RegisterNodeErrors, RegisterNodeResponses, ReinstallGitlabWebhookData, ReinstallGitlabWebhookErrors, ReinstallGitlabWebhookResponses, RejectPendingActionData, RejectPendingActionErrors, RejectPendingActionResponses, ReloadPluginsData, ReloadPluginsErrors, ReloadPluginsResponses, RemoveClusterMemberData, RemoveClusterMemberErrors, RemoveClusterMemberResponses, RemoveManagedDomainData, RemoveManagedDomainErrors, RemoveManagedDomainResponses, RemoveRoleData, RemoveRoleErrors, RemoveRoleResponses, RemoveTeamMemberData, RemoveTeamMemberErrors, RemoveTeamMemberResponses, RenameConversationData, RenameConversationErrors, RenameConversationResponses, RenewDomainData, RenewDomainErrors, RenewDomainResponses, RequestPasswordResetData, RequestPasswordResetErrors, RequestPasswordResetResponses, ResetPasswordData, ResetPasswordErrors, ResetPasswordResponses, ResizeSandboxData, ResizeSandboxErrors, ResizeSandboxResponses, ResolveAlarmData, ResolveAlarmErrors, ResolveAlarmResponses, RestartContainerData, RestartContainerErrors, RestartContainerResponses, RestartPreviewGatewayData, RestartPreviewGatewayResponses, RestartSandboxData, RestartSandboxErrors, RestartSandboxResponses, RestoreFlagData, RestoreFlagErrors, RestoreFlagResponses, RestoreUserData, RestoreUserErrors, RestoreUserResponses, ResumeDeploymentData, ResumeDeploymentErrors, ResumeDeploymentResponses, ResumeSandboxData, ResumeSandboxErrors, ResumeSandboxResponses, RetryClusterData, RetryClusterErrors, RetryClusterResponses, RetryDeliveryData, RetryDeliveryErrors, RetryDeliveryResponses, RetryPgUpgradeData, RetryPgUpgradeErrors, RetryPgUpgradeResponses, RetryRunData, RetryRunErrors, RetryRunResponses, RevealGlobalMcpConfigData, RevealGlobalMcpConfigErrors, RevealGlobalMcpConfigResponses, RevealMcpConfigData, RevealMcpConfigErrors, RevealMcpConfigResponses, RevealNotificationProviderConfigData, RevealNotificationProviderConfigErrors, RevealNotificationProviderConfigResponses, RevealServiceParameterData, RevealServiceParameterErrors, RevealServiceParameterResponses, RevenueCreateIntegrationData, RevenueCreateIntegrationErrors, RevenueCreateIntegrationResponses, RevenueDeleteIntegrationData, RevenueDeleteIntegrationResponses, RevenueGlobalEventsData, RevenueGlobalEventsResponses, RevenueImportInvoicesCsvData, RevenueImportInvoicesCsvErrors, RevenueImportInvoicesCsvResponses, RevenueImportSubscriptionsCsvData, RevenueImportSubscriptionsCsvErrors, RevenueImportSubscriptionsCsvResponses, RevenueListIntegrationsData, RevenueListIntegrationsResponses, RevenueListProvidersData, RevenueListProvidersResponses, RevenueMetricsCustomersData, RevenueMetricsCustomersResponses, RevenueMetricsGlobalMrrData, RevenueMetricsGlobalMrrResponses, RevenueMetricsGlobalSummaryData, RevenueMetricsGlobalSummaryResponses, RevenueMetricsMrrData, RevenueMetricsMrrResponses, RevenueMetricsSummaryData, RevenueMetricsSummaryResponses, RevenueRecentEventsData, RevenueRecentEventsResponses, RevenueRotateTokenData, RevenueRotateTokenResponses, RevenueUpdateConfigData, RevenueUpdateConfigErrors, RevenueUpdateConfigResponses, RevenueUpdateSecretData, RevenueUpdateSecretErrors, RevenueUpdateSecretResponses, RevokeDsnData, RevokeDsnErrors, RevokeDsnResponses, RevokeEnrollmentTokenData, RevokeEnrollmentTokenErrors, RevokeEnrollmentTokenResponses, RevokeJoinTokenData, RevokeJoinTokenErrors, RevokeJoinTokenResponses, RevokeProjectAccessData, RevokeProjectAccessErrors, RevokeProjectAccessResponses, RollbackPgUpgradeData, RollbackPgUpgradeErrors, RollbackPgUpgradeResponses, RollbackToDeploymentData, RollbackToDeploymentErrors, RollbackToDeploymentResponses, RootfsGcData, RootfsGcResponses, RootfsReportData, RootfsReportResponses, RotateApiKeyData, RotateApiKeyErrors, RotateApiKeyResponses, RotateDeploymentTokenData, RotateDeploymentTokenErrors, RotateDeploymentTokenResponses, RunBackupForSourceData, RunBackupForSourceErrors, RunBackupForSourceResponses, RunConnectionHealthCheckData, RunConnectionHealthCheckErrors, RunConnectionHealthCheckResponses, RunExternalServiceBackupData, RunExternalServiceBackupErrors, RunExternalServiceBackupResponses, RunScheduleNowData, RunScheduleNowErrors, RunScheduleNowResponses, SandboxCreatePreviewLinkData, SandboxCreatePreviewLinkErrors, SandboxCreatePreviewLinkResponses, SaveAgentTokenData, SaveAgentTokenErrors, SaveAgentTokenResponses, SaveAiProviderCredentialData, SaveAiProviderCredentialErrors, SaveAiProviderCredentialResponses, SearchLogsData, SearchLogsErrors, SearchLogsResponses, SendEmailData, SendEmailErrors, SendEmailResponses, SendMessageData, SendMessageErrors, SendMessageResponses, SetDefaultS3SourceData, SetDefaultS3SourceErrors, SetDefaultS3SourceResponses, SetFlagEnvironmentData, SetFlagEnvironmentErrors, SetFlagEnvironmentResponses, SetPreviewPasswordData, SetPreviewPasswordErrors, SetPreviewPasswordResponses, SetupDnsChallengeData, SetupDnsChallengeErrors, SetupDnsChallengeResponses, SetupDnsData, SetupDnsErrors, SetupDnsResponses, SetupEmailTrackingData, SetupEmailTrackingErrors, SetupEmailTrackingResponses, SetupMfaData, SetupMfaErrors, SetupMfaResponses, SleepEnvironmentData, SleepEnvironmentErrors, SleepEnvironmentResponses, SmokeTestAgentData, SmokeTestAgentErrors, SmokeTestAgentResponses, SourceSandboxData, SourceSandboxErrors, SourceSandboxResponses, StartAnalysisData, StartAnalysisErrors, StartAnalysisResponses, StartContainerData, StartContainerErrors, StartContainerResponses, StartFixData, StartFixErrors, StartFixResponses, StartGitProviderOauthData, StartGitProviderOauthErrors, StartOidcLoginBySlugData, StartOidcLoginBySlugErrors, StartPgUpgradeData, StartPgUpgradeErrors, StartPgUpgradeResponses, StartRestoreData, StartRestoreErrors, StartRestoreResponses, StartServiceData, StartServiceErrors, StartServiceResponses, StatPathData, StatPathErrors, StatPathResponses, StopContainerData, StopContainerErrors, StopContainerResponses, StopSandboxData, StopSandboxErrors, StopSandboxResponses, StopServiceData, StopServiceErrors, StopServiceResponses, StreamContainerMetricsData, StreamContainerMetricsErrors, StreamContainerMetricsResponses, StreamEventsData, StreamEventsErrors, StreamEventsResponses, StreamRunEventsData, StreamRunEventsErrors, StreamRunEventsResponses, SyncRepositoriesData, SyncRepositoriesErrors, SyncRepositoriesResponses, TailDeploymentJobLogsData, TailDeploymentJobLogsErrors, TailLogsData, TailLogsErrors, TailLogsResponses, TeardownDeploymentData, TeardownDeploymentErrors, TeardownDeploymentResponses, TeardownEnvironmentData, TeardownEnvironmentErrors, TeardownEnvironmentResponses, TestNotificationProviderData, TestNotificationProviderErrors, TestNotificationProviderResponses, TestOidcProviderData, TestOidcProviderResponses, TestProviderConnectionData, TestProviderConnectionErrors, TestProviderConnectionResponses, TestProviderData, TestProviderErrors, TestProviderKeyByIdData, TestProviderKeyByIdErrors, TestProviderKeyByIdResponses, TestProviderKeyInlineData, TestProviderKeyInlineErrors, TestProviderKeyInlineResponses, TestProviderResponses, TestS3ConnectionPreviewData, TestS3ConnectionPreviewErrors, TestS3ConnectionPreviewResponses, TestS3SourceConnectionData, TestS3SourceConnectionErrors, TestS3SourceConnectionResponses, TrackClickData, TrackClickErrors, TrackOpenData, TrackOpenErrors, TrackOpenResponses, TriggerAgentData, TriggerAgentErrors, TriggerAgentResponses, TriggerProjectPipelineData, TriggerProjectPipelineErrors, TriggerProjectPipelineResponses, TriggerScanData, TriggerScanErrors, TriggerScanResponses, TriggerServiceHealthCheckData, TriggerServiceHealthCheckErrors, TriggerServiceHealthCheckResponses, TriggerWeeklyDigestData, TriggerWeeklyDigestErrors, TriggerWeeklyDigestResponses, UnlinkServiceFromProjectData, UnlinkServiceFromProjectErrors, UnlinkServiceFromProjectResponses, UpdateAgentData, UpdateAgentErrors, UpdateAgentResponses, UpdateAiProviderData, UpdateAiProviderErrors, UpdateAiProviderResponses, UpdateAlertData, UpdateAlertErrors, UpdateAlertResponses, UpdateAlertRuleData, UpdateAlertRuleErrors, UpdateAlertRuleResponses, UpdateApiKeyData, UpdateApiKeyErrors, UpdateApiKeyResponses, UpdateAutomaticDeployData, UpdateAutomaticDeployErrors, UpdateAutomaticDeployResponses, UpdateBackupScheduleData, UpdateBackupScheduleErrors, UpdateBackupScheduleResponses, UpdateCloudflareProviderData, UpdateCloudflareProviderErrors, UpdateCloudflareProviderResponses, UpdateConnectionTokenData, UpdateConnectionTokenErrors, UpdateConnectionTokenResponses, UpdateCustomDomainData, UpdateCustomDomainErrors, UpdateCustomDomainResponses, UpdateDashboardData, UpdateDashboardErrors, UpdateDashboardResponses, UpdateDeploymentTokenData, UpdateDeploymentTokenErrors, UpdateDeploymentTokenResponses, UpdateEmailProviderData, UpdateEmailProviderErrors, UpdateEmailProviderResponses, UpdateEnvironmentSettingsData, UpdateEnvironmentSettingsErrors, UpdateEnvironmentSettingsResponses, UpdateEnvironmentSubdomainData, UpdateEnvironmentSubdomainErrors, UpdateEnvironmentSubdomainResponses, UpdateEnvironmentVariableData, UpdateEnvironmentVariableErrors, UpdateEnvironmentVariableResponses, UpdateErrorGroupData, UpdateErrorGroupErrors, UpdateErrorGroupResponses, UpdateFlagData, UpdateFlagErrors, UpdateFlagResponses, UpdateFunnelData, UpdateFunnelErrors, UpdateFunnelResponses, UpdateGitProviderCredentialsData, UpdateGitProviderCredentialsErrors, UpdateGitProviderCredentialsResponses, UpdateGitSettingsData, UpdateGitSettingsErrors, UpdateGitSettingsResponses, UpdateGlobalMcpData, UpdateGlobalMcpErrors, UpdateGlobalMcpResponses, UpdateGlobalSkillData, UpdateGlobalSkillErrors, UpdateGlobalSkillResponses, UpdateIncidentStatusData, UpdateIncidentStatusErrors, UpdateIncidentStatusResponses, UpdateIpAccessControlData, UpdateIpAccessControlErrors, UpdateIpAccessControlResponses, UpdateManagedDomainData, UpdateManagedDomainErrors, UpdateManagedDomainResponses, UpdateMcpData, UpdateMcpErrors, UpdateMcpResponses, UpdateNotificationEmailProviderData, UpdateNotificationEmailProviderErrors, UpdateNotificationEmailProviderResponses, UpdateNotificationProviderData, UpdateNotificationProviderErrors, UpdateNotificationProviderResponses, UpdateOidcProviderData, UpdateOidcProviderResponses, UpdatePreferencesData, UpdatePreferencesErrors, UpdatePreferencesResponses, UpdateProjectData, UpdateProjectDeploymentConfigData, UpdateProjectDeploymentConfigErrors, UpdateProjectDeploymentConfigResponses, UpdateProjectErrors, UpdateProjectResponses, UpdateProjectSecretData, UpdateProjectSecretErrors, UpdateProjectSecretResponses, UpdateProjectSettingsData, UpdateProjectSettingsErrors, UpdateProjectSettingsResponses, UpdateProviderData, UpdateProviderErrors, UpdateProviderKeyData, UpdateProviderKeyErrors, UpdateProviderKeyResponses, UpdateProviderResponses, UpdateRouteData, UpdateRouteErrors, UpdateRouteResponses, UpdateS3SourceData, UpdateS3SourceErrors, UpdateS3SourceResponses, UpdateSelfData, UpdateSelfErrors, UpdateSelfResponses, UpdateServiceData, UpdateServiceErrors, UpdateServiceResourcesData, UpdateServiceResourcesErrors, UpdateServiceResourcesResponses, UpdateServiceResponses, UpdateSessionDurationData, UpdateSessionDurationErrors, UpdateSessionDurationResponses, UpdateSettingsData, UpdateSettingsErrors, UpdateSettingsResponses, UpdateSkillData, UpdateSkillErrors, UpdateSkillResponses, UpdateSlackProviderData, UpdateSlackProviderErrors, UpdateSlackProviderResponses, UpdateSpeedMetricsData, UpdateSpeedMetricsErrors, UpdateSpeedMetricsResponses, UpdateTeamData, UpdateTeamErrors, UpdateTeamMemberRoleData, UpdateTeamMemberRoleErrors, UpdateTeamMemberRoleResponses, UpdateTeamResponses, UpdateUserData, UpdateUserErrors, UpdateUserResponses, UpdateWebhookData, UpdateWebhookErrors, UpdateWebhookProviderData, UpdateWebhookProviderErrors, UpdateWebhookProviderResponses, UpdateWebhookResponses, UpgradePreviewGatewayData, UpgradePreviewGatewayResponses, UpgradeServiceData, UpgradeServiceErrors, UpgradeServiceResponses, UploadGlobalSkillData, UploadGlobalSkillErrors, UploadGlobalSkillResponses, UploadReleaseFileData, UploadReleaseFileErrors, UploadReleaseFileResponses, UploadSkillData, UploadSkillErrors, UploadSkillResponses, UploadSourceFileData, UploadSourceFileErrors, UploadSourceFileResponses, UploadSourceMapData, UploadSourceMapErrors, UploadSourceMapResponses, UploadStaticBundleData, UploadStaticBundleErrors, UploadStaticBundleResponses, UpsertSecretData, UpsertSecretErrors, UpsertSecretResponses, ValidateConnectionData, ValidateConnectionErrors, ValidateConnectionResponses, ValidateEmailData, ValidateEmailErrors, ValidateEmailResponses, VerifyAndEnableMfaData, VerifyAndEnableMfaErrors, VerifyAndEnableMfaResponses, VerifyDomainData, VerifyDomainErrors, VerifyDomainResponses, VerifyEmailData, VerifyEmailErrors, VerifyEmailResponses, VerifyManagedDomainData, VerifyManagedDomainErrors, VerifyManagedDomainResponses, VerifyMfaChallengeData, VerifyMfaChallengeErrors, VerifyMfaChallengeResponses, VerifyStepUpData, VerifyStepUpErrors, VerifyStepUpResponses, WakeEnvironmentData, WakeEnvironmentErrors, WakeEnvironmentResponses, WebhookTriggerData, WebhookTriggerErrors, WebhookTriggerResponses, WorkflowDryRunData, WorkflowDryRunErrors, WorkflowDryRunResponses, WriteFileData, WriteFileErrors, WriteFileResponses, WriteFilesData, WriteFilesErrors, WriteFilesResponses } from './types.gen'; +import type { AcknowledgeAlarmData, AcknowledgeAlarmErrors, AcknowledgeAlarmResponses, ActivateAiProviderData, ActivateAiProviderErrors, ActivateAiProviderResponses, ActivateApiKeyData, ActivateApiKeyErrors, ActivateApiKeyResponses, ActivateConnectionData, ActivateConnectionErrors, ActivateConnectionResponses, ActivateProviderData, ActivateProviderErrors, ActivateProviderResponses, AddClusterMemberData, AddClusterMemberErrors, AddClusterMemberResponses, AddContextData, AddContextErrors, AddContextResponses, AddEnvironmentDomainData, AddEnvironmentDomainErrors, AddEnvironmentDomainResponses, AddEventsData, AddEventsErrors, AddEventsResponses, AddManagedDomainData, AddManagedDomainErrors, AddManagedDomainResponses, AddSessionReplayEventsData, AddSessionReplayEventsErrors, AddSessionReplayEventsResponses, AddTeamMemberData, AddTeamMemberErrors, AddTeamMemberResponses, AdminDrainNodeData, AdminDrainNodeErrors, AdminDrainNodeResponses, AdminDrainStatusData, AdminDrainStatusErrors, AdminDrainStatusResponses, AdminGetNodeData, AdminGetNodeErrors, AdminGetNodeResponses, AdminListNodeContainersData, AdminListNodeContainersErrors, AdminListNodeContainersResponses, AdminListNodesData, AdminListNodesErrors, AdminListNodesResponses, AdminRemoveNodeData, AdminRemoveNodeErrors, AdminRemoveNodeResponses, AdminUndrainNodeData, AdminUndrainNodeErrors, AdminUndrainNodeResponses, ApplyHostnameModeData, ApplyHostnameModeErrors, ApplyHostnameModeResponses, ArchiveConversationData, ArchiveConversationErrors, ArchiveConversationResponses, ArchiveFlagData, ArchiveFlagErrors, ArchiveFlagResponses, AssignRoleData, AssignRoleErrors, AssignRoleResponses, AttachScheduleServicesData, AttachScheduleServicesErrors, AttachScheduleServicesResponses, BlobCopyData, BlobCopyErrors, BlobCopyResponses, BlobDeleteData, BlobDeleteErrors, BlobDeleteResponses, BlobDisableData, BlobDisableErrors, BlobDisableResponses, BlobDownloadData, BlobDownloadErrors, BlobDownloadResponses, BlobEnableData, BlobEnableErrors, BlobEnableResponses, BlobHeadData, BlobHeadErrors, BlobHeadResponses, BlobListData, BlobListErrors, BlobListResponses, BlobPutData, BlobPutErrors, BlobPutResponses, BlobStatusData, BlobStatusErrors, BlobStatusResponses, BlobUpdateData, BlobUpdateErrors, BlobUpdateResponses, CancelBackupData, CancelBackupErrors, CancelBackupResponses, CancelData, CancelDeploymentData, CancelDeploymentErrors, CancelDeploymentResponses, CancelDomainOrderData, CancelDomainOrderErrors, CancelDomainOrderResponses, CancelErrors, CancelPgUpgradeData, CancelPgUpgradeErrors, CancelPgUpgradeResponses, CancelResponses, CancelRunData, CancelRunErrors, CancelRunResponses, CancelScheduleRunData, CancelScheduleRunErrors, CancelScheduleRunResponses, ChangePasswordSelfData, ChangePasswordSelfErrors, ChangePasswordSelfResponses, ChangeProjectSourceData, ChangeProjectSourceErrors, ChangeProjectSourceResponses, ChatCompletionsData, ChatCompletionsErrors, ChatCompletionsResponses, CheckAnalyticsHasEventsData, CheckAnalyticsHasEventsErrors, CheckAnalyticsHasEventsResponses, CheckCommitExistsData, CheckCommitExistsErrors, CheckCommitExistsResponses, CheckDomainStatusData, CheckDomainStatusErrors, CheckDomainStatusResponses, CheckExplorerSupportData, CheckExplorerSupportErrors, CheckExplorerSupportResponses, CheckIpBlockedData, CheckIpBlockedErrors, CheckIpBlockedResponses, CheckProviderDeletionSafetyData, CheckProviderDeletionSafetyErrors, CheckProviderDeletionSafetyResponses, ChunkUploadOptionsData, ChunkUploadOptionsResponses, CleanupExpiredBackupsData, CleanupExpiredBackupsErrors, CleanupExpiredBackupsResponses, ClearPreviewPasswordData, ClearPreviewPasswordErrors, ClearPreviewPasswordResponses, CliDeviceApproveData, CliDeviceApproveErrors, CliDeviceApproveResponses, CliDeviceDenyData, CliDeviceDenyErrors, CliDeviceDenyResponses, CliDeviceLookupData, CliDeviceLookupErrors, CliDeviceLookupResponses, CliDevicePollData, CliDevicePollErrors, CliDevicePollResponses, CliDeviceStartData, CliDeviceStartErrors, CliDeviceStartResponses, CliLogoutData, CliLogoutErrors, CliLogoutResponses, CmdData, CmdErrors, CmdKillData, CmdKillErrors, CmdKillResponses, CmdLogsData, CmdLogsErrors, CmdLogsResponses, CmdResponses, ConfirmPendingActionData, ConfirmPendingActionErrors, ConfirmPendingActionResponses, ContainerMetricsGetHistoryData, ContainerMetricsGetHistoryErrors, ContainerMetricsGetHistoryResponses, CreateAgentData, CreateAgentErrors, CreateAgentResponses, CreateAlertData, CreateAlertErrors, CreateAlertResponses, CreateAlertRuleData, CreateAlertRuleErrors, CreateAlertRuleResponses, CreateApiKeyData, CreateApiKeyErrors, CreateApiKeyResponses, CreateBackupScheduleData, CreateBackupScheduleErrors, CreateBackupScheduleResponses, CreateBitbucketProviderData, CreateBitbucketProviderErrors, CreateBitbucketProviderResponses, CreateCloudflareProviderData, CreateCloudflareProviderErrors, CreateCloudflareProviderResponses, CreateConversationData, CreateConversationErrors, CreateConversationResponses, CreateCustomDomainData, CreateCustomDomainErrors, CreateCustomDomainResponses, CreateDashboardData, CreateDashboardErrors, CreateDashboardResponses, CreateDeploymentTokenData, CreateDeploymentTokenErrors, CreateDeploymentTokenResponses, CreateDnsProviderData, CreateDnsProviderErrors, CreateDnsProviderResponses, CreateDomainData, CreateDomainErrors, CreateDomainResponses, CreateDsnData, CreateDsnErrors, CreateDsnResponses, CreateEmailDomainData, CreateEmailDomainErrors, CreateEmailDomainResponses, CreateEmailProviderData, CreateEmailProviderErrors, CreateEmailProviderResponses, CreateEnvironmentData, CreateEnvironmentErrors, CreateEnvironmentResponses, CreateEnvironmentVariableData, CreateEnvironmentVariableErrors, CreateEnvironmentVariableResponses, CreateFlagData, CreateFlagErrors, CreateFlagResponses, CreateFunnelData, CreateFunnelErrors, CreateFunnelResponses, CreateGenericProviderData, CreateGenericProviderErrors, CreateGenericProviderResponses, CreateGiteaPatProviderData, CreateGiteaPatProviderErrors, CreateGiteaPatProviderResponses, CreateGithubPatProviderData, CreateGithubPatProviderErrors, CreateGithubPatProviderResponses, CreateGitlabOauthProviderData, CreateGitlabOauthProviderErrors, CreateGitlabOauthProviderResponses, CreateGitlabPatProviderData, CreateGitlabPatProviderErrors, CreateGitlabPatProviderResponses, CreateGitProviderData, CreateGitProviderErrors, CreateGitProviderResponses, CreateGlobalMcpData, CreateGlobalMcpErrors, CreateGlobalMcpResponses, CreateGlobalSkillData, CreateGlobalSkillErrors, CreateGlobalSkillResponses, CreateIncidentData, CreateIncidentErrors, CreateIncidentResponses, CreateIpAccessControlData, CreateIpAccessControlErrors, CreateIpAccessControlResponses, CreateMcpData, CreateMcpErrors, CreateMcpResponses, CreateMonitorData, CreateMonitorErrors, CreateMonitorResponses, CreateNotificationEmailProviderData, CreateNotificationEmailProviderErrors, CreateNotificationEmailProviderResponses, CreateNotificationProviderData, CreateNotificationProviderErrors, CreateNotificationProviderResponses, CreateOidcProviderData, CreateOidcProviderErrors, CreateOidcProviderResponses, CreateOidcRoleMappingData, CreateOidcRoleMappingResponses, CreateOrRecreateOrderData, CreateOrRecreateOrderErrors, CreateOrRecreateOrderResponses, CreatePlanData, CreatePlanErrors, CreatePlanResponses, CreatePrData, CreatePrErrors, CreateProjectData, CreateProjectErrors, CreateProjectFromTemplateData, CreateProjectFromTemplateErrors, CreateProjectFromTemplateResponses, CreateProjectReleaseData, CreateProjectReleaseErrors, CreateProjectReleaseResponses, CreateProjectResponses, CreateProjectSecretData, CreateProjectSecretErrors, CreateProjectSecretResponses, CreateProviderKeyData, CreateProviderKeyErrors, CreateProviderKeyResponses, CreatePrResponses, CreateReleaseData, CreateReleaseErrors, CreateReleaseResponses, CreateRouteData, CreateRouteErrors, CreateRouteResponses, CreateS3SourceData, CreateS3SourceErrors, CreateS3SourceResponses, CreateSandboxData, CreateSandboxErrors, CreateSandboxResponses, CreateServiceData, CreateServiceErrors, CreateServiceResponses, CreateSkillData, CreateSkillErrors, CreateSkillResponses, CreateSlackProviderData, CreateSlackProviderErrors, CreateSlackProviderResponses, CreateTeamData, CreateTeamErrors, CreateTeamResponses, CreateUserData, CreateUserErrors, CreateUserResponses, CreateWebhookData, CreateWebhookErrors, CreateWebhookProviderData, CreateWebhookProviderErrors, CreateWebhookProviderResponses, CreateWebhookResponses, DeactivateApiKeyData, DeactivateApiKeyErrors, DeactivateApiKeyResponses, DeactivateConnectionData, DeactivateConnectionErrors, DeactivateConnectionResponses, DeactivateProviderData, DeactivateProviderErrors, DeactivateProviderResponses, DeleteAgentData, DeleteAgentErrors, DeleteAgentResponses, DeleteAlertData, DeleteAlertErrors, DeleteAlertResponses, DeleteAlertRuleData, DeleteAlertRuleErrors, DeleteAlertRuleResponses, DeleteApiKeyData, DeleteApiKeyErrors, DeleteApiKeyResponses, DeleteBackupData, DeleteBackupErrors, DeleteBackupResponses, DeleteBackupScheduleData, DeleteBackupScheduleErrors, DeleteBackupScheduleResponses, DeleteConnectionData, DeleteConnectionErrors, DeleteConnectionResponses, DeleteCustomDomainData, DeleteCustomDomainErrors, DeleteCustomDomainResponses, DeleteDashboardData, DeleteDashboardErrors, DeleteDashboardResponses, DeleteDeploymentTokenData, DeleteDeploymentTokenErrors, DeleteDeploymentTokenResponses, DeleteDnsProviderData, DeleteDnsProviderErrors, DeleteDnsProviderResponses, DeleteDomainData, DeleteDomainErrors, DeleteDomainResponses, DeleteEmailDomainData, DeleteEmailDomainErrors, DeleteEmailDomainResponses, DeleteEmailProviderData, DeleteEmailProviderErrors, DeleteEmailProviderResponses, DeleteEnvironmentData, DeleteEnvironmentDomainData, DeleteEnvironmentDomainErrors, DeleteEnvironmentDomainResponses, DeleteEnvironmentErrors, DeleteEnvironmentResponses, DeleteEnvironmentVariableData, DeleteEnvironmentVariableErrors, DeleteEnvironmentVariableResponses, DeleteExternalImageData, DeleteExternalImageErrors, DeleteExternalImageResponses, DeleteFunnelData, DeleteFunnelErrors, DeleteFunnelResponses, DeleteGitProviderData, DeleteGitProviderErrors, DeleteGitProviderResponses, DeleteGlobalMcpData, DeleteGlobalMcpErrors, DeleteGlobalMcpResponses, DeleteGlobalSkillData, DeleteGlobalSkillErrors, DeleteGlobalSkillResponses, DeleteIpAccessControlData, DeleteIpAccessControlErrors, DeleteIpAccessControlResponses, DeleteMcpData, DeleteMcpErrors, DeleteMcpResponses, DeleteMonitorData, DeleteMonitorErrors, DeleteMonitorResponses, DeleteNotificationProviderData, DeleteNotificationProviderErrors, DeleteNotificationProviderResponses, DeleteOidcProviderData, DeleteOidcProviderResponses, DeleteOidcRoleMappingData, DeleteOidcRoleMappingResponses, DeletePreferencesData, DeletePreferencesErrors, DeletePreferencesResponses, DeleteProjectData, DeleteProjectErrors, DeleteProjectResponses, DeleteProjectSecretData, DeleteProjectSecretErrors, DeleteProjectSecretResponses, DeleteProviderKeyData, DeleteProviderKeyErrors, DeleteProviderKeyResponses, DeleteProviderSafelyData, DeleteProviderSafelyErrors, DeleteProviderSafelyResponses, DeleteReleaseSourceFilesData, DeleteReleaseSourceFilesErrors, DeleteReleaseSourceFilesResponses, DeleteReleaseSourceMapsData, DeleteReleaseSourceMapsErrors, DeleteReleaseSourceMapsResponses, DeleteRouteData, DeleteRouteErrors, DeleteRouteResponses, DeleteS3SourceData, DeleteS3SourceErrors, DeleteS3SourceResponses, DeleteScanData, DeleteScanErrors, DeleteScanResponses, DeleteSecretData, DeleteSecretErrors, DeleteSecretResponses, DeleteServiceData, DeleteServiceErrors, DeleteServiceResponses, DeleteSessionReplayData, DeleteSessionReplayErrors, DeleteSessionReplayResponses, DeleteSkillData, DeleteSkillErrors, DeleteSkillResponses, DeleteSourceMapData, DeleteSourceMapErrors, DeleteSourceMapResponses, DeleteStaticBundleData, DeleteStaticBundleErrors, DeleteStaticBundleResponses, DeleteTeamData, DeleteTeamErrors, DeleteTeamResponses, DeleteUserData, DeleteUserErrors, DeleteUserResponses, DeleteWebhookData, DeleteWebhookErrors, DeleteWebhookResponses, DeployFromImageData, DeployFromImageErrors, DeployFromImageResponses, DeployFromImageUploadData, DeployFromImageUploadErrors, DeployFromImageUploadResponses, DeployFromStaticData, DeployFromStaticErrors, DeployFromStaticResponses, DeployFromUploadedSourceData, DeployFromUploadedSourceErrors, DeployFromUploadedSourceResponses, DeploymentMetricsGetLatestData, DeploymentMetricsGetLatestErrors, DeploymentMetricsGetLatestResponses, DeploymentMetricsGetRangeData, DeploymentMetricsGetRangeErrors, DeploymentMetricsGetRangeResponses, DeploymentMetricsToggleData, DeploymentMetricsToggleErrors, DeploymentMetricsToggleResponses, DestroySandboxData, DestroySandboxErrors, DestroySandboxResponses, DetachScheduleServiceData, DetachScheduleServiceErrors, DetachScheduleServiceResponses, DetectPublicPresetsData, DetectPublicPresetsErrors, DetectPublicPresetsResponses, DisableBackupScheduleData, DisableBackupScheduleErrors, DisableBackupScheduleResponses, DisableMfaData, DisableMfaErrors, DisableMfaResponses, DisconnectCloudData, DisconnectCloudResponses, DiscoverWorkloadsData, DiscoverWorkloadsErrors, DiscoverWorkloadsResponses, DomainData, DomainErrors, DomainResponses, DownloadGlobalSkillArchiveData, DownloadGlobalSkillArchiveErrors, DownloadGlobalSkillArchiveResponses, DownloadObjectData, DownloadObjectErrors, DownloadObjectResponses, DownloadSkillArchiveData, DownloadSkillArchiveErrors, DownloadSkillArchiveResponses, EmailStatusData, EmailStatusErrors, EmailStatusResponses, EmbeddingsData, EmbeddingsErrors, EmbeddingsResponses, EnableBackupScheduleData, EnableBackupScheduleErrors, EnableBackupScheduleResponses, EnrichVisitorData, EnrichVisitorErrors, EnrichVisitorResponses, EnrollCloudData, EnrollCloudResponses, ExecData, ExecDetachedData, ExecDetachedErrors, ExecDetachedResponses, ExecErrors, ExecResponses, ExecuteDeploymentOperationData, ExecuteDeploymentOperationErrors, ExecuteDeploymentOperationResponses, ExecuteImportData, ExecuteImportErrors, ExecuteImportResponses, ExtendTimeoutData, ExtendTimeoutErrors, ExtendTimeoutResponses, ExternalServiceEnablePgStatStatementsData, ExternalServiceEnablePgStatStatementsErrors, ExternalServiceEnablePgStatStatementsResponses, ExternalServiceMetricsByDatabaseData, ExternalServiceMetricsByDatabaseErrors, ExternalServiceMetricsByDatabaseResponses, ExternalServiceMetricsCreateAlertRuleData, ExternalServiceMetricsCreateAlertRuleErrors, ExternalServiceMetricsCreateAlertRuleResponses, ExternalServiceMetricsDeleteAlertRuleData, ExternalServiceMetricsDeleteAlertRuleErrors, ExternalServiceMetricsDeleteAlertRuleResponses, ExternalServiceMetricsGetAlertRulesData, ExternalServiceMetricsGetAlertRulesErrors, ExternalServiceMetricsGetAlertRulesResponses, ExternalServiceMetricsGetLatestData, ExternalServiceMetricsGetLatestErrors, ExternalServiceMetricsGetLatestResponses, ExternalServiceMetricsGetRangeData, ExternalServiceMetricsGetRangeErrors, ExternalServiceMetricsGetRangeResponses, ExternalServiceMetricsStatusData, ExternalServiceMetricsStatusErrors, ExternalServiceMetricsStatusResponses, ExternalServiceMetricsToggleData, ExternalServiceMetricsToggleErrors, ExternalServiceMetricsToggleResponses, ExternalServiceMetricsUpdateAlertRuleData, ExternalServiceMetricsUpdateAlertRuleErrors, ExternalServiceMetricsUpdateAlertRuleResponses, ExternalServiceResetPgStatStatementsData, ExternalServiceResetPgStatStatementsErrors, ExternalServiceResetPgStatStatementsResponses, FinalizeOrderData, FinalizeOrderErrors, FinalizeOrderResponses, FinalizeProjectReleaseData, FinalizeProjectReleaseErrors, FinalizeProjectReleaseResponses, FindConversationData, FindConversationErrors, FindConversationResponses, GenerateJoinTokenData, GenerateJoinTokenErrors, GenerateJoinTokenResponses, GeneratePresetDockerfileData, GeneratePresetDockerfileErrors, GeneratePresetDockerfileResponses, GetAccessInfoData, GetAccessInfoErrors, GetAccessInfoResponses, GetActiveVisitorsData, GetActiveVisitorsErrors, GetActiveVisitorsResponses, GetActivityGraphData, GetActivityGraphErrors, GetActivityGraphResponses, GetAdminGateData, GetAdminGateErrors, GetAdminGateResponses, GetAgentData, GetAgentErrors, GetAgentResponses, GetAggregatedBucketsData, GetAggregatedBucketsErrors, GetAggregatedBucketsResponses, GetAiAgentBreakdownData, GetAiAgentBreakdownErrors, GetAiAgentBreakdownResponses, GetAiAgentPagesData, GetAiAgentPagesErrors, GetAiAgentPagesResponses, GetAiAgentTimelineData, GetAiAgentTimelineErrors, GetAiAgentTimelineResponses, GetAiPageBreakdownData, GetAiPageBreakdownErrors, GetAiPageBreakdownResponses, GetAiStatusBreakdownData, GetAiStatusBreakdownErrors, GetAiStatusBreakdownResponses, GetAlertData, GetAlertErrors, GetAlertResponses, GetAlertRuleData, GetAlertRuleErrors, GetAlertRuleResponses, GetAllRepositoriesByNameData, GetAllRepositoriesByNameErrors, GetAllRepositoriesByNameResponses, GetAnalyticsActiveVisitorsData, GetAnalyticsActiveVisitorsErrors, GetAnalyticsActiveVisitorsResponses, GetAnalyticsEventsCountData, GetAnalyticsEventsCountErrors, GetAnalyticsEventsCountResponses, GetAnalyticsSessionEventsData, GetAnalyticsSessionEventsErrors, GetAnalyticsSessionEventsResponses, GetAnalyticsVisitorSessionsData, GetAnalyticsVisitorSessionsErrors, GetAnalyticsVisitorSessionsResponses, GetApiKeyData, GetApiKeyErrors, GetApiKeyPermissionsData, GetApiKeyPermissionsErrors, GetApiKeyPermissionsResponses, GetApiKeyResponses, GetAuditLogData, GetAuditLogErrors, GetAuditLogResponses, GetBackupData, GetBackupErrors, GetBackupResponses, GetBackupScheduleData, GetBackupScheduleErrors, GetBackupScheduleResponses, GetBranchesByRepositoryIdData, GetBranchesByRepositoryIdErrors, GetBranchesByRepositoryIdResponses, GetBucketedIncidentsData, GetBucketedIncidentsErrors, GetBucketedIncidentsResponses, GetBucketedStatusData, GetBucketedStatusErrors, GetBucketedStatusResponses, GetChallengeTokenData, GetChallengeTokenErrors, GetChallengeTokenResponses, GetChatReadinessData, GetChatReadinessErrors, GetChatReadinessResponses, GetCliStatusData, GetCliStatusErrors, GetCliStatusResponses, GetCloudCapabilityData, GetCloudCapabilityResponses, GetCloudStatusData, GetCloudStatusResponses, GetClusterHealthData, GetClusterHealthErrors, GetClusterHealthResponses, GetClusterMemberData, GetClusterMemberErrors, GetClusterMemberResponses, GetCmdData, GetCmdErrors, GetCmdResponses, GetContainerDetailData, GetContainerDetailErrors, GetContainerDetailResponses, GetContainerEnvironmentVariableData, GetContainerEnvironmentVariableErrors, GetContainerEnvironmentVariableResponses, GetContainerInfoData, GetContainerInfoErrors, GetContainerInfoResponses, GetContainerLogsByIdData, GetContainerLogsByIdErrors, GetContainerLogsData, GetContainerLogsErrors, GetContainerMetricsData, GetContainerMetricsErrors, GetContainerMetricsResponses, GetConversationData, GetConversationDetailData, GetConversationDetailErrors, GetConversationDetailResponses, GetConversationErrors, GetConversationResponses, GetConversationsData, GetConversationsErrors, GetConversationsResponses, GetCronByIdData, GetCronByIdErrors, GetCronByIdResponses, GetCronExecutionsData, GetCronExecutionsErrors, GetCronExecutionsResponses, GetCrossProjectTraceSiblingsData, GetCrossProjectTraceSiblingsErrors, GetCrossProjectTraceSiblingsResponses, GetCurrentMonitorStatusData, GetCurrentMonitorStatusErrors, GetCurrentMonitorStatusResponses, GetCurrentUserData, GetCurrentUserErrors, GetCurrentUserResponses, GetCustomDomainData, GetCustomDomainErrors, GetCustomDomainResponses, GetDashboardData, GetDashboardErrors, GetDashboardProjectsAnalyticsData, GetDashboardProjectsAnalyticsErrors, GetDashboardProjectsAnalyticsResponses, GetDashboardResponses, GetDeliveryData, GetDeliveryErrors, GetDeliveryResponses, GetDeploymentContainerLogContentData, GetDeploymentContainerLogContentErrors, GetDeploymentContainerLogContentResponses, GetDeploymentData, GetDeploymentErrors, GetDeploymentJobLogsData, GetDeploymentJobLogsErrors, GetDeploymentJobLogsResponses, GetDeploymentJobsData, GetDeploymentJobsErrors, GetDeploymentJobsResponses, GetDeploymentOperationsData, GetDeploymentOperationsErrors, GetDeploymentOperationsResponses, GetDeploymentOperationStatusData, GetDeploymentOperationStatusErrors, GetDeploymentOperationStatusResponses, GetDeploymentResponses, GetDeploymentTokenData, GetDeploymentTokenErrors, GetDeploymentTokenResponses, GetDiskStatusData, GetDiskStatusErrors, GetDiskStatusResponses, GetDnsChangesData, GetDnsChangesErrors, GetDnsChangesResponses, GetDnsProviderData, GetDnsProviderErrors, GetDnsProviderResponses, GetDomainByHostData, GetDomainByHostErrors, GetDomainByHostResponses, GetDomainByIdData, GetDomainByIdErrors, GetDomainByIdResponses, GetDomainByNameData, GetDomainByNameErrors, GetDomainByNameResponses, GetDomainData, GetDomainDnsRecordsData, GetDomainDnsRecordsErrors, GetDomainDnsRecordsResponses, GetDomainErrors, GetDomainOrderData, GetDomainOrderErrors, GetDomainOrderResponses, GetDomainResponses, GetEmailData, GetEmailErrors, GetEmailEventsData, GetEmailEventsErrors, GetEmailEventsResponses, GetEmailLinksData, GetEmailLinksErrors, GetEmailLinksResponses, GetEmailProviderData, GetEmailProviderErrors, GetEmailProviderResponses, GetEmailResponses, GetEmailStatsData, GetEmailStatsErrors, GetEmailStatsResponses, GetEmailTrackingData, GetEmailTrackingErrors, GetEmailTrackingResponses, GetEmailTrackingStatusData, GetEmailTrackingStatusErrors, GetEmailTrackingStatusResponses, GetEntityInfoData, GetEntityInfoErrors, GetEntityInfoResponses, GetEnvironmentCronsData, GetEnvironmentCronsErrors, GetEnvironmentCronsResponses, GetEnvironmentData, GetEnvironmentDomainsData, GetEnvironmentDomainsErrors, GetEnvironmentDomainsResponses, GetEnvironmentErrors, GetEnvironmentResponses, GetEnvironmentsData, GetEnvironmentsErrors, GetEnvironmentsResponses, GetEnvironmentVariablesData, GetEnvironmentVariablesErrors, GetEnvironmentVariablesResponses, GetEnvironmentVariableValueData, GetEnvironmentVariableValueErrors, GetEnvironmentVariableValueResponses, GetErrorDashboardStatsData, GetErrorDashboardStatsErrors, GetErrorDashboardStatsResponses, GetErrorEventData, GetErrorEventErrors, GetErrorEventResponses, GetErrorGroupData, GetErrorGroupErrors, GetErrorGroupResponses, GetErrorStatsData, GetErrorStatsErrors, GetErrorStatsResponses, GetErrorTimeSeriesData, GetErrorTimeSeriesErrors, GetErrorTimeSeriesResponses, GetEventDetailData, GetEventDetailErrors, GetEventDetailResponses, GetEventEntriesData, GetEventEntriesErrors, GetEventEntriesResponses, GetEventsCountData, GetEventsCountErrors, GetEventsCountResponses, GetEventsTimelineData, GetEventsTimelineErrors, GetEventsTimelineResponses, GetEventTypeBreakdownData, GetEventTypeBreakdownErrors, GetEventTypeBreakdownResponses, GetEventVisitorsData, GetEventVisitorsErrors, GetEventVisitorsResponses, GetExternalImageData, GetExternalImageErrors, GetExternalImageResponses, GetFileData, GetFileErrors, GetFileResponses, GetFlagData, GetFlagErrors, GetFlagResponses, GetFlagSnapshotData, GetFlagSnapshotErrors, GetFlagSnapshotResponses, GetFunnelMetricsData, GetFunnelMetricsErrors, GetFunnelMetricsResponses, GetGenaiTraceData, GetGenaiTraceErrors, GetGenaiTraceResponses, GetGeneralStatsData, GetGeneralStatsErrors, GetGeneralStatsResponses, GetGitProviderData, GetGitProviderErrors, GetGitProviderResponses, GetGlobalEventsData, GetGlobalEventsErrors, GetGlobalEventsResponses, GetGlobalEventStatsData, GetGlobalEventStatsErrors, GetGlobalEventStatsResponses, GetGlobalMcpData, GetGlobalMcpErrors, GetGlobalMcpResponses, GetGlobalSandboxStatusData, GetGlobalSandboxStatusErrors, GetGlobalSandboxStatusResponses, GetGlobalSkillData, GetGlobalSkillErrors, GetGlobalSkillResponses, GetGroupedPageMetricsData, GetGroupedPageMetricsErrors, GetGroupedPageMetricsResponses, GetHealthData, GetHealthErrors, GetHealthResponses, GetHourlyVisitsData, GetHourlyVisitsErrors, GetHourlyVisitsResponses, GetHttpChallengeDebugData, GetHttpChallengeDebugErrors, GetHttpChallengeDebugResponses, GetImportStatusData, GetImportStatusErrors, GetImportStatusResponses, GetIncidentData, GetIncidentErrors, GetIncidentResponses, GetIncidentUpdatesData, GetIncidentUpdatesErrors, GetIncidentUpdatesResponses, GetIpAccessControlData, GetIpAccessControlErrors, GetIpAccessControlResponses, GetIpGeolocationData, GetIpGeolocationErrors, GetIpGeolocationResponses, GetJoinTokenStatusData, GetJoinTokenStatusErrors, GetJoinTokenStatusResponses, GetLastDeploymentData, GetLastDeploymentErrors, GetLastDeploymentResponses, GetLatestScanData, GetLatestScanErrors, GetLatestScanResponses, GetLatestScansPerEnvironmentData, GetLatestScansPerEnvironmentErrors, GetLatestScansPerEnvironmentResponses, GetLiveVisitorsListData, GetLiveVisitorsListErrors, GetLiveVisitorsListResponses, GetLogContextData, GetLogContextErrors, GetLogContextResponses, GetMcpData, GetMcpErrors, GetMcpResponses, GetMetricsOverTimeData, GetMetricsOverTimeErrors, GetMetricsOverTimeResponses, GetMonitorData, GetMonitorErrors, GetMonitorResponses, GetNotificationProviderData, GetNotificationProviderErrors, GetNotificationProviderResponses, GetOnDemandCertStatusData, GetOnDemandCertStatusErrors, GetOnDemandCertStatusResponses, GetOrCreateDsnData, GetOrCreateDsnErrors, GetOrCreateDsnResponses, GetPageFlowData, GetPageFlowErrors, GetPageFlowResponses, GetPageHourlySessionsData, GetPageHourlySessionsErrors, GetPageHourlySessionsResponses, GetPagePathDetailData, GetPagePathDetailErrors, GetPagePathDetailResponses, GetPagePathsData, GetPagePathsErrors, GetPagePathsResponses, GetPagePathsSparklinesData, GetPagePathsSparklinesErrors, GetPagePathsSparklinesResponses, GetPagePathVisitorsData, GetPagePathVisitorsErrors, GetPagePathVisitorsResponses, GetPendingActionData, GetPendingActionErrors, GetPendingActionResponses, GetPerformanceMetricsData, GetPerformanceMetricsErrors, GetPerformanceMetricsResponses, GetPgUpgradeData, GetPgUpgradeErrors, GetPgUpgradeLogsData, GetPgUpgradeLogsErrors, GetPgUpgradeLogsResponses, GetPgUpgradeResponses, GetPipelineStatsData, GetPipelineStatsErrors, GetPipelineStatsResponses, GetPlatformInfoData, GetPlatformInfoErrors, GetPlatformInfoResponses, GetPostgresWalHealthData, GetPostgresWalHealthErrors, GetPostgresWalHealthResponses, GetPreferencesData, GetPreferencesErrors, GetPreferencesResponses, GetPreviewGatewayLogsData, GetPreviewGatewayLogsResponses, GetPreviewGatewaySettingsData, GetPreviewGatewaySettingsResponses, GetPreviewGatewayStatusData, GetPreviewGatewayStatusResponses, GetPricingData, GetPricingErrors, GetPricingResponses, GetPrivateIpData, GetPrivateIpErrors, GetPrivateIpResponses, GetProjectAlarmsSummaryData, GetProjectAlarmsSummaryErrors, GetProjectAlarmsSummaryResponses, GetProjectBySlugData, GetProjectBySlugErrors, GetProjectBySlugResponses, GetProjectData, GetProjectDeploymentsData, GetProjectDeploymentsErrors, GetProjectDeploymentsResponses, GetProjectErrors, GetProjectResponses, GetProjectsData, GetProjectsErrors, GetProjectServiceEnvironmentVariablesData, GetProjectServiceEnvironmentVariablesErrors, GetProjectServiceEnvironmentVariablesResponses, GetProjectSessionReplaysData, GetProjectSessionReplaysErrors, GetProjectSessionReplaysResponses, GetProjectsHealthData, GetProjectsHealthErrors, GetProjectsHealthResponses, GetProjectsMonitorHealthData, GetProjectsMonitorHealthErrors, GetProjectsMonitorHealthResponses, GetProjectsResponses, GetProjectStatisticsData, GetProjectStatisticsErrors, GetProjectStatisticsResponses, GetProjectTemplateData, GetProjectTemplateErrors, GetProjectTemplateResponses, GetPropertyBreakdownData, GetPropertyBreakdownErrors, GetPropertyBreakdownResponses, GetPropertyTimelineData, GetPropertyTimelineErrors, GetPropertyTimelineResponses, GetProviderConnectionsData, GetProviderConnectionsErrors, GetProviderConnectionsResponses, GetProviderMetadataData, GetProviderMetadataErrors, GetProviderMetadataResponses, GetProvidersMetadataData, GetProvidersMetadataErrors, GetProvidersMetadataResponses, GetProxyLogByIdData, GetProxyLogByIdErrors, GetProxyLogByIdResponses, GetProxyLogByRequestIdData, GetProxyLogByRequestIdErrors, GetProxyLogByRequestIdResponses, GetProxyLogsData, GetProxyLogsErrors, GetProxyLogsResponses, GetPublicBranchesData, GetPublicBranchesErrors, GetPublicBranchesResponses, GetPublicIpData, GetPublicIpErrors, GetPublicIpResponses, GetPublicRepositoryData, GetPublicRepositoryErrors, GetPublicRepositoryResponses, GetQuotaData, GetQuotaErrors, GetQuotaResponses, GetRecentActivityData, GetRecentActivityErrors, GetRecentActivityResponses, GetRemoteExternalImageData, GetRemoteExternalImageErrors, GetRemoteExternalImageResponses, GetRepositoryBranchesData, GetRepositoryBranchesErrors, GetRepositoryBranchesResponses, GetRepositoryByIdData, GetRepositoryByIdErrors, GetRepositoryByIdResponses, GetRepositoryByNameData, GetRepositoryByNameErrors, GetRepositoryByNameResponses, GetRepositoryPresetByNameData, GetRepositoryPresetByNameErrors, GetRepositoryPresetByNameResponses, GetRepositoryPresetLiveData, GetRepositoryPresetLiveErrors, GetRepositoryPresetLiveResponses, GetRepositoryTagsData, GetRepositoryTagsErrors, GetRepositoryTagsResponses, GetResolvedEnvironmentVariablesData, GetResolvedEnvironmentVariablesErrors, GetResolvedEnvironmentVariablesResponses, GetResolvedEnvironmentVariableValueData, GetResolvedEnvironmentVariableValueErrors, GetResolvedEnvironmentVariableValueResponses, GetRestoreCapabilitiesData, GetRestoreCapabilitiesErrors, GetRestoreCapabilitiesResponses, GetRestoreRunData, GetRestoreRunErrors, GetRestoreRunResponses, GetRouteData, GetRouteErrors, GetRouteResponses, GetRunData, GetRunErrors, GetRunResponses, GetRunWithLogsData, GetRunWithLogsErrors, GetRunWithLogsResponses, GetS3CredentialsData, GetS3CredentialsErrors, GetS3CredentialsResponses, GetS3SourceData, GetS3SourceErrors, GetS3SourceResponses, GetSandboxData, GetSandboxErrors, GetSandboxResponses, GetSandboxStatusData, GetSandboxStatusErrors, GetSandboxStatusResponses, GetScanByDeploymentData, GetScanByDeploymentErrors, GetScanByDeploymentResponses, GetScanData, GetScanErrors, GetScanResponses, GetScanVulnerabilitiesData, GetScanVulnerabilitiesErrors, GetScanVulnerabilitiesResponses, GetServiceBySlugData, GetServiceBySlugErrors, GetServiceBySlugResponses, GetServiceData, GetServiceEnvironmentVariableData, GetServiceEnvironmentVariableErrors, GetServiceEnvironmentVariableResponses, GetServiceEnvironmentVariablesData, GetServiceEnvironmentVariablesErrors, GetServiceEnvironmentVariablesResponses, GetServiceErrors, GetServiceHealthStatusData, GetServiceHealthStatusErrors, GetServiceHealthStatusResponses, GetServicePreviewEnvironmentVariableNamesData, GetServicePreviewEnvironmentVariableNamesErrors, GetServicePreviewEnvironmentVariableNamesResponses, GetServicePreviewEnvironmentVariablesMaskedData, GetServicePreviewEnvironmentVariablesMaskedErrors, GetServicePreviewEnvironmentVariablesMaskedResponses, GetServiceResponses, GetServiceRuntimeData, GetServiceRuntimeErrors, GetServiceRuntimeResponses, GetServiceStatsData, GetServiceStatsErrors, GetServiceStatsResponses, GetServiceTypeParametersData, GetServiceTypeParametersErrors, GetServiceTypeParametersResponses, GetServiceTypesData, GetServiceTypesErrors, GetServiceTypesResponses, GetSessionDetailsData, GetSessionDetailsErrors, GetSessionDetailsResponses, GetSessionEventsData, GetSessionEventsErrors, GetSessionEventsResponses, GetSessionLogsData, GetSessionLogsErrors, GetSessionLogsResponses, GetSessionReplayData, GetSessionReplayErrors, GetSessionReplayEventsData, GetSessionReplayEventsErrors, GetSessionReplayEventsResponses, GetSessionReplayResponses, GetSettingsData, GetSettingsErrors, GetSettingsResponses, GetSkillData, GetSkillErrors, GetSkillResponses, GetSlowQueriesData, GetSlowQueriesErrors, GetSlowQueriesResponses, GetStaticBundleData, GetStaticBundleErrors, GetStaticBundleResponses, GetStatusOverviewData, GetStatusOverviewErrors, GetStatusOverviewResponses, GetTagsByRepositoryIdData, GetTagsByRepositoryIdErrors, GetTagsByRepositoryIdResponses, GetTeamData, GetTeamErrors, GetTeamResponses, GetTimeBucketStatsData, GetTimeBucketStatsErrors, GetTimeBucketStatsResponses, GetTodayStatsData, GetTodayStatsErrors, GetTodayStatsResponses, GetTraceData, GetTraceErrors, GetTraceResponses, GetUnifiedTraceData, GetUnifiedTraceErrors, GetUnifiedTraceResponses, GetUniqueCountsData, GetUniqueCountsErrors, GetUniqueCountsResponses, GetUniqueEventsData, GetUniqueEventsErrors, GetUniqueEventsResponses, GetUpdateStatusData, GetUpdateStatusErrors, GetUpdateStatusResponses, GetUptimeHistoryData, GetUptimeHistoryErrors, GetUptimeHistoryResponses, GetUsageByProviderData, GetUsageByProviderErrors, GetUsageByProviderResponses, GetUsageRecentData, GetUsageRecentErrors, GetUsageRecentResponses, GetUsageSummaryData, GetUsageSummaryErrors, GetUsageSummaryResponses, GetUsageTimeseriesData, GetUsageTimeseriesErrors, GetUsageTimeseriesResponses, GetUsageTopModelsData, GetUsageTopModelsErrors, GetUsageTopModelsResponses, GetVisitorByGuidData, GetVisitorByGuidErrors, GetVisitorByGuidResponses, GetVisitorByIdData, GetVisitorByIdErrors, GetVisitorByIdResponses, GetVisitorDetailsData, GetVisitorDetailsErrors, GetVisitorDetailsResponses, GetVisitorFacetsData, GetVisitorFacetsErrors, GetVisitorFacetsResponses, GetVisitorInfoData, GetVisitorInfoErrors, GetVisitorInfoResponses, GetVisitorJourneyData, GetVisitorJourneyErrors, GetVisitorJourneyResponses, GetVisitorsData, GetVisitorsErrors, GetVisitorSessionsData, GetVisitorSessionsErrors, GetVisitorSessionsResponses, GetVisitorsResponses, GetVisitorStatsData, GetVisitorStatsErrors, GetVisitorStatsResponses, GetWebhookData, GetWebhookErrors, GetWebhookResponses, GrantProjectAccessData, GrantProjectAccessErrors, GrantProjectAccessResponses, HandleGitProviderOauthCallbackData, HandleGitProviderOauthCallbackErrors, HasAnalyticsEventsData, HasAnalyticsEventsErrors, HasAnalyticsEventsResponses, HasErrorGroupsData, HasErrorGroupsErrors, HasErrorGroupsResponses, HasPerformanceMetricsData, HasPerformanceMetricsErrors, HasPerformanceMetricsResponses, ImportExternalServiceData, ImportExternalServiceErrors, ImportExternalServiceResponses, IngestLogsByPathData, IngestLogsByPathErrors, IngestLogsByPathResponses, IngestLogsData, IngestLogsErrors, IngestLogsResponses, IngestMetricsByPathData, IngestMetricsByPathErrors, IngestMetricsByPathResponses, IngestMetricsData, IngestMetricsErrors, IngestMetricsResponses, IngestSentryEnvelopeData, IngestSentryEnvelopeErrors, IngestSentryEnvelopeResponses, IngestSentryEventData, IngestSentryEventErrors, IngestSentryEventResponses, IngestTracesByPathData, IngestTracesByPathErrors, IngestTracesByPathResponses, IngestTracesData, IngestTracesErrors, IngestTracesResponses, InitSessionReplayData, InitSessionReplayErrors, InitSessionReplayResponses, InspectDropArchiveData, InspectDropArchiveErrors, InspectDropArchiveResponses, JobLogsData, JobLogsErrors, JobLogsResponses, JobStatusData, JobStatusErrors, JobStatusResponses, KillJobData, KillJobErrors, KillJobResponses, KvDelData, KvDelErrors, KvDelResponses, KvDisableData, KvDisableErrors, KvDisableResponses, KvEnableData, KvEnableErrors, KvEnableResponses, KvExpireData, KvExpireErrors, KvExpireResponses, KvGetData, KvGetErrors, KvGetResponses, KvIncrData, KvIncrErrors, KvIncrResponses, KvKeysData, KvKeysErrors, KvKeysResponses, KvSetData, KvSetErrors, KvSetResponses, KvStatusData, KvStatusErrors, KvStatusResponses, KvTtlData, KvTtlErrors, KvTtlResponses, KvUpdateData, KvUpdateErrors, KvUpdateResponses, LatestRunForSourceData, LatestRunForSourceErrors, LatestRunForSourceResponses, LinkCustomDomainToCertificateData, LinkCustomDomainToCertificateErrors, LinkCustomDomainToCertificateResponses, LinkServiceToProjectData, LinkServiceToProjectErrors, LinkServiceToProjectResponses, ListAgentRunsData, ListAgentRunsErrors, ListAgentRunsResponses, ListAgentsData, ListAgentsErrors, ListAgentsResponses, ListAiProvidersData, ListAiProvidersErrors, ListAiProvidersResponses, ListAlertRulesData, ListAlertRulesErrors, ListAlertRulesResponses, ListAlertsData, ListAlertsErrors, ListAlertsResponses, ListAllConversationsData, ListAllConversationsErrors, ListAllConversationsResponses, ListAllRunsData, ListAllRunsErrors, ListAllRunsResponses, ListApiKeysData, ListApiKeysErrors, ListApiKeysResponses, ListAuditLogsData, ListAuditLogsErrors, ListAuditLogsResponses, ListAvailableContainersData, ListAvailableContainersErrors, ListAvailableContainersResponses, ListBackupAlertsData, ListBackupAlertsErrors, ListBackupAlertsResponses, ListBackupChildrenData, ListBackupChildrenErrors, ListBackupChildrenResponses, ListBackupSchedulesData, ListBackupSchedulesErrors, ListBackupSchedulesResponses, ListBackupsForScheduleData, ListBackupsForScheduleErrors, ListBackupsForScheduleResponses, ListCommitsByRepositoryIdData, ListCommitsByRepositoryIdErrors, ListCommitsByRepositoryIdResponses, ListConnectionsData, ListConnectionsErrors, ListConnectionsResponses, ListContainersAtPathData, ListContainersAtPathErrors, ListContainersAtPathResponses, ListContainersData, ListContainersErrors, ListContainersResponses, ListConversationsData, ListConversationsErrors, ListConversationsResponses, ListCustomDomainsForProjectData, ListCustomDomainsForProjectErrors, ListCustomDomainsForProjectResponses, ListDashboardsData, ListDashboardsErrors, ListDashboardsResponses, ListDeliveriesData, ListDeliveriesErrors, ListDeliveriesResponses, ListDeploymentContainerLogsData, ListDeploymentContainerLogsErrors, ListDeploymentContainerLogsResponses, ListDeploymentTokensData, ListDeploymentTokensErrors, ListDeploymentTokensResponses, ListDnsProvidersData, ListDnsProvidersErrors, ListDnsProvidersResponses, ListDomainsData, ListDomainsErrors, ListDomainsResponses, ListDsnsData, ListDsnsErrors, ListDsnsResponses, ListEmailDomainsData, ListEmailDomainsErrors, ListEmailDomainsResponses, ListEmailProvidersData, ListEmailProvidersErrors, ListEmailProvidersResponses, ListEmailsData, ListEmailsErrors, ListEmailsResponses, ListEnrollmentTokensData, ListEnrollmentTokensErrors, ListEnrollmentTokensResponses, ListEntitiesData, ListEntitiesErrors, ListEntitiesResponses, ListErrorEventsData, ListErrorEventsErrors, ListErrorEventsResponses, ListErrorGroupsData, ListErrorGroupsErrors, ListErrorGroupsResponses, ListEventsData, ListEventsResponses, ListEventTypesData, ListEventTypesResponses, ListExternalImagesData, ListExternalImagesErrors, ListExternalImagesResponses, ListExternalPluginsData, ListExternalPluginsErrors, ListExternalPluginsResponses, ListExternalServiceBackupsData, ListExternalServiceBackupsErrors, ListExternalServiceBackupsResponses, ListFlagsData, ListFlagsErrors, ListFlagsResponses, ListFunnelsData, ListFunnelsErrors, ListFunnelsResponses, ListGitProvidersData, ListGitProvidersErrors, ListGitProvidersResponses, ListGlobalMcpsData, ListGlobalMcpsErrors, ListGlobalMcpsResponses, ListGlobalSkillsData, ListGlobalSkillsErrors, ListGlobalSkillsResponses, ListIncidentsData, ListIncidentsErrors, ListIncidentsResponses, ListInsightsData, ListInsightsErrors, ListInsightsResponses, ListIpAccessControlData, ListIpAccessControlErrors, ListIpAccessControlResponses, ListJobsData, ListJobsErrors, ListJobsResponses, ListKnownAiAgentsData, ListKnownAiAgentsErrors, ListKnownAiAgentsResponses, ListManagedDomainsData, ListManagedDomainsErrors, ListManagedDomainsResponses, ListMcpsData, ListMcpsErrors, ListMcpsResponses, ListMetricLabelKeysData, ListMetricLabelKeysErrors, ListMetricLabelKeysResponses, ListMetricLabelValuesData, ListMetricLabelValuesErrors, ListMetricLabelValuesResponses, ListMetricNamesData, ListMetricNamesErrors, ListMetricNamesResponses, ListModelsData, ListModelsErrors, ListModelsResponses, ListMonitorsData, ListMonitorsErrors, ListMonitorsResponses, ListNotificationProvidersData, ListNotificationProvidersErrors, ListNotificationProvidersResponses, ListOidcProvidersData, ListOidcProvidersResponses, ListOidcProviderUsersData, ListOidcProviderUsersErrors, ListOidcProviderUsersResponses, ListOidcRoleMappingsData, ListOidcRoleMappingsResponses, ListOnDemandCertsData, ListOnDemandCertsErrors, ListOnDemandCertsResponses, ListOrdersData, ListOrdersErrors, ListOrdersResponses, ListPeersData, ListPeersErrors, ListPeersResponses, ListPendingActionsData, ListPendingActionsErrors, ListPendingActionsResponses, ListPgUpgradesData, ListPgUpgradesErrors, ListPgUpgradesResponses, ListPresetsData, ListPresetsErrors, ListPresetsResponses, ListProjectAccessData, ListProjectAccessErrors, ListProjectAccessResponses, ListProjectAlarmsData, ListProjectAlarmsErrors, ListProjectAlarmsResponses, ListProjectScansData, ListProjectScansErrors, ListProjectScansResponses, ListProjectSecretsData, ListProjectSecretsErrors, ListProjectSecretsResponses, ListProjectServicesData, ListProjectServicesErrors, ListProjectServicesResponses, ListProjectTemplatesData, ListProjectTemplatesErrors, ListProjectTemplatesResponses, ListProjectTemplateTagsData, ListProjectTemplateTagsErrors, ListProjectTemplateTagsResponses, ListProviderKeysData, ListProviderKeysErrors, ListProviderKeysResponses, ListProviderZonesData, ListProviderZonesErrors, ListProviderZonesResponses, ListPublicProvidersData, ListPublicProvidersResponses, ListReleaseFilesData, ListReleaseFilesErrors, ListReleaseFilesResponses, ListReleasesData, ListReleasesErrors, ListReleasesResponses, ListRemoteExternalImagesData, ListRemoteExternalImagesErrors, ListRemoteExternalImagesResponses, ListRepositoriesByConnectionData, ListRepositoriesByConnectionErrors, ListRepositoriesByConnectionResponses, ListRepositoriesByProviderData, ListRepositoriesByProviderErrors, ListRepositoriesByProviderResponses, ListRestoreRunsForServiceData, ListRestoreRunsForServiceResponses, ListRootContainersData, ListRootContainersErrors, ListRootContainersResponses, ListRoutesData, ListRoutesErrors, ListRoutesResponses, ListS3SourcesData, ListS3SourcesErrors, ListS3SourcesResponses, ListSandboxesData, ListSandboxesResponses, ListScheduleRunJobsData, ListScheduleRunJobsErrors, ListScheduleRunJobsResponses, ListScheduleRunsData, ListScheduleRunsErrors, ListScheduleRunsResponses, ListScheduleServicesData, ListScheduleServicesErrors, ListScheduleServicesResponses, ListSecretsData, ListSecretsErrors, ListSecretsResponses, ListServiceHealthStatusesData, ListServiceHealthStatusesErrors, ListServiceHealthStatusesResponses, ListServiceProjectsData, ListServiceProjectsErrors, ListServiceProjectsResponses, ListServiceSchedulesData, ListServiceSchedulesErrors, ListServiceSchedulesResponses, ListServicesData, ListServicesErrors, ListServicesResponses, ListSkillsData, ListSkillsErrors, ListSkillsResponses, ListSourceBackupsData, ListSourceBackupsErrors, ListSourceBackupsResponses, ListSourceFilesData, ListSourceFilesErrors, ListSourceFilesResponses, ListSourceMapsData, ListSourceMapsErrors, ListSourceMapsResponses, ListSourcesData, ListSourcesErrors, ListSourcesResponses, ListStaticBundlesData, ListStaticBundlesErrors, ListStaticBundlesResponses, ListSyncedRepositoriesData, ListSyncedRepositoriesErrors, ListSyncedRepositoriesResponses, ListTeamMembersData, ListTeamMembersErrors, ListTeamMembersResponses, ListTeamProjectsData, ListTeamProjectsErrors, ListTeamProjectsResponses, ListTeamsData, ListTeamsErrors, ListTeamsResponses, ListUsersData, ListUsersErrors, ListUsersResponses, ListWebhooksData, ListWebhooksErrors, ListWebhooksResponses, LoginData, LoginErrors, LoginResponses, LogoutData, LogoutErrors, LogoutResponses, LookupDnsARecordsData, LookupDnsARecordsErrors, LookupDnsARecordsResponses, MintEnrollmentTokenData, MintEnrollmentTokenErrors, MintEnrollmentTokenResponses, MkdirData, MkdirErrors, MkdirResponses, NodeHeartbeatData, NodeHeartbeatErrors, NodeHeartbeatResponses, NodeMetricsGetRangeData, NodeMetricsGetRangeErrors, NodeMetricsGetRangeResponses, ObservabilityFullEventData, ObservabilityFullEventErrors, ObservabilityFullEventResponses, ObservabilityListEventsData, ObservabilityListEventsErrors, ObservabilityListEventsResponses, OidcCallbackData, PatchAdminGateData, PatchAdminGateErrors, PatchAdminGateResponses, PatchPreviewGatewaySettingsData, PatchPreviewGatewaySettingsResponses, PauseDeploymentData, PauseDeploymentErrors, PauseDeploymentResponses, PauseSandboxData, PauseSandboxErrors, PauseSandboxResponses, PlanRestoreData, PlanRestoreErrors, PlanRestoreResponses, PostDnsAckData, PostDnsAckErrors, PostDnsAckResponses, PreviewAlertData, PreviewAlertErrors, PreviewAlertResponses, PreviewFunnelMetricsData, PreviewFunnelMetricsErrors, PreviewFunnelMetricsResponses, PreviewHostnameModeData, PreviewHostnameModeErrors, PreviewHostnameModeResponses, PromoteClusterMemberData, PromoteClusterMemberErrors, PromoteClusterMemberResponses, PromoteDeploymentData, PromoteDeploymentErrors, PromoteDeploymentResponses, ProvisionDomainData, ProvisionDomainErrors, ProvisionDomainResponses, PurgeProjectLogsData, PurgeProjectLogsErrors, PurgeProjectLogsResponses, PushExternalImageData, PushExternalImageErrors, PushExternalImageResponses, QueryDataData, QueryDataErrors, QueryDataResponses, QueryGenaiTracesData, QueryGenaiTracesErrors, QueryGenaiTracesResponses, QueryLogsData, QueryLogsErrors, QueryLogsResponses, QueryMetricsData, QueryMetricsErrors, QueryMetricsResponses, QueryTracesData, QueryTracesErrors, QueryTracesResponses, QueryTraceSummariesData, QueryTraceSummariesErrors, QueryTraceSummariesResponses, ReadFileData, ReadFileErrors, ReadFileResponses, ReAnalyzeData, ReAnalyzeErrors, ReAnalyzeResponses, RebuildSandboxImageData, RebuildSandboxImageErrors, RebuildSandboxImageResponses, RecordConsoleEventData, RecordConsoleEventErrors, RecordConsoleEventResponses, RecordEventMetricsData, RecordEventMetricsErrors, RecordEventMetricsResponses, RecordFlagExposureData, RecordFlagExposureErrors, RecordFlagExposureResponses, RecordSpeedMetricsData, RecordSpeedMetricsErrors, RecordSpeedMetricsResponses, RefreshRouteTableData, RefreshRouteTableErrors, RefreshRouteTableResponses, RegenerateDsnData, RegenerateDsnErrors, RegenerateDsnResponses, RegisterExternalImageData, RegisterExternalImageErrors, RegisterExternalImageResponses, RegisterNodeData, RegisterNodeErrors, RegisterNodeResponses, ReinstallGitlabWebhookData, ReinstallGitlabWebhookErrors, ReinstallGitlabWebhookResponses, RejectPendingActionData, RejectPendingActionErrors, RejectPendingActionResponses, ReloadPluginsData, ReloadPluginsErrors, ReloadPluginsResponses, RemoveClusterMemberData, RemoveClusterMemberErrors, RemoveClusterMemberResponses, RemoveManagedDomainData, RemoveManagedDomainErrors, RemoveManagedDomainResponses, RemoveRoleData, RemoveRoleErrors, RemoveRoleResponses, RemoveTeamMemberData, RemoveTeamMemberErrors, RemoveTeamMemberResponses, RenameConversationData, RenameConversationErrors, RenameConversationResponses, RenewDomainData, RenewDomainErrors, RenewDomainResponses, RequestPasswordResetData, RequestPasswordResetErrors, RequestPasswordResetResponses, ResetPasswordData, ResetPasswordErrors, ResetPasswordResponses, ResizeSandboxData, ResizeSandboxErrors, ResizeSandboxResponses, ResolveAlarmData, ResolveAlarmErrors, ResolveAlarmResponses, RestartContainerData, RestartContainerErrors, RestartContainerResponses, RestartPreviewGatewayData, RestartPreviewGatewayResponses, RestartSandboxData, RestartSandboxErrors, RestartSandboxResponses, RestoreFlagData, RestoreFlagErrors, RestoreFlagResponses, RestoreUserData, RestoreUserErrors, RestoreUserResponses, ResumeDeploymentData, ResumeDeploymentErrors, ResumeDeploymentResponses, ResumeSandboxData, ResumeSandboxErrors, ResumeSandboxResponses, RetryClusterData, RetryClusterErrors, RetryClusterResponses, RetryDeliveryData, RetryDeliveryErrors, RetryDeliveryResponses, RetryPgUpgradeData, RetryPgUpgradeErrors, RetryPgUpgradeResponses, RetryRunData, RetryRunErrors, RetryRunResponses, RevealGlobalMcpConfigData, RevealGlobalMcpConfigErrors, RevealGlobalMcpConfigResponses, RevealMcpConfigData, RevealMcpConfigErrors, RevealMcpConfigResponses, RevealNotificationProviderConfigData, RevealNotificationProviderConfigErrors, RevealNotificationProviderConfigResponses, RevealServiceParameterData, RevealServiceParameterErrors, RevealServiceParameterResponses, RevenueCreateIntegrationData, RevenueCreateIntegrationErrors, RevenueCreateIntegrationResponses, RevenueDeleteIntegrationData, RevenueDeleteIntegrationResponses, RevenueGlobalEventsData, RevenueGlobalEventsResponses, RevenueImportInvoicesCsvData, RevenueImportInvoicesCsvErrors, RevenueImportInvoicesCsvResponses, RevenueImportSubscriptionsCsvData, RevenueImportSubscriptionsCsvErrors, RevenueImportSubscriptionsCsvResponses, RevenueListIntegrationsData, RevenueListIntegrationsResponses, RevenueListProvidersData, RevenueListProvidersResponses, RevenueMetricsCustomersData, RevenueMetricsCustomersResponses, RevenueMetricsGlobalMrrData, RevenueMetricsGlobalMrrResponses, RevenueMetricsGlobalSummaryData, RevenueMetricsGlobalSummaryResponses, RevenueMetricsMrrData, RevenueMetricsMrrResponses, RevenueMetricsSummaryData, RevenueMetricsSummaryResponses, RevenueRecentEventsData, RevenueRecentEventsResponses, RevenueRotateTokenData, RevenueRotateTokenResponses, RevenueUpdateConfigData, RevenueUpdateConfigErrors, RevenueUpdateConfigResponses, RevenueUpdateSecretData, RevenueUpdateSecretErrors, RevenueUpdateSecretResponses, RevokeDsnData, RevokeDsnErrors, RevokeDsnResponses, RevokeEnrollmentTokenData, RevokeEnrollmentTokenErrors, RevokeEnrollmentTokenResponses, RevokeJoinTokenData, RevokeJoinTokenErrors, RevokeJoinTokenResponses, RevokeProjectAccessData, RevokeProjectAccessErrors, RevokeProjectAccessResponses, RollbackPgUpgradeData, RollbackPgUpgradeErrors, RollbackPgUpgradeResponses, RollbackToDeploymentData, RollbackToDeploymentErrors, RollbackToDeploymentResponses, RootfsGcData, RootfsGcResponses, RootfsReportData, RootfsReportResponses, RotateApiKeyData, RotateApiKeyErrors, RotateApiKeyResponses, RotateDeploymentTokenData, RotateDeploymentTokenErrors, RotateDeploymentTokenResponses, RunBackupForSourceData, RunBackupForSourceErrors, RunBackupForSourceResponses, RunConnectionHealthCheckData, RunConnectionHealthCheckErrors, RunConnectionHealthCheckResponses, RunExternalServiceBackupData, RunExternalServiceBackupErrors, RunExternalServiceBackupResponses, RunScheduleNowData, RunScheduleNowErrors, RunScheduleNowResponses, SandboxCreatePreviewLinkData, SandboxCreatePreviewLinkErrors, SandboxCreatePreviewLinkResponses, SaveAgentTokenData, SaveAgentTokenErrors, SaveAgentTokenResponses, SaveAiProviderCredentialData, SaveAiProviderCredentialErrors, SaveAiProviderCredentialResponses, SearchLogsData, SearchLogsErrors, SearchLogsResponses, SendEmailData, SendEmailErrors, SendEmailResponses, SendMessageData, SendMessageErrors, SendMessageResponses, SetDefaultS3SourceData, SetDefaultS3SourceErrors, SetDefaultS3SourceResponses, SetFlagEnvironmentData, SetFlagEnvironmentErrors, SetFlagEnvironmentResponses, SetPreviewPasswordData, SetPreviewPasswordErrors, SetPreviewPasswordResponses, SetupDnsChallengeData, SetupDnsChallengeErrors, SetupDnsChallengeResponses, SetupDnsData, SetupDnsErrors, SetupDnsResponses, SetupEmailTrackingData, SetupEmailTrackingErrors, SetupEmailTrackingResponses, SetupMfaData, SetupMfaErrors, SetupMfaResponses, SleepEnvironmentData, SleepEnvironmentErrors, SleepEnvironmentResponses, SmokeTestAgentData, SmokeTestAgentErrors, SmokeTestAgentResponses, SourceSandboxData, SourceSandboxErrors, SourceSandboxResponses, StartAnalysisData, StartAnalysisErrors, StartAnalysisResponses, StartContainerData, StartContainerErrors, StartContainerResponses, StartFixData, StartFixErrors, StartFixResponses, StartGitProviderOauthData, StartGitProviderOauthErrors, StartOidcLoginBySlugData, StartOidcLoginBySlugErrors, StartPgUpgradeData, StartPgUpgradeErrors, StartPgUpgradeResponses, StartRestoreData, StartRestoreErrors, StartRestoreResponses, StartServiceData, StartServiceErrors, StartServiceResponses, StatPathData, StatPathErrors, StatPathResponses, StopContainerData, StopContainerErrors, StopContainerResponses, StopSandboxData, StopSandboxErrors, StopSandboxResponses, StopServiceData, StopServiceErrors, StopServiceResponses, StreamContainerMetricsData, StreamContainerMetricsErrors, StreamContainerMetricsResponses, StreamEventsData, StreamEventsErrors, StreamEventsResponses, StreamRunEventsData, StreamRunEventsErrors, StreamRunEventsResponses, SyncRepositoriesData, SyncRepositoriesErrors, SyncRepositoriesResponses, TailDeploymentJobLogsData, TailDeploymentJobLogsErrors, TailLogsData, TailLogsErrors, TailLogsResponses, TeardownDeploymentData, TeardownDeploymentErrors, TeardownDeploymentResponses, TeardownEnvironmentData, TeardownEnvironmentErrors, TeardownEnvironmentResponses, TestNotificationProviderData, TestNotificationProviderErrors, TestNotificationProviderResponses, TestOidcProviderData, TestOidcProviderResponses, TestProviderConnectionData, TestProviderConnectionErrors, TestProviderConnectionResponses, TestProviderData, TestProviderErrors, TestProviderKeyByIdData, TestProviderKeyByIdErrors, TestProviderKeyByIdResponses, TestProviderKeyInlineData, TestProviderKeyInlineErrors, TestProviderKeyInlineResponses, TestProviderResponses, TestS3ConnectionPreviewData, TestS3ConnectionPreviewErrors, TestS3ConnectionPreviewResponses, TestS3SourceConnectionData, TestS3SourceConnectionErrors, TestS3SourceConnectionResponses, TrackClickData, TrackClickErrors, TrackOpenData, TrackOpenErrors, TrackOpenResponses, TriggerAgentData, TriggerAgentErrors, TriggerAgentResponses, TriggerProjectPipelineData, TriggerProjectPipelineErrors, TriggerProjectPipelineResponses, TriggerScanData, TriggerScanErrors, TriggerScanResponses, TriggerServiceHealthCheckData, TriggerServiceHealthCheckErrors, TriggerServiceHealthCheckResponses, TriggerWeeklyDigestData, TriggerWeeklyDigestErrors, TriggerWeeklyDigestResponses, UnlinkServiceFromProjectData, UnlinkServiceFromProjectErrors, UnlinkServiceFromProjectResponses, UpdateAgentData, UpdateAgentErrors, UpdateAgentResponses, UpdateAiProviderData, UpdateAiProviderErrors, UpdateAiProviderResponses, UpdateAlertData, UpdateAlertErrors, UpdateAlertResponses, UpdateAlertRuleData, UpdateAlertRuleErrors, UpdateAlertRuleResponses, UpdateApiKeyData, UpdateApiKeyErrors, UpdateApiKeyResponses, UpdateAutomaticDeployData, UpdateAutomaticDeployErrors, UpdateAutomaticDeployResponses, UpdateBackupScheduleData, UpdateBackupScheduleErrors, UpdateBackupScheduleResponses, UpdateCloudflareProviderData, UpdateCloudflareProviderErrors, UpdateCloudflareProviderResponses, UpdateConnectionTokenData, UpdateConnectionTokenErrors, UpdateConnectionTokenResponses, UpdateCustomDomainData, UpdateCustomDomainErrors, UpdateCustomDomainResponses, UpdateDashboardData, UpdateDashboardErrors, UpdateDashboardResponses, UpdateDeploymentTokenData, UpdateDeploymentTokenErrors, UpdateDeploymentTokenResponses, UpdateEmailProviderData, UpdateEmailProviderErrors, UpdateEmailProviderResponses, UpdateEnvironmentSettingsData, UpdateEnvironmentSettingsErrors, UpdateEnvironmentSettingsResponses, UpdateEnvironmentSubdomainData, UpdateEnvironmentSubdomainErrors, UpdateEnvironmentSubdomainResponses, UpdateEnvironmentVariableData, UpdateEnvironmentVariableErrors, UpdateEnvironmentVariableResponses, UpdateErrorGroupData, UpdateErrorGroupErrors, UpdateErrorGroupResponses, UpdateFlagData, UpdateFlagErrors, UpdateFlagResponses, UpdateFunnelData, UpdateFunnelErrors, UpdateFunnelResponses, UpdateGitProviderCredentialsData, UpdateGitProviderCredentialsErrors, UpdateGitProviderCredentialsResponses, UpdateGitSettingsData, UpdateGitSettingsErrors, UpdateGitSettingsResponses, UpdateGlobalMcpData, UpdateGlobalMcpErrors, UpdateGlobalMcpResponses, UpdateGlobalSkillData, UpdateGlobalSkillErrors, UpdateGlobalSkillResponses, UpdateIncidentStatusData, UpdateIncidentStatusErrors, UpdateIncidentStatusResponses, UpdateIpAccessControlData, UpdateIpAccessControlErrors, UpdateIpAccessControlResponses, UpdateManagedDomainData, UpdateManagedDomainErrors, UpdateManagedDomainResponses, UpdateMcpData, UpdateMcpErrors, UpdateMcpResponses, UpdateNotificationEmailProviderData, UpdateNotificationEmailProviderErrors, UpdateNotificationEmailProviderResponses, UpdateNotificationProviderData, UpdateNotificationProviderErrors, UpdateNotificationProviderResponses, UpdateOidcProviderData, UpdateOidcProviderResponses, UpdatePreferencesData, UpdatePreferencesErrors, UpdatePreferencesResponses, UpdateProjectData, UpdateProjectDeploymentConfigData, UpdateProjectDeploymentConfigErrors, UpdateProjectDeploymentConfigResponses, UpdateProjectErrors, UpdateProjectResponses, UpdateProjectSecretData, UpdateProjectSecretErrors, UpdateProjectSecretResponses, UpdateProjectSettingsData, UpdateProjectSettingsErrors, UpdateProjectSettingsResponses, UpdateProviderData, UpdateProviderErrors, UpdateProviderKeyData, UpdateProviderKeyErrors, UpdateProviderKeyResponses, UpdateProviderResponses, UpdateRouteData, UpdateRouteErrors, UpdateRouteResponses, UpdateS3SourceData, UpdateS3SourceErrors, UpdateS3SourceResponses, UpdateSelfData, UpdateSelfErrors, UpdateSelfResponses, UpdateServiceData, UpdateServiceErrors, UpdateServiceResourcesData, UpdateServiceResourcesErrors, UpdateServiceResourcesResponses, UpdateServiceResponses, UpdateSessionDurationData, UpdateSessionDurationErrors, UpdateSessionDurationResponses, UpdateSettingsData, UpdateSettingsErrors, UpdateSettingsResponses, UpdateSkillData, UpdateSkillErrors, UpdateSkillResponses, UpdateSlackProviderData, UpdateSlackProviderErrors, UpdateSlackProviderResponses, UpdateSpeedMetricsData, UpdateSpeedMetricsErrors, UpdateSpeedMetricsResponses, UpdateTeamData, UpdateTeamErrors, UpdateTeamMemberRoleData, UpdateTeamMemberRoleErrors, UpdateTeamMemberRoleResponses, UpdateTeamResponses, UpdateUserData, UpdateUserErrors, UpdateUserResponses, UpdateWebhookData, UpdateWebhookErrors, UpdateWebhookProviderData, UpdateWebhookProviderErrors, UpdateWebhookProviderResponses, UpdateWebhookResponses, UpgradePreviewGatewayData, UpgradePreviewGatewayResponses, UpgradeServiceData, UpgradeServiceErrors, UpgradeServiceResponses, UploadGlobalSkillData, UploadGlobalSkillErrors, UploadGlobalSkillResponses, UploadReleaseFileData, UploadReleaseFileErrors, UploadReleaseFileResponses, UploadSkillData, UploadSkillErrors, UploadSkillResponses, UploadSourceFileData, UploadSourceFileErrors, UploadSourceFileResponses, UploadSourceMapData, UploadSourceMapErrors, UploadSourceMapResponses, UploadStaticBundleData, UploadStaticBundleErrors, UploadStaticBundleResponses, UpsertSecretData, UpsertSecretErrors, UpsertSecretResponses, ValidateConnectionData, ValidateConnectionErrors, ValidateConnectionResponses, ValidateEmailData, ValidateEmailErrors, ValidateEmailResponses, VerifyAndEnableMfaData, VerifyAndEnableMfaErrors, VerifyAndEnableMfaResponses, VerifyDomainData, VerifyDomainErrors, VerifyDomainResponses, VerifyEmailData, VerifyEmailErrors, VerifyEmailResponses, VerifyManagedDomainData, VerifyManagedDomainErrors, VerifyManagedDomainResponses, VerifyMfaChallengeData, VerifyMfaChallengeErrors, VerifyMfaChallengeResponses, VerifyStepUpData, VerifyStepUpErrors, VerifyStepUpResponses, WakeEnvironmentData, WakeEnvironmentErrors, WakeEnvironmentResponses, WebhookTriggerData, WebhookTriggerErrors, WebhookTriggerResponses, WorkflowDryRunData, WorkflowDryRunErrors, WorkflowDryRunResponses, WriteFileData, WriteFileErrors, WriteFileResponses, WriteFilesData, WriteFilesErrors, WriteFilesResponses } from './types.gen'; export type Options = Options2 & { /** @@ -1320,6 +1320,34 @@ export const blobHead = (options: Options< ...options }); +export const disconnectCloud = (options?: Options): RequestResult => (options?.client ?? client).delete({ + security: [{ scheme: 'bearer', type: 'http' }], + url: '/cloud', + ...options +}); + +export const getCloudCapability = (options?: Options): RequestResult => (options?.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }], + url: '/cloud/capability', + ...options +}); + +export const enrollCloud = (options: Options): RequestResult => (options.client ?? client).post({ + security: [{ scheme: 'bearer', type: 'http' }], + url: '/cloud/enroll', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +export const getCloudStatus = (options?: Options): RequestResult => (options?.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }], + url: '/cloud/status', + ...options +}); + /** * Get dashboard analytics for multiple projects in a single batch request * diff --git a/apps/temps-cli/src/api/types.gen.ts b/apps/temps-cli/src/api/types.gen.ts index ecd8daf63..0e9811cfe 100644 --- a/apps/temps-cli/src/api/types.gen.ts +++ b/apps/temps-cli/src/api/types.gen.ts @@ -1008,6 +1008,11 @@ export type AppSettings = { * hardware that already has its own per-host headroom). */ build_limits?: BuildLimitsSettings; + /** + * Managed control-plane connection. Credentials are deliberately not + * stored here; they live in the owner-only cloud-link state file. + */ + cloud?: CloudSettings; /** * Cluster-DNS resolver settings (ADR-024, experimental beta). Off by * default — see `ClusterDnsSettings` for the incident background and @@ -2121,11 +2126,37 @@ export type CliLoginRequest = { username: string; }; +export type CloudCapability = { + configured: boolean; + reason?: string | null; + setup_path: string; +}; + /** * Cloud provider detected from node metadata */ export type CloudProvider = 'aws' | 'gcp' | 'azure' | 'hetzner' | 'digitalocean' | 'other'; +/** + * Non-secret managed control-plane settings stored with application settings. + */ +export type CloudSettings = { + /** + * HTTPS origin used for enrollment and telemetry mirroring. + */ + backend_url?: string; +}; + +export type CloudStatus = { + backend_url: string; + health: string; + health_message: string; + instance_id?: string | null; + spooled_spans: number; + status: string; + status_message: string; +}; + /** * Configuration for a Cloudflare Email Sending notification provider. * @@ -4737,6 +4768,19 @@ export type DeploymentMetadata = { * ID of the deployment this was rolled back from (if applicable) */ rolledBackFromId?: number | null; + /** + * Uploaded source archive content type. + */ + sourceBundleContentType?: string | null; + /** + * Uploaded source archive ID. Source archives are extracted before the + * regular preset build pipeline and do not require Git metadata. + */ + sourceBundleId?: number | null; + /** + * Uploaded source archive path in the Temps data directory. + */ + sourceBundlePath?: string | null; /** * Static bundle content type (for proper extraction: application/gzip or application/zip) */ @@ -6001,6 +6045,10 @@ export type EnrichVisitorResponse = { visitor_id: string; }; +export type EnrollCloudRequest = { + enrollment_code: string; +}; + export type EnrollmentTokenInfo = { bound_node_name?: string | null; created_at: string; @@ -24072,6 +24120,58 @@ export type BlobHeadResponses = { 200: unknown; }; +export type DisconnectCloudData = { + body?: never; + path?: never; + query?: never; + url: '/cloud'; +}; + +export type DisconnectCloudResponses = { + 200: CloudStatus; +}; + +export type DisconnectCloudResponse = DisconnectCloudResponses[keyof DisconnectCloudResponses]; + +export type GetCloudCapabilityData = { + body?: never; + path?: never; + query?: never; + url: '/cloud/capability'; +}; + +export type GetCloudCapabilityResponses = { + 200: CloudCapability; +}; + +export type GetCloudCapabilityResponse = GetCloudCapabilityResponses[keyof GetCloudCapabilityResponses]; + +export type EnrollCloudData = { + body: EnrollCloudRequest; + path?: never; + query?: never; + url: '/cloud/enroll'; +}; + +export type EnrollCloudResponses = { + 200: CloudStatus; +}; + +export type EnrollCloudResponse = EnrollCloudResponses[keyof EnrollCloudResponses]; + +export type GetCloudStatusData = { + body?: never; + path?: never; + query?: never; + url: '/cloud/status'; +}; + +export type GetCloudStatusResponses = { + 200: CloudStatus; +}; + +export type GetCloudStatusResponse = GetCloudStatusResponses[keyof GetCloudStatusResponses]; + export type GetDashboardProjectsAnalyticsData = { body?: never; path?: never; diff --git a/apps/temps-cli/src/commands/cloud/index.ts b/apps/temps-cli/src/commands/cloud/index.ts index 5705f0328..d595ecb73 100644 --- a/apps/temps-cli/src/commands/cloud/index.ts +++ b/apps/temps-cli/src/commands/cloud/index.ts @@ -11,10 +11,17 @@ import { keyValue, error as errorOutput, } from '../../ui/output.js' -import { startSpinner, succeedSpinner, failSpinner, updateSpinner } from '../../ui/spinner.js' +import { startSpinner, succeedSpinner, failSpinner, updateSpinner, withSpinner } from '../../ui/spinner.js' import { getCloudUrl, cloudFetch, isCloudAuthenticated } from '../../lib/cloud-client.js' import { registerCloudVpsCommands } from './vps.js' import { registerCloudBillingCommands } from './billing.js' +import { requireAuth } from '../../config/store.js' +import { client, getErrorMessage, setupClient } from '../../lib/api-client.js' +import { + disconnectCloud as disconnectInstance, + enrollCloud as enrollInstance, + getCloudStatus as getInstanceCloudStatus, +} from '../../api/sdk.gen.js' interface DeviceCodeResponse { device_code: string @@ -222,6 +229,54 @@ async function cloudWhoami(): Promise { newline() } +async function instanceStatus(options: { json?: boolean }): Promise { + await requireAuth() + await setupClient() + const result = await withSpinner('Reading Temps Cloud link...', async () => { + const { data, error } = await getInstanceCloudStatus({ client }) + if (error) throw new Error(getErrorMessage(error)) + return data + }) + if (!result) return + if (options.json) { + process.stdout.write(`${JSON.stringify(result, null, 2)}\n`) + return + } + newline() + header(`${icons.globe} Instance Cloud Link`) + keyValue('Status', result.status.replaceAll('_', ' ')) + keyValue('Health', result.health.replaceAll('_', ' ')) + keyValue('Instance', result.instance_id ?? 'not enrolled') + keyValue('Buffered spans', result.spooled_spans) + info(result.status_message) + if (result.health !== 'healthy') info(result.health_message) + newline() +} + +async function connectInstance(options: { code: string }): Promise { + await requireAuth() + await setupClient() + const result = await withSpinner('Connecting this instance...', async () => { + const { data, error } = await enrollInstance({ + client, + body: { enrollment_code: options.code }, + }) + if (error) throw new Error(getErrorMessage(error)) + return data + }) + if (result) info(`Connected. ${result.status_message}`) +} + +async function disconnectCurrentInstance(): Promise { + await requireAuth() + await setupClient() + await withSpinner('Disconnecting this instance...', async () => { + const { error } = await disconnectInstance({ client }) + if (error) throw new Error(getErrorMessage(error)) + }) + info('Instance disconnected from Temps Cloud') +} + export function registerCloudCommands(program: Command): void { const cloud = program .command('cloud') @@ -242,6 +297,23 @@ export function registerCloudCommands(program: Command): void { .description('Show current Temps Cloud account') .action(cloudWhoami) + cloud + .command('status') + .description('Show this self-hosted instance\'s Temps Cloud link') + .option('--json', 'Output JSON') + .action(instanceStatus) + + cloud + .command('connect') + .description('Connect this self-hosted instance using an enrollment code') + .requiredOption('--code ', 'Single-use enrollment code from Temps Cloud') + .action(connectInstance) + + cloud + .command('disconnect') + .description('Disconnect this self-hosted instance from Temps Cloud') + .action(disconnectCurrentInstance) + registerCloudVpsCommands(cloud) registerCloudBillingCommands(cloud) } diff --git a/apps/temps-cli/src/commands/env-sync/index.ts b/apps/temps-cli/src/commands/env-sync/index.ts index c57bcfa4e..e30c44d14 100644 --- a/apps/temps-cli/src/commands/env-sync/index.ts +++ b/apps/temps-cli/src/commands/env-sync/index.ts @@ -102,11 +102,12 @@ async function pull( // Generate .env content const envContent = filteredVars .map(v => { - const escapedValue = v.value.includes('\n') || v.value.includes('"') - ? `"${v.value.replace(/"/g, '\\"').replace(/\n/g, '\\n')}"` - : v.value.includes(' ') || v.value.includes('#') - ? `"${v.value}"` - : v.value + const value = v.value ?? '' + const escapedValue = value.includes('\n') || value.includes('"') + ? `"${value.replace(/"/g, '\\"').replace(/\n/g, '\\n')}"` + : value.includes(' ') || value.includes('#') + ? `"${value}"` + : value return `${v.key}=${escapedValue}` }) .join('\n') diff --git a/apps/temps-cli/src/commands/environments/index.ts b/apps/temps-cli/src/commands/environments/index.ts index 4b44b1ac4..54e864ca0 100644 --- a/apps/temps-cli/src/commands/environments/index.ts +++ b/apps/temps-cli/src/commands/environments/index.ts @@ -945,11 +945,12 @@ async function exportEnvVars( // Generate .env content const envContent = filteredVars .map(v => { - const escapedValue = v.value.includes('\n') || v.value.includes('"') - ? `"${v.value.replace(/"/g, '\\"').replace(/\n/g, '\\n')}"` - : v.value.includes(' ') || v.value.includes('#') - ? `"${v.value}"` - : v.value + const value = v.value ?? '' + const escapedValue = value.includes('\n') || value.includes('"') + ? `"${value.replace(/"/g, '\\"').replace(/\n/g, '\\n')}"` + : value.includes(' ') || value.includes('#') + ? `"${value}"` + : value return `${v.key}=${escapedValue}` }) .join('\n') diff --git a/apps/temps-cli/src/commands/notifications/index.ts b/apps/temps-cli/src/commands/notifications/index.ts index c10feb4e7..65b6208c9 100644 --- a/apps/temps-cli/src/commands/notifications/index.ts +++ b/apps/temps-cli/src/commands/notifications/index.ts @@ -10,7 +10,7 @@ import { testNotificationProvider as testProvider2, updateNotificationProvider as updateProvider2, updateSlackProvider, - updateEmailProvider, + updateNotificationEmailProvider, } from '../../api/sdk.gen.js' import type { NotificationProviderResponse } from '../../api/types.gen.js' import { withSpinner } from '../../ui/spinner.js' @@ -567,7 +567,7 @@ async function updateEmailProviderAction( } | null const updated = await withSpinner('Updating Email provider...', async () => { - const { data, error } = await updateEmailProvider({ + const { data, error } = await updateNotificationEmailProvider({ client, path: { id }, body: { diff --git a/apps/temps-cli/src/commands/providers/index.ts b/apps/temps-cli/src/commands/providers/index.ts index 25812df3a..ef2b52321 100644 --- a/apps/temps-cli/src/commands/providers/index.ts +++ b/apps/temps-cli/src/commands/providers/index.ts @@ -961,10 +961,8 @@ async function syncConnectionAction(options: IdOptions): Promise { return data }) - success(`Synced ${result?.total_count ?? 0} repositories for connection ${id}`) - if (result?.synced_at) { - info(`Synced at: ${result.synced_at}`) - } + success(`Repository sync started for connection ${result?.connection_id ?? id}`) + if (result?.started_at) info(`Started at: ${result.started_at}`) } async function updateTokenAction(options: UpdateTokenOptions): Promise { diff --git a/crates/temps-cli/Cargo.toml b/crates/temps-cli/Cargo.toml index 0f5495449..2fc266a8d 100644 --- a/crates/temps-cli/Cargo.toml +++ b/crates/temps-cli/Cargo.toml @@ -41,6 +41,7 @@ temps-backup = { path = "../temps-backup" } temps-revenue = { path = "../temps-revenue" } temps-observability = { path = "../temps-observability" } temps-config = { path = "../temps-config" } +temps-cloud = { path = "../temps-cloud" } temps-core = { path = "../temps-core" } temps-database = { path = "../temps-database" } temps-deployer = { path = "../temps-deployer" } diff --git a/crates/temps-cli/src/commands/serve/console.rs b/crates/temps-cli/src/commands/serve/console.rs index 0d47642e2..1775d1614 100644 --- a/crates/temps-cli/src/commands/serve/console.rs +++ b/crates/temps-cli/src/commands/serve/console.rs @@ -24,6 +24,7 @@ use temps_audit::AuditPlugin; use temps_auth::{ApiKeyPlugin, AuthPlugin}; use temps_backup::BackupPlugin; use temps_blob::BlobPlugin; +use temps_cloud::{CloudPlugin, CloudService}; use temps_config::ConfigPlugin; use temps_config::ServerConfig; use temps_core::plugin::{PluginManager, TempsPlugin}; @@ -1893,6 +1894,15 @@ pub async fn start_console_api(params: ConsoleApiParams) -> anyhow::Result<()> { let config_plugin = Box::new(ConfigPlugin::new(config.clone())); plugin_manager.register_plugin(config_plugin); + // Optional managed control plane. It owns the enrollment state and the + // background telemetry mirror consumed later by OtelPlugin. + debug!("Registering CloudPlugin"); + let cloud_plugin = Box::new(CloudPlugin::new( + config.data_dir.clone(), + env!("CARGO_PKG_VERSION"), + )); + plugin_manager.register_plugin(cloud_plugin); + // 1.5. TelemetryPlugin - registers the anonymous telemetry reporter // (depends only on ServerConfig for the data dir). Registered early so // every later plugin can require the Arc. @@ -2981,12 +2991,20 @@ pub async fn start_console_api(params: ConsoleApiParams) -> anyhow::Result<()> { let external_plugins_service = plugin_manager .service_context() .get_service::(); + let cloud_service = plugin_manager + .service_context() + .get_service::(); let shutdown_signal = { let svc = external_plugins_service.clone(); + let cloud = cloud_service.clone(); async move { let _ = tokio::signal::ctrl_c().await; - info!("Console API received shutdown signal, stopping external plugins..."); + info!("Console API received shutdown signal, stopping background services..."); + if let Some(service) = cloud { + service.shutdown().await; + info!("Managed telemetry mirror shut down"); + } if let Some(service) = svc { service.shutdown_all().await; info!("External plugins shut down"); diff --git a/crates/temps-cloud-client/src/lib.rs b/crates/temps-cloud-client/src/lib.rs index 0edbf766e..c2e651353 100644 --- a/crates/temps-cloud-client/src/lib.rs +++ b/crates/temps-cloud-client/src/lib.rs @@ -219,6 +219,41 @@ impl CloudClient { Err(CloudError::EnrollmentRefused { detail }) } + /// Revoke an instance credential before removing the local copy. + pub async fn revoke(&self, token: &str) -> Result<(), CloudError> { + let res = self + .http + .post(self.backend.endpoint("/v1/revoke")) + .bearer_auth(token) + .send() + .await + .map_err(|e| CloudError::Unreachable { + reason: e.to_string(), + spooled_bytes: 0, + })?; + + let status = res.status(); + if status.is_success() { + return Ok(()); + } + match status.as_u16() { + 401 | 403 => Err(CloudError::CredentialRejected), + 429 | 500..=599 => Err(CloudError::Unreachable { + reason: format!("backend returned {status}"), + spooled_bytes: 0, + }), + _ => { + let detail = res + .json::() + .await + .ok() + .and_then(|value| value["detail"].as_str().map(String::from)) + .unwrap_or_else(|| format!("backend returned {status}")); + Err(CloudError::Rejected { detail }) + } + } + } + /// Mirror a batch of spans. Never called on a request path. pub async fn ship( &self, diff --git a/crates/temps-cloud-client/src/link.rs b/crates/temps-cloud-client/src/link.rs index 8c388f47c..150099641 100644 --- a/crates/temps-cloud-client/src/link.rs +++ b/crates/temps-cloud-client/src/link.rs @@ -15,8 +15,9 @@ //! silently... no: the worst it can do is *count a drop the operator can see*. use std::path::PathBuf; -use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; +use std::sync::atomic::{AtomicBool, AtomicU64, AtomicUsize, Ordering}; use std::sync::{Mutex, RwLock}; +use tokio::sync::mpsc; use temps_cloud_protocol::SpanRecord; use uuid::Uuid; @@ -28,6 +29,9 @@ use crate::{BackendUrl, CloudClient, CloudError}; /// Spans per shipment. Small enough that one failure loses little progress. const BATCH_SIZE: usize = 500; +/// Number of producer batches accepted before the mirror starts shedding load. +/// The local telemetry store remains authoritative and is never affected. +const INCOMING_BATCH_CAPACITY: usize = 8; /// What a flush attempt did. Returned so a caller can log or schedule backoff. #[derive(Debug, Clone, PartialEq)] @@ -57,8 +61,18 @@ struct PendingSubmission { spans: Vec, } +struct IncomingBatch { + generation: u64, + spans: Vec, +} + pub struct CloudLink { state: RwLock>, + incoming_tx: mpsc::Sender, + incoming_rx: Mutex>, + incoming_spans: AtomicUsize, + incoming_dropped: AtomicU64, + linked: AtomicBool, spool: Mutex, /// The active submission stays here until a matching full acknowledgement /// arrives, preserving its id across retries. @@ -103,9 +117,16 @@ impl CloudLink { tracing::error!(error = %e, "link state unreadable; treating as unlinked"); None }); + let linked = state.as_ref().is_some_and(EnrollmentState::is_linked); + let (incoming_tx, incoming_rx) = mpsc::channel(INCOMING_BATCH_CAPACITY); Self { state: RwLock::new(state), + incoming_tx, + incoming_rx: Mutex::new(incoming_rx), + incoming_spans: AtomicUsize::new(0), + incoming_dropped: AtomicU64::new(0), + linked: AtomicBool::new(linked), spool: Mutex::new(Spool::with_default_capacity()), pending: Mutex::new(None), health: RwLock::new(MirrorHealth::Healthy), @@ -148,6 +169,18 @@ impl CloudLink { } pub fn health(&self) -> MirrorHealth { + let spool_dropped = self + .spool + .lock() + .unwrap_or_else(|p| p.into_inner()) + .dropped(); + let dropped = spool_dropped.saturating_add(self.incoming_dropped.load(Ordering::Relaxed)); + if dropped > 0 { + return MirrorHealth::Dropping { + spooled: self.spooled(), + dropped, + }; + } self.health .read() .unwrap_or_else(|p| p.into_inner()) @@ -162,10 +195,24 @@ impl CloudLink { .map(|s| s.instance_id) } + /// Lock-free fast-path hint for telemetry producers. Enrollment can race + /// with an offer; generation tagging prevents a raced batch crossing links. + pub fn is_linked(&self) -> bool { + self.linked.load(Ordering::Acquire) + } + /// Point this instance at a backend without linking it yet. pub fn configure(&self, backend: BackendUrl) -> Result<(), crate::state::StateError> { let mut guard = self.state.write().unwrap_or_else(|p| p.into_inner()); let next_url = backend.as_str().to_string(); + if let Some(existing) = guard.as_ref() { + if existing.is_linked() && existing.base_url != next_url { + return Err(crate::state::StateError::BackendChangeRequiresDisconnect { + current: existing.base_url.clone(), + requested: next_url, + }); + } + } let mut changed_origin = false; let next = match guard.as_ref() { Some(existing) => { @@ -184,6 +231,7 @@ impl CloudLink { }; next.save(&self.state_path)?; if changed_origin { + self.linked.store(false, Ordering::Release); self.spool .lock() .unwrap_or_else(|p| p.into_inner()) @@ -197,6 +245,10 @@ impl CloudLink { } *guard = Some(next); self.generation.fetch_add(1, Ordering::SeqCst); + self.linked.store( + guard.as_ref().is_some_and(EnrollmentState::is_linked), + Ordering::Release, + ); Ok(()) } @@ -242,14 +294,32 @@ impl CloudLink { })?; *guard = Some(next); self.generation.fetch_add(1, Ordering::SeqCst); + self.linked.store(true, Ordering::Release); self.credential_rejected.store(false, Ordering::SeqCst); *self.health.write().unwrap_or_else(|p| p.into_inner()) = MirrorHealth::Healthy; Ok(()) } + /// Revoke the active credential at its issuing backend. + /// + /// This deliberately leaves local state untouched. The caller may only + /// remove the local credential after this succeeds, or after the backend + /// confirms that the credential is already invalid. + pub async fn revoke(&self) -> Result<(), CloudError> { + let (base_url, token) = { + let guard = self.state.read().unwrap_or_else(|p| p.into_inner()); + let state = guard.as_ref().ok_or(CloudError::NotEnrolled)?; + let token = state.token.clone().ok_or(CloudError::NotEnrolled)?; + (state.base_url.clone(), token) + }; + let backend = self.parse_backend(&base_url)?; + CloudClient::new(backend)?.revoke(&token).await + } + /// Forget the credential. Keeps the instance identity so re-linking later /// reattaches to the same record. pub fn disconnect(&self) -> Result<(), crate::state::StateError> { + self.linked.store(false, Ordering::Release); let mut guard = self.state.write().unwrap_or_else(|p| p.into_inner()); if let Some(s) = guard.as_mut() { let mut next = s.clone(); @@ -277,23 +347,27 @@ impl CloudLink { /// that does not exist would burn memory to no purpose. Telemetry is still /// stored locally by the instance itself — that path is untouched. pub fn record(&self, spans: Vec) { - let state = self.state.read().unwrap_or_else(|p| p.into_inner()); - if !state.as_ref().is_some_and(|s| s.is_linked()) { + if spans.is_empty() || !self.linked.load(Ordering::Acquire) { return; } - let mut spool = self.spool.lock().unwrap_or_else(|p| p.into_inner()); - spool.push(spans); - - if spool.dropped() > 0 { - *self.health.write().unwrap_or_else(|p| p.into_inner()) = MirrorHealth::Dropping { - spooled: spool.len(), - dropped: spool.dropped(), - }; + let count = spans.len(); + self.incoming_spans.fetch_add(count, Ordering::Relaxed); + let batch = IncomingBatch { + generation: self.generation.load(Ordering::Acquire), + spans, + }; + if let Err(error) = self.incoming_tx.try_send(batch) { + let dropped = error.into_inner().spans.len(); + self.incoming_spans.fetch_sub(dropped, Ordering::Relaxed); + self.incoming_dropped + .fetch_add(dropped as u64, Ordering::Relaxed); } - drop(state); } pub fn spooled(&self) -> usize { + // Status reads are off the ingest path and may opportunistically move + // accepted producer batches into the bounded spool for an exact count. + self.drain_incoming(); let queued = self.spool.lock().unwrap_or_else(|p| p.into_inner()).len(); let pending = self .pending @@ -301,12 +375,26 @@ impl CloudLink { .unwrap_or_else(|p| p.into_inner()) .as_ref() .map_or(0, |batch| batch.spans.len()); - queued + pending + self.incoming_spans.load(Ordering::Relaxed) + queued + pending + } + + fn drain_incoming(&self) { + let current_generation = self.generation.load(Ordering::Acquire); + let mut receiver = self.incoming_rx.lock().unwrap_or_else(|p| p.into_inner()); + let mut spool = self.spool.lock().unwrap_or_else(|p| p.into_inner()); + while let Ok(batch) = receiver.try_recv() { + self.incoming_spans + .fetch_sub(batch.spans.len(), Ordering::Relaxed); + if batch.generation == current_generation && self.linked.load(Ordering::Acquire) { + spool.push(batch.spans); + } + } } /// Ship one batch. Called on an interval by a background task. pub async fn flush(&self) -> FlushOutcome { let _flush = self.flush_lock.lock().await; + self.drain_incoming(); let (base_url, token, generation) = { let guard = self.state.read().unwrap_or_else(|p| p.into_inner()); match guard.as_ref() { @@ -394,7 +482,9 @@ impl CloudLink { } let spool = self.spool.lock().unwrap_or_else(|p| p.into_inner()); let spooled = spool.len() + count; - let dropped = spool.dropped(); + let dropped = spool + .dropped() + .saturating_add(self.incoming_dropped.load(Ordering::Relaxed)); *self.health.write().unwrap_or_else(|p| p.into_inner()) = if dropped > 0 { MirrorHealth::Dropping { spooled, dropped } diff --git a/crates/temps-cloud-client/src/state.rs b/crates/temps-cloud-client/src/state.rs index a369c80d1..dd2ca1c48 100644 --- a/crates/temps-cloud-client/src/state.rs +++ b/crates/temps-cloud-client/src/state.rs @@ -13,6 +13,9 @@ use uuid::Uuid; #[derive(Debug, Error)] pub enum StateError { + #[error("Disconnect from {current} before changing the managed backend to {requested}")] + BackendChangeRequiresDisconnect { current: String, requested: String }, + #[error("Failed to read link state at {path}: {reason}")] Read { path: String, reason: String }, diff --git a/crates/temps-cloud-client/src/status.rs b/crates/temps-cloud-client/src/status.rs index 01d4fe86b..c8c1b2ed8 100644 --- a/crates/temps-cloud-client/src/status.rs +++ b/crates/temps-cloud-client/src/status.rs @@ -4,10 +4,12 @@ //! sentence naming what is wrong and what to do about it — never a spinner, //! never a silent absence, and never a bare boolean the UI has to interpret. +use serde::Serialize; use temps_cloud_protocol::Unavailable; /// Whether this instance is linked to a managed account. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Serialize)] +#[serde(tag = "state", rename_all = "snake_case")] pub enum LinkStatus { /// No backend configured. The UI should offer to connect one rather than /// hiding the feature — an unconfigured capability must onboard, not vanish. @@ -54,7 +56,8 @@ impl LinkStatus { } /// How the mirror is doing, independent of whether the link is valid. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Serialize)] +#[serde(tag = "state", rename_all = "snake_case")] pub enum MirrorHealth { /// Everything shipped. Healthy, diff --git a/crates/temps-cloud-client/tests/link_lifecycle_test.rs b/crates/temps-cloud-client/tests/link_lifecycle_test.rs index bcd315e17..9d849e52e 100644 --- a/crates/temps-cloud-client/tests/link_lifecycle_test.rs +++ b/crates/temps-cloud-client/tests/link_lifecycle_test.rs @@ -23,6 +23,7 @@ struct Stub { received: Arc, submissions: Arc>>, enroll_delay_ms: Arc, + revoked: Arc, } async fn serve(stub: Stub) -> String { @@ -69,6 +70,19 @@ async fn serve(stub: Stub) -> String { }, ), ) + .route( + "/v1/revoke", + post(|State(s): State| async move { + let code = s.status.load(Ordering::SeqCst); + if code == 200 { + s.revoked.fetch_add(1, Ordering::SeqCst); + } + ( + axum::http::StatusCode::from_u16(code).unwrap(), + Json(serde_json::json!({"detail": "stub revoke"})), + ) + }), + ) .with_state(stub); let listener = tokio::net::TcpListener::bind::("127.0.0.1:0".parse().unwrap()) @@ -155,6 +169,34 @@ async fn the_full_lifecycle_configure_enroll_record_flush() { assert_eq!(l.health(), MirrorHealth::Healthy); } +#[tokio::test] +async fn a_saturated_ingest_queue_drops_only_the_mirror_and_reports_it() { + let d = tempfile::tempdir().unwrap(); + let url = serve(Stub { + status: Arc::new(AtomicU16::new(200)), + ..Default::default() + }) + .await; + + let link = link(&d); + link.configure(backend(&url)).unwrap(); + link.enroll("abcd-2345").await.unwrap(); + + for _ in 0..9 { + link.record(spans(1)); + } + + assert_eq!(link.spooled(), 8, "the producer queue must stay bounded"); + assert_eq!( + link.health(), + MirrorHealth::Dropping { + spooled: 8, + dropped: 1, + }, + "mirror pressure must be visible without affecting local ingest" + ); +} + #[tokio::test] async fn concurrent_flushes_ship_each_submission_once() { let d = tempfile::tempdir().unwrap(); @@ -265,7 +307,7 @@ async fn an_outage_buffers_and_a_recovery_drains_without_loss() { } #[tokio::test] -async fn changing_backend_origin_revokes_the_existing_credential() { +async fn changing_backend_origin_requires_remote_disconnect_first() { let d = tempfile::tempdir().unwrap(); let first = serve(Stub { status: Arc::new(AtomicU16::new(200)), @@ -285,16 +327,15 @@ async fn changing_backend_origin_revokes_the_existing_credential() { l.record(spans(2)); assert_eq!(l.spooled(), 2); - l.configure(backend(&second)).unwrap(); + let error = l.configure(backend(&second)).unwrap_err().to_string(); - assert!(matches!(l.status(), LinkStatus::AwaitingEnrollment { .. })); + assert!(error.contains("Disconnect"), "unexpected error: {error}"); + assert!(matches!(l.status(), LinkStatus::Linked { .. })); assert_eq!( l.spooled(), - 0, - "telemetry buffered for one origin must not cross to another" + 2, + "a refused origin change must retain the active link's telemetry" ); - l.record(spans(1)); - assert_eq!(l.flush().await, FlushOutcome::NotLinked); } #[tokio::test] @@ -353,11 +394,11 @@ async fn the_credential_survives_a_restart() { #[tokio::test] async fn disconnecting_clears_the_credential_but_keeps_the_identity() { let d = tempfile::tempdir().unwrap(); - let url = serve(Stub { + let stub = Stub { status: Arc::new(AtomicU16::new(200)), ..Default::default() - }) - .await; + }; + let url = serve(stub.clone()).await; let l = link(&d); l.configure(backend(&url)).unwrap(); @@ -365,8 +406,10 @@ async fn disconnecting_clears_the_credential_but_keeps_the_identity() { let id = l.instance_id().unwrap(); l.record(spans(5)); + l.revoke().await.unwrap(); l.disconnect().unwrap(); + assert_eq!(stub.revoked.load(Ordering::SeqCst), 1); assert!(matches!(l.status(), LinkStatus::AwaitingEnrollment { .. })); assert_eq!( l.spooled(), @@ -376,6 +419,25 @@ async fn disconnecting_clears_the_credential_but_keeps_the_identity() { assert_eq!(l.instance_id().unwrap(), id, "re-linking must reattach"); } +#[tokio::test] +async fn failed_remote_revocation_keeps_the_local_link() { + let d = tempfile::tempdir().unwrap(); + let stub = Stub { + status: Arc::new(AtomicU16::new(200)), + ..Default::default() + }; + let url = serve(stub.clone()).await; + let link = link(&d); + link.configure(backend(&url)).unwrap(); + link.enroll("abcd-2345").await.unwrap(); + + stub.status.store(503, Ordering::SeqCst); + assert!(link.revoke().await.is_err()); + + assert!(matches!(link.status(), LinkStatus::Linked { .. })); + assert_eq!(stub.revoked.load(Ordering::SeqCst), 0); +} + #[tokio::test] async fn a_corrupt_state_file_leaves_the_instance_working_and_unlinked() { // One damaged file must never stop an instance from starting. diff --git a/crates/temps-cloud/Cargo.toml b/crates/temps-cloud/Cargo.toml new file mode 100644 index 000000000..41402cb4f --- /dev/null +++ b/crates/temps-cloud/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "temps-cloud" +version.workspace = true +edition.workspace = true +license.workspace = true +description = "Host integration for the optional Temps managed control plane." + +[dependencies] +temps-auth = { path = "../temps-auth" } +temps-cloud-client = { path = "../temps-cloud-client" } +temps-config = { path = "../temps-config" } +temps-core = { path = "../temps-core" } + +anyhow.workspace = true +axum.workspace = true +serde.workspace = true +serde_json.workspace = true +thiserror.workspace = true +tokio.workspace = true +tracing.workspace = true +utoipa.workspace = true +uuid.workspace = true + +[dev-dependencies] +tempfile.workspace = true diff --git a/crates/temps-cloud/src/handler.rs b/crates/temps-cloud/src/handler.rs new file mode 100644 index 000000000..86bd1126c --- /dev/null +++ b/crates/temps-cloud/src/handler.rs @@ -0,0 +1,173 @@ +use std::sync::Arc; + +use axum::{ + extract::{Extension, State}, + http::StatusCode, + routing::{delete, get, post}, + Json, Router, +}; +use serde::{Deserialize, Serialize}; +use temps_auth::{permission_guard, RequireAuth}; +use temps_core::{ + error_builder::ErrorBuilder, problemdetails::Problem, AuditContext, AuditLogger, + AuditOperation, RequestMetadata, +}; +use utoipa::{OpenApi, ToSchema}; + +use crate::{CloudCapability, CloudService, CloudServiceError, CloudStatus}; + +#[derive(Clone)] +pub struct CloudState { + service: Arc, + audit: Arc, +} + +#[derive(Debug, Deserialize, ToSchema)] +pub struct EnrollCloudRequest { + #[schema(min_length = 1, example = "ABCD-EFGH")] + pub enrollment_code: String, +} + +#[derive(Debug, Serialize)] +struct CloudLinkAudit { + context: AuditContext, + action: &'static str, +} + +impl AuditOperation for CloudLinkAudit { + fn operation_type(&self) -> String { + self.action.to_string() + } + fn user_id(&self) -> Option { + Some(self.context.user_id) + } + fn ip_address(&self) -> Option { + self.context.ip_address.clone() + } + fn user_agent(&self) -> &str { + &self.context.user_agent + } + fn serialize(&self) -> anyhow::Result { + serde_json::to_string(self).map_err(Into::into) + } +} + +fn problem(error: CloudServiceError) -> Problem { + let status = match &error { + CloudServiceError::Client(temps_cloud_client::CloudError::EnrollmentRefused { .. }) => { + StatusCode::UNPROCESSABLE_ENTITY + } + CloudServiceError::Client(temps_cloud_client::CloudError::Unreachable { .. }) => { + StatusCode::SERVICE_UNAVAILABLE + } + CloudServiceError::Client(temps_cloud_client::CloudError::CredentialRejected) => { + StatusCode::UNAUTHORIZED + } + CloudServiceError::Client(temps_cloud_client::CloudError::NotEnrolled) => { + StatusCode::CONFLICT + } + CloudServiceError::Client( + temps_cloud_client::CloudError::Rejected { .. } + | temps_cloud_client::CloudError::InvalidAcknowledgement { .. }, + ) => StatusCode::BAD_GATEWAY, + CloudServiceError::Configuration(_) + | CloudServiceError::InvalidBackend { .. } + | CloudServiceError::State(_) + | CloudServiceError::Client( + temps_cloud_client::CloudError::InvalidBackendUrl { .. } + | temps_cloud_client::CloudError::ClientConfiguration { .. }, + ) => StatusCode::INTERNAL_SERVER_ERROR, + }; + ErrorBuilder::new(status) + .type_("https://temps.sh/probs/cloud-link") + .title("Managed control plane error") + .detail(error.to_string()) + .build() +} + +#[utoipa::path(get, path = "/cloud/capability", tag = "Cloud", responses((status = 200, body = CloudCapability)), security(("bearer_auth" = [])))] +async fn get_cloud_capability( + RequireAuth(auth): RequireAuth, + State(state): State, +) -> Result, Problem> { + permission_guard!(auth, SettingsRead); + Ok(Json(state.service.capability().await)) +} + +#[utoipa::path(get, path = "/cloud/status", tag = "Cloud", responses((status = 200, body = CloudStatus)), security(("bearer_auth" = [])))] +async fn get_cloud_status( + RequireAuth(auth): RequireAuth, + State(state): State, +) -> Result, Problem> { + permission_guard!(auth, SettingsRead); + state.service.status().await.map(Json).map_err(problem) +} + +#[utoipa::path(post, path = "/cloud/enroll", tag = "Cloud", request_body = EnrollCloudRequest, responses((status = 200, body = CloudStatus)), security(("bearer_auth" = [])))] +async fn enroll_cloud( + RequireAuth(auth): RequireAuth, + State(state): State, + Extension(metadata): Extension, + Json(request): Json, +) -> Result, Problem> { + permission_guard!(auth, SettingsWrite); + if request.enrollment_code.trim().is_empty() { + return Err(ErrorBuilder::new(StatusCode::BAD_REQUEST) + .detail("Enrollment code cannot be empty") + .build()); + } + let result = state + .service + .enroll(&request.enrollment_code) + .await + .map_err(problem)?; + audit(&state, &auth, &metadata, "CLOUD_LINK_CONNECTED").await; + Ok(Json(result)) +} + +#[utoipa::path(delete, path = "/cloud", tag = "Cloud", responses((status = 200, body = CloudStatus)), security(("bearer_auth" = [])))] +async fn disconnect_cloud( + RequireAuth(auth): RequireAuth, + State(state): State, + Extension(metadata): Extension, +) -> Result, Problem> { + permission_guard!(auth, SettingsWrite); + let result = state.service.disconnect().await.map_err(problem)?; + audit(&state, &auth, &metadata, "CLOUD_LINK_DISCONNECTED").await; + Ok(Json(result)) +} + +async fn audit( + state: &CloudState, + auth: &temps_auth::AuthContext, + metadata: &RequestMetadata, + action: &'static str, +) { + let event = CloudLinkAudit { + context: AuditContext { + user_id: auth.user_id(), + ip_address: Some(metadata.ip_address.clone()), + user_agent: metadata.user_agent.clone(), + }, + action, + }; + if let Err(error) = state.audit.create_audit_log(&event).await { + tracing::error!(%error, action, "failed to record managed control-plane audit event"); + } +} + +pub fn cloud_routes(service: Arc, audit: Arc) -> Router { + Router::new() + .route("/cloud/capability", get(get_cloud_capability)) + .route("/cloud/status", get(get_cloud_status)) + .route("/cloud/enroll", post(enroll_cloud)) + .route("/cloud", delete(disconnect_cloud)) + .with_state(CloudState { service, audit }) +} + +#[derive(OpenApi)] +#[openapi( + paths(get_cloud_capability, get_cloud_status, enroll_cloud, disconnect_cloud), + components(schemas(CloudCapability, CloudStatus, EnrollCloudRequest)) +)] +pub struct CloudApiDoc; diff --git a/crates/temps-cloud/src/lib.rs b/crates/temps-cloud/src/lib.rs new file mode 100644 index 000000000..be75fa975 --- /dev/null +++ b/crates/temps-cloud/src/lib.rs @@ -0,0 +1,11 @@ +//! Optional managed-control-plane integration for a self-hosted Temps instance. + +#![forbid(unsafe_code)] + +mod handler; +mod plugin; +mod service; + +pub use handler::{cloud_routes, CloudApiDoc}; +pub use plugin::CloudPlugin; +pub use service::{CloudCapability, CloudService, CloudServiceError, CloudStatus}; diff --git a/crates/temps-cloud/src/plugin.rs b/crates/temps-cloud/src/plugin.rs new file mode 100644 index 000000000..cf5b8c044 --- /dev/null +++ b/crates/temps-cloud/src/plugin.rs @@ -0,0 +1,86 @@ +use std::{future::Future, path::PathBuf, pin::Pin, sync::Arc}; + +use temps_cloud_client::CloudLink; +use temps_config::ConfigService; +use temps_core::plugin::{ + PluginContext, PluginError, PluginRoutes, ServiceRegistrationContext, TempsPlugin, +}; +use utoipa::{openapi::OpenApi, OpenApi as _}; + +use crate::{cloud_routes, CloudApiDoc, CloudService}; + +pub struct CloudPlugin { + data_dir: PathBuf, + agent_version: String, + allow_loopback_development: bool, +} + +impl CloudPlugin { + pub fn new(data_dir: PathBuf, agent_version: impl Into) -> Self { + let allow_loopback_development = std::env::var("TEMPS_CLOUD_ALLOW_LOOPBACK") + .is_ok_and(|value| matches!(value.as_str(), "1" | "true" | "TRUE")); + Self { + data_dir, + agent_version: agent_version.into(), + allow_loopback_development, + } + } +} + +impl TempsPlugin for CloudPlugin { + fn name(&self) -> &'static str { + "cloud" + } + + fn register_services<'a>( + &'a self, + context: &'a ServiceRegistrationContext, + ) -> Pin> + Send + 'a>> { + Box::pin(async move { + let config = context.require_service::(); + let link = if self.allow_loopback_development { + Arc::new(CloudLink::load_for_loopback_development( + self.data_dir.clone(), + self.agent_version.clone(), + )) + } else { + Arc::new(CloudLink::load( + self.data_dir.clone(), + self.agent_version.clone(), + )) + }; + let service = Arc::new(CloudService::new( + link.clone(), + config, + self.allow_loopback_development, + )); + context.register_service(link); + context.register_service(service); + Ok(()) + }) + } + + fn initialize_plugin_services<'a>( + &'a self, + context: &'a PluginContext, + ) -> Pin> + Send + 'a>> { + Box::pin(async move { + context + .require_service::() + .initialize() + .await + .map_err(|error| PluginError::InitializationFailed(error.to_string())) + }) + } + + fn configure_routes(&self, context: &PluginContext) -> Option { + Some(PluginRoutes::new(cloud_routes( + context.require_service::(), + context.require_service::(), + ))) + } + + fn openapi_schema(&self) -> Option { + Some(CloudApiDoc::openapi()) + } +} diff --git a/crates/temps-cloud/src/service.rs b/crates/temps-cloud/src/service.rs new file mode 100644 index 000000000..8d3162d6c --- /dev/null +++ b/crates/temps-cloud/src/service.rs @@ -0,0 +1,233 @@ +use std::sync::{Arc, Mutex}; + +use serde::Serialize; +use temps_cloud_client::{BackendUrl, CloudError, CloudLink}; +use temps_config::{ConfigService, ConfigServiceError}; +use thiserror::Error; +use tokio::sync::watch; +use utoipa::ToSchema; +use uuid::Uuid; + +const SETUP_PATH: &str = "/settings/cloud"; + +#[derive(Debug, Error)] +pub enum CloudServiceError { + #[error("Could not read managed-control-plane settings: {0}")] + Configuration(#[from] ConfigServiceError), + #[error("Managed-control-plane URL is invalid: {reason}")] + InvalidBackend { reason: String }, + #[error("Managed-control-plane operation failed: {0}")] + Client(CloudError), + #[error("Could not persist the managed-control-plane link: {0}")] + State(temps_cloud_client::state::StateError), +} + +#[derive(Debug, Clone, Serialize, ToSchema)] +pub struct CloudCapability { + pub configured: bool, + pub reason: Option, + pub setup_path: String, +} + +#[derive(Debug, Clone, Serialize, ToSchema)] +pub struct CloudStatus { + pub status: String, + pub status_message: String, + pub health: String, + pub health_message: String, + #[schema(value_type = Option)] + pub instance_id: Option, + pub spooled_spans: usize, + pub backend_url: String, +} + +pub struct CloudService { + link: Arc, + config: Arc, + cancel: watch::Sender, + task: Mutex>>, + allow_loopback_development: bool, +} + +impl CloudService { + pub fn new( + link: Arc, + config: Arc, + allow_loopback_development: bool, + ) -> Self { + let (cancel, _) = watch::channel(false); + Self { + link, + config, + cancel, + task: Mutex::new(None), + allow_loopback_development, + } + } + + pub fn link(&self) -> Arc { + self.link.clone() + } + + pub async fn initialize(&self) -> Result<(), CloudServiceError> { + let settings = self.config.get_settings().await?; + let backend = parse_backend(&settings.cloud.backend_url, self.allow_loopback_development) + .map_err(|error| CloudServiceError::InvalidBackend { + reason: error.to_string(), + })?; + self.link + .configure(backend) + .map_err(CloudServiceError::State)?; + + let mut task = self + .task + .lock() + .unwrap_or_else(|poisoned| poisoned.into_inner()); + if task.is_none() { + let link = self.link.clone(); + let cancel = self.cancel.subscribe(); + *task = Some(tokio::spawn(async move { + temps_cloud_client::flusher::run(link, cancel).await; + })); + } + Ok(()) + } + + pub async fn capability(&self) -> CloudCapability { + match self.config.get_settings().await { + Ok(settings) => { + match parse_backend(&settings.cloud.backend_url, self.allow_loopback_development) { + Ok(_) => CloudCapability { + configured: true, + reason: None, + setup_path: SETUP_PATH.to_string(), + }, + Err(error) => CloudCapability { + configured: false, + reason: Some(error.to_string()), + setup_path: SETUP_PATH.to_string(), + }, + } + } + Err(error) => CloudCapability { + configured: false, + reason: Some(format!("Could not load settings: {error}")), + setup_path: SETUP_PATH.to_string(), + }, + } + } + + pub async fn status(&self) -> Result { + let settings = self.config.get_settings().await?; + let status = self.link.status(); + let health = self.link.health(); + Ok(CloudStatus { + status: status_name(&status).to_string(), + status_message: status.message(), + health: health_name(&health).to_string(), + health_message: health.message(), + instance_id: self.link.instance_id(), + spooled_spans: self.link.spooled(), + backend_url: settings.cloud.backend_url, + }) + } + + pub async fn enroll(&self, code: &str) -> Result { + let settings = self.config.get_settings().await?; + let backend = parse_backend(&settings.cloud.backend_url, self.allow_loopback_development) + .map_err(|error| CloudServiceError::InvalidBackend { + reason: error.to_string(), + })?; + self.link + .configure(backend) + .map_err(CloudServiceError::State)?; + self.link + .enroll(code) + .await + .map_err(CloudServiceError::Client)?; + self.status().await + } + + pub async fn disconnect(&self) -> Result { + match self.link.revoke().await { + Ok(()) | Err(CloudError::CredentialRejected) => {} + Err(error) => return Err(CloudServiceError::Client(error)), + } + self.link.disconnect().map_err(CloudServiceError::State)?; + self.status().await + } + + pub async fn shutdown(&self) { + let _ = self.cancel.send(true); + let task = self + .task + .lock() + .unwrap_or_else(|poisoned| poisoned.into_inner()) + .take(); + if let Some(task) = task { + if let Err(error) = task.await { + tracing::warn!(%error, "managed telemetry mirror task did not shut down cleanly"); + } + } + } +} + +fn parse_backend(value: &str, allow_loopback_development: bool) -> Result { + if allow_loopback_development { + BackendUrl::loopback_development(value) + } else { + BackendUrl::production(value) + } +} + +fn status_name(status: &temps_cloud_client::LinkStatus) -> &'static str { + match status { + temps_cloud_client::LinkStatus::NotConfigured => "not_configured", + temps_cloud_client::LinkStatus::AwaitingEnrollment { .. } => "awaiting_enrollment", + temps_cloud_client::LinkStatus::Linked { .. } => "linked", + temps_cloud_client::LinkStatus::CredentialRejected { .. } => "credential_rejected", + } +} + +fn health_name(health: &temps_cloud_client::MirrorHealth) -> &'static str { + match health { + temps_cloud_client::MirrorHealth::Healthy => "healthy", + temps_cloud_client::MirrorHealth::Buffering { .. } => "buffering", + temps_cloud_client::MirrorHealth::Dropping { .. } => "dropping", + temps_cloud_client::MirrorHealth::Degraded { .. } => "degraded", + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn production_cloud_configuration_rejects_plain_http() { + assert!(parse_backend("http://cloud.example.com", false).is_err()); + assert!(parse_backend("http://cloud.example.com", true).is_err()); + } + + #[test] + fn loopback_http_requires_the_explicit_development_gate() { + assert!(parse_backend("http://127.0.0.1:19200", false).is_err()); + assert!(parse_backend("http://127.0.0.1:19200", true).is_ok()); + } + + #[test] + fn status_names_are_stable_api_values() { + assert_eq!( + status_name(&temps_cloud_client::LinkStatus::Linked { + base_url: "https://cloud.test".to_string(), + }), + "linked" + ); + assert_eq!( + health_name(&temps_cloud_client::MirrorHealth::Buffering { + spooled: 1, + reason: "offline".to_string(), + }), + "buffering" + ); + } +} diff --git a/crates/temps-core/src/app_settings.rs b/crates/temps-core/src/app_settings.rs index 140787d2f..64dc284a3 100644 --- a/crates/temps-core/src/app_settings.rs +++ b/crates/temps-core/src/app_settings.rs @@ -23,6 +23,10 @@ pub struct AppSettings { /// disables DNS record sync regardless of per-domain opt-in. pub edge_target: Option, + /// Managed control-plane connection. Credentials are deliberately not + /// stored here; they live in the owner-only cloud-link state file. + pub cloud: CloudSettings, + // Screenshot settings pub screenshots: ScreenshotSettings, @@ -135,6 +139,22 @@ pub struct AppSettings { pub console_version: Option, } +/// Non-secret managed control-plane settings stored with application settings. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)] +#[serde(default)] +pub struct CloudSettings { + /// HTTPS origin used for enrollment and telemetry mirroring. + pub backend_url: String, +} + +impl Default for CloudSettings { + fn default() -> Self { + Self { + backend_url: "https://app.temps.sh".to_string(), + } + } +} + /// Cluster-DNS resolver settings (ADR-024, experimental beta). /// /// When `enabled`, the Temps control plane starts a Hickory DNS resolver and @@ -883,6 +903,7 @@ impl Default for AppSettings { internal_url: None, preview_domain: DEFAULT_LOCAL_DOMAIN.to_string(), edge_target: None, + cloud: CloudSettings::default(), screenshots: ScreenshotSettings::default(), letsencrypt: LetsEncryptSettings::default(), dns_provider: DnsProviderSettings::default(), diff --git a/crates/temps-otel/Cargo.toml b/crates/temps-otel/Cargo.toml index 1699524d7..892914fff 100644 --- a/crates/temps-otel/Cargo.toml +++ b/crates/temps-otel/Cargo.toml @@ -18,6 +18,8 @@ temps-deployer = { path = "../temps-deployer" } temps-auth = { path = "../temps-auth" } temps-metrics = { path = "../temps-metrics" } temps-monitoring = { path = "../temps-monitoring" } +temps-cloud-client = { path = "../temps-cloud-client" } +temps-cloud-protocol = { path = "../temps-cloud-protocol" } # Async runtime tokio = { workspace = true } @@ -91,3 +93,4 @@ anyhow = { workspace = true } # `http_wait_plain` enables the HTTP /ping readiness wait — the clickhouse-server # image never logs "Ready for connections" to stdout/stderr, only to its log file. testcontainers = { workspace = true, features = ["http_wait_plain"] } +tempfile.workspace = true diff --git a/crates/temps-otel/src/plugin.rs b/crates/temps-otel/src/plugin.rs index 1d6c96f79..fc6e31408 100644 --- a/crates/temps-otel/src/plugin.rs +++ b/crates/temps-otel/src/plugin.rs @@ -476,12 +476,15 @@ impl TempsPlugin for OtelPlugin { )); // Create the main OTel service - let otel_service = Arc::new(OtelService::new( - storage.clone(), - auth_service, - rate_limiter, - config.max_concurrent_ingest_requests, - )); + let otel_service = Arc::new( + OtelService::new( + storage.clone(), + auth_service, + rate_limiter, + config.max_concurrent_ingest_requests, + ) + .with_cloud_link(context.require_service::()), + ); context.register_service(otel_service.clone()); // Also expose the same service behind the storage-agnostic read // contract so read-only consumers (e.g. the AI debugging chat in diff --git a/crates/temps-otel/src/services/otel_service.rs b/crates/temps-otel/src/services/otel_service.rs index ec03ead90..4a6869b7b 100644 --- a/crates/temps-otel/src/services/otel_service.rs +++ b/crates/temps-otel/src/services/otel_service.rs @@ -41,6 +41,7 @@ pub struct OtelService { /// [`DEFAULT_MAX_CONCURRENT_INGEST_REQUESTS`] when overridden via /// `TEMPS_OTEL_MAX_CONCURRENT_INGEST_REQUESTS`). ingest_permit_limit: usize, + cloud_link: Option>, stats: PipelineStatsAtomic, } @@ -62,6 +63,23 @@ const SERVICE_INGEST_MAX_REQUESTS: u32 = 600; /// Sliding window for the service ingest limiter. const SERVICE_INGEST_WINDOW: Duration = Duration::from_secs(60); +fn cloud_span(span: &SpanRecord) -> temps_cloud_protocol::SpanRecord { + temps_cloud_protocol::SpanRecord { + trace_id: span.trace_id.clone(), + span_id: span.span_id.clone(), + // Span names are application-controlled too. Instrumentation may put + // raw URLs, SQL, email addresses or identifiers here, so the safe + // continuous projection uses a neutral operation label. + name: "span".to_string(), + ts_millis: span.start_time.timestamp_millis(), + duration_ms: span.duration_ms, + // Default-deny at the OSS boundary. Arbitrary span attributes + // routinely contain headers, SQL, user identifiers and other + // application data. + attributes: Default::default(), + } +} + /// Atomic counters for pipeline observability. struct PipelineStatsAtomic { metrics_received: AtomicU64, @@ -113,10 +131,18 @@ impl OtelService { quota_cache: Arc::new(QuotaCache::new(QUOTA_CACHE_TTL)), ingest_semaphore: Arc::new(Semaphore::new(max_concurrent_ingest_requests)), ingest_permit_limit: max_concurrent_ingest_requests, + cloud_link: None, stats: PipelineStatsAtomic::default(), } } + /// Attach the optional managed telemetry mirror. The mirror is offered + /// spans only after local durable storage succeeds. + pub fn with_cloud_link(mut self, cloud_link: Arc) -> Self { + self.cloud_link = Some(cloud_link); + self + } + /// Acquire an ingest slot without queueing more work in memory. pub fn try_acquire_ingest_permit(&self) -> Result { self.ingest_semaphore @@ -246,9 +272,17 @@ impl OtelService { return Ok(0); } + let mirror = self.cloud_link.as_ref().and_then(|link| { + link.is_linked() + .then(|| spans.iter().map(cloud_span).collect::>()) + }); + match self.storage.store_spans(spans).await { Ok(stored) => { self.stats.spans_stored.fetch_add(stored, Ordering::Relaxed); + if let (Some(link), Some(mirror)) = (&self.cloud_link, mirror) { + link.record(mirror); + } Ok(stored) } Err(e) => { @@ -484,6 +518,24 @@ mod tests { use crate::test_support::{self, MockOtelStorage}; use std::time::Duration; + fn linked_cloud() -> (tempfile::TempDir, Arc) { + let directory = tempfile::tempdir().unwrap(); + let state_path = directory.path().join("cloud-link/state.json"); + temps_cloud_client::EnrollmentState { + instance_id: uuid::Uuid::new_v4(), + base_url: "https://cloud.test/".to_string(), + token: Some("instance-token".to_string()), + tenant_id: Some(uuid::Uuid::new_v4()), + } + .save(&state_path) + .unwrap(); + let link = Arc::new(temps_cloud_client::CloudLink::load( + directory.path().to_path_buf(), + "test", + )); + (directory, link) + } + fn make_service(storage: MockOtelStorage) -> (OtelService, MockOtelStorage) { let storage_clone = storage.clone(); let db = Arc::new(sea_orm::DatabaseConnection::Disconnected); @@ -523,6 +575,41 @@ mod tests { assert_eq!(stats.spans_stored, 4); } + #[tokio::test] + async fn successful_local_ingest_offers_spans_to_the_cloud_mirror() { + let mock = MockOtelStorage::new(); + let (svc, _) = make_service(mock); + let (_directory, link) = linked_cloud(); + let svc = svc.with_cloud_link(link.clone()); + let (_, encoded) = test_support::build_sample_trace_tree(); + let spans = decode::decode_traces_request(&encoded, 1, None).unwrap(); + + svc.ingest_spans(spans).await.unwrap(); + + assert_eq!(link.spooled(), 4); + } + + #[test] + fn cloud_mirror_strips_application_controlled_names_and_attributes() { + let (_, encoded) = test_support::build_sample_trace_tree(); + let mut spans = decode::decode_traces_request(&encoded, 1, None).unwrap(); + spans[0].attributes.insert( + "http.request.header.authorization".into(), + "Bearer must-not-leave".into(), + ); + spans[0].name = "SELECT * FROM users WHERE email='secret@example.com'".into(); + + let mirrored = cloud_span(&spans[0]); + + assert!(mirrored.attributes.is_empty()); + assert_eq!(mirrored.trace_id, spans[0].trace_id); + assert_eq!(mirrored.span_id, spans[0].span_id); + assert_eq!(mirrored.name, "span"); + let serialized = serde_json::to_string(&mirrored).unwrap(); + assert!(!serialized.contains("secret@example.com")); + assert!(!serialized.contains("must-not-leave")); + } + #[tokio::test] async fn test_ingest_spans_error_span_stored() { let mock = MockOtelStorage::new(); @@ -585,6 +672,21 @@ mod tests { assert!(stats.spans_dropped > 0 || stats.ingest_errors > 0); } + #[tokio::test] + async fn failed_local_ingest_never_offers_spans_to_the_cloud_mirror() { + let mock = MockOtelStorage::new(); + *mock.fail_store_spans.lock().unwrap() = Some("disk full".into()); + let (svc, _) = make_service(mock); + let (_directory, link) = linked_cloud(); + let svc = svc.with_cloud_link(link.clone()); + let (_, encoded) = test_support::build_sample_trace_tree(); + let spans = decode::decode_traces_request(&encoded, 1, None).unwrap(); + + assert!(svc.ingest_spans(spans).await.is_err()); + + assert_eq!(link.spooled(), 0, "local storage must succeed first"); + } + #[tokio::test] async fn test_ingest_and_query_trace_tree_roundtrip() { let mock = MockOtelStorage::new(); diff --git a/web/e2e/authenticated/ai-cloud-entry.spec.ts b/web/e2e/authenticated/ai-cloud-entry.spec.ts new file mode 100644 index 000000000..ab8dc1fec --- /dev/null +++ b/web/e2e/authenticated/ai-cloud-entry.spec.ts @@ -0,0 +1,94 @@ +import type { Page } from '@playwright/test' +import { expect, expectAppMounted, test } from '../fixtures' + +const routeProviders = async (page: Page, body: unknown[]) => { + await page.route('**/ai/providers', async (route) => { + await route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify(body), + }) + }) +} + +test.describe('AI entry and Cloud onboarding', () => { + test('keeps AI discoverable and routes both setup choices', async ({ + page, + consoleErrors, + }) => { + await routeProviders(page, []) + await page.goto('/projects') + await expectAppMounted(page) + + const entry = page.getByRole('button', { + name: 'AI assistant', + exact: true, + }) + await expect(entry).toBeVisible() + await expect(entry).toHaveAttribute('aria-expanded', 'false') + + await entry.click() + await expect(entry).toHaveAttribute('aria-expanded', 'true') + await expect( + page.getByRole('heading', { + name: 'Ask your stack. Keep the evidence attached.', + }) + ).toBeVisible() + await expect(page.getByText('250 AI credits included monthly')).toBeVisible() + await expect(page.getByText('Cited, read-only answers')).toBeVisible() + + await page.getByRole('link', { name: 'Connect Temps Cloud' }).click() + await expect(page).toHaveURL(/\/settings\/cloud(?:[?#]|$)/) + await expect( + page.getByRole('heading', { name: 'Temps Cloud', exact: true }) + ).toBeVisible() + await expect(entry).toHaveAttribute('aria-expanded', 'false') + + await page.goto('/projects') + await entry.click() + await page.getByRole('link', { name: 'Use my own AI provider' }).click() + await expect(page).toHaveURL(/\/settings\/ai-providers(?:[?#]|$)/) + await expect( + page.getByRole('heading', { name: /AI Providers/i }) + ).toBeVisible() + + expect(consoleErrors).toEqual([]) + }) + + test('opens the existing assistant when a local provider is configured', async ({ + page, + consoleErrors, + }) => { + await routeProviders(page, [ + { + api_key_masked: 'sk-…test', + base_url: null, + created_at: '2026-08-05T00:00:00Z', + default_model: 'claude-sonnet-4-5', + display_name: 'Anthropic', + id: 1, + is_active: true, + provider: 'anthropic', + updated_at: '2026-08-05T00:00:00Z', + }, + ]) + await page.goto('/projects') + await expectAppMounted(page) + + const entry = page.getByRole('button', { + name: 'AI assistant', + exact: true, + }) + await entry.click() + + await expect( + page.getByRole('heading', { name: 'AI assistant', exact: true }) + ).toBeVisible() + await expect( + page.getByRole('heading', { + name: 'Ask your stack. Keep the evidence attached.', + }) + ).not.toBeVisible() + expect(consoleErrors).toEqual([]) + }) +}) diff --git a/web/e2e/authenticated/cloud-onboarding.spec.ts b/web/e2e/authenticated/cloud-onboarding.spec.ts new file mode 100644 index 000000000..08578a0c3 --- /dev/null +++ b/web/e2e/authenticated/cloud-onboarding.spec.ts @@ -0,0 +1,97 @@ +import type { Page } from '@playwright/test' +import { expect, expectAppMounted, test } from '../fixtures' + +const cloudStatus = (linked: boolean) => ({ + backend_url: 'http://localhost:19200', + health: linked ? 'healthy' : 'disconnected', + health_message: linked ? 'Signals are reaching Temps Cloud' : 'Not linked', + instance_id: linked ? 'instance-e2e-1234' : null, + spooled_spans: 0, + status: linked ? 'linked' : 'disconnected', + status_message: linked + ? 'This instance is reporting to Temps Cloud' + : 'Connect this instance to begin reporting', +}) + +const routeCloudLifecycle = async (page: Page) => { + let linked = false + const enrollmentCodes: string[] = [] + + await page.route('**/cloud/capability', async (route) => { + await route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ + configured: true, + reason: null, + setup_path: '/settings/cloud', + }), + }) + }) + await page.route('**/cloud/status', async (route) => { + await route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify(cloudStatus(linked)), + }) + }) + await page.route('**/cloud/enroll', async (route) => { + enrollmentCodes.push(route.request().postDataJSON().enrollment_code) + linked = true + await route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify(cloudStatus(true)), + }) + }) + await page.route('**/cloud', async (route) => { + if (route.request().method() !== 'DELETE') { + await route.fallback() + return + } + linked = false + await route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify(cloudStatus(false)), + }) + }) + + return { enrollmentCodes } +} + +test.describe('Temps Cloud activation onboarding', () => { + test('connects and disconnects an instance from the two-step setup', async ({ + page, + consoleErrors, + }) => { + const cloud = await routeCloudLifecycle(page) + await page.goto('/settings/cloud') + await expectAppMounted(page) + + await expect( + page.getByRole('heading', { name: 'Connect this instance' }) + ).toBeVisible() + await expect(page.getByRole('link', { name: 'Get a code' })).toHaveAttribute( + 'href', + 'http://localhost:19200' + ) + await page.getByLabel('1. Paste enrollment code').fill('ABCD-EFGH') + await page.getByRole('button', { name: '2. Connect' }).click() + + await expect(page.getByRole('heading', { name: 'Connected' })).toBeVisible() + await expect(page.getByText('instance-e2')).toBeVisible() + expect(cloud.enrollmentCodes).toEqual(['ABCD-EFGH']) + + await page.getByRole('button', { name: 'Disconnect' }).click() + await expect( + page.getByRole('heading', { name: 'Connect this instance' }) + ).toBeVisible() + + await page.getByLabel('1. Paste enrollment code').fill('WXYZ-IJKL') + await page.getByRole('button', { name: '2. Connect' }).click() + await expect(page.getByRole('heading', { name: 'Connected' })).toBeVisible() + expect(cloud.enrollmentCodes).toEqual(['ABCD-EFGH', 'WXYZ-IJKL']) + expect(consoleErrors).toEqual([]) + }) +}) diff --git a/web/src/App.tsx b/web/src/App.tsx index e9bd48ca4..042bc0881 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -257,6 +257,11 @@ const DockerRegistryPage = lazy(() => default: m.DockerRegistryPage, })) ) +const CloudSettingsPage = lazy(() => + import('./pages/settings/CloudSettingsPage').then((m) => ({ + default: m.CloudSettingsPage, + })) +) const SecurityPage = lazy(() => import('./pages/settings/SecurityPage').then((m) => ({ default: m.SecurityPage, @@ -545,7 +550,8 @@ const FullAppRoutes = () => { } /> } /> } /> - } /> + } /> + } /> } /> } /> } /> diff --git a/web/src/api/client/@tanstack/react-query.gen.ts b/web/src/api/client/@tanstack/react-query.gen.ts index 487105279..d73f233ef 100644 --- a/web/src/api/client/@tanstack/react-query.gen.ts +++ b/web/src/api/client/@tanstack/react-query.gen.ts @@ -3,8 +3,8 @@ import { type DefaultError, type InfiniteData, infiniteQueryOptions, queryOptions, type UseMutationOptions } from '@tanstack/react-query'; import { client } from '../client.gen'; -import { acknowledgeAlarm, activateAiProvider, activateApiKey, activateConnection, activateProvider, addClusterMember, addContext, addEnvironmentDomain, addEvents, addManagedDomain, addSessionReplayEvents, addTeamMember, adminDrainNode, adminDrainStatus, adminGetNode, adminListNodeContainers, adminListNodes, adminRemoveNode, adminUndrainNode, applyHostnameMode, archiveConversation, archiveFlag, assignRole, attachScheduleServices, blobCopy, blobDelete, blobDisable, blobDownload, blobEnable, blobList, blobPut, blobStatus, blobUpdate, cancel, cancelBackup, cancelDeployment, cancelDomainOrder, cancelPgUpgrade, cancelRun, cancelScheduleRun, changePasswordSelf, changeProjectSource, chatCompletions, checkAnalyticsHasEvents, checkCommitExists, checkDomainStatus, checkExplorerSupport, checkIpBlocked, checkProviderDeletionSafety, chunkUploadOptions, cleanupExpiredBackups, clearPreviewPassword, cliDeviceApprove, cliDeviceDeny, cliDeviceLookup, cliDevicePoll, cliDeviceStart, cliLogout, cmd, cmdKill, cmdLogs, confirmPendingAction, containerMetricsGetHistory, createAgent, createAlert, createAlertRule, createApiKey, createBackupSchedule, createBitbucketProvider, createCloudflareProvider, createConversation, createCustomDomain, createDashboard, createDeploymentToken, createDnsProvider, createDomain, createDsn, createEmailDomain, createEmailProvider, createEnvironment, createEnvironmentVariable, createFlag, createFunnel, createGenericProvider, createGiteaPatProvider, createGithubPatProvider, createGitlabOauthProvider, createGitlabPatProvider, createGitProvider, createGlobalMcp, createGlobalSkill, createIncident, createIpAccessControl, createMcp, createMonitor, createNotificationEmailProvider, createNotificationProvider, createOidcProvider, createOidcRoleMapping, createOrRecreateOrder, createPlan, createPr, createProject, createProjectFromTemplate, createProjectRelease, createProjectSecret, createProviderKey, createRelease, createRoute, createS3Source, createSandbox, createService, createSkill, createSlackProvider, createTeam, createUser, createWebhook, createWebhookProvider, deactivateApiKey, deactivateConnection, deactivateProvider, deleteAgent, deleteAlert, deleteAlertRule, deleteApiKey, deleteBackup, deleteBackupSchedule, deleteConnection, deleteCustomDomain, deleteDashboard, deleteDeploymentToken, deleteDnsProvider, deleteDomain, deleteEmailDomain, deleteEmailProvider, deleteEnvironment, deleteEnvironmentDomain, deleteEnvironmentVariable, deleteExternalImage, deleteFunnel, deleteGitProvider, deleteGlobalMcp, deleteGlobalSkill, deleteIpAccessControl, deleteMcp, deleteMonitor, deleteNotificationProvider, deleteOidcProvider, deleteOidcRoleMapping, deletePreferences, deleteProject, deleteProjectSecret, deleteProviderKey, deleteProviderSafely, deleteReleaseSourceFiles, deleteReleaseSourceMaps, deleteRoute, deleteS3Source, deleteScan, deleteSecret, deleteService, deleteSessionReplay, deleteSkill, deleteSourceMap, deleteStaticBundle, deleteTeam, deleteUser, deleteWebhook, deployFromImage, deployFromImageUpload, deployFromStatic, deployFromUploadedSource, deploymentMetricsGetLatest, deploymentMetricsGetRange, deploymentMetricsToggle, destroySandbox, detachScheduleService, detectPublicPresets, disableBackupSchedule, disableMfa, discoverWorkloads, domain, downloadGlobalSkillArchive, downloadObject, downloadSkillArchive, emailStatus, embeddings, enableBackupSchedule, enrichVisitor, exec, execDetached, executeDeploymentOperation, executeImport, extendTimeout, externalServiceEnablePgStatStatements, externalServiceMetricsByDatabase, externalServiceMetricsCreateAlertRule, externalServiceMetricsDeleteAlertRule, externalServiceMetricsGetAlertRules, externalServiceMetricsGetLatest, externalServiceMetricsGetRange, externalServiceMetricsStatus, externalServiceMetricsToggle, externalServiceMetricsUpdateAlertRule, externalServiceResetPgStatStatements, finalizeOrder, finalizeProjectRelease, findConversation, generateJoinToken, generatePresetDockerfile, getAccessInfo, getActiveVisitors, getActivityGraph, getAdminGate, getAgent, getAggregatedBuckets, getAiAgentBreakdown, getAiAgentPages, getAiAgentTimeline, getAiPageBreakdown, getAiStatusBreakdown, getAlert, getAlertRule, getAllRepositoriesByName, getAnalyticsActiveVisitors, getAnalyticsEventsCount, getAnalyticsSessionEvents, getAnalyticsVisitorSessions, getApiKey, getApiKeyPermissions, getAuditLog, getBackup, getBackupSchedule, getBranchesByRepositoryId, getBucketedIncidents, getBucketedStatus, getChallengeToken, getChatReadiness, getCliStatus, getClusterHealth, getClusterMember, getCmd, getContainerDetail, getContainerEnvironmentVariable, getContainerInfo, getContainerLogs, getContainerLogsById, getContainerMetrics, getConversation, getConversationDetail, getConversations, getCronById, getCronExecutions, getCrossProjectTraceSiblings, getCurrentMonitorStatus, getCurrentUser, getCustomDomain, getDashboard, getDashboardProjectsAnalytics, getDelivery, getDeployment, getDeploymentContainerLogContent, getDeploymentJobLogs, getDeploymentJobs, getDeploymentOperations, getDeploymentOperationStatus, getDeploymentToken, getDiskStatus, getDnsChanges, getDnsProvider, getDomain, getDomainByHost, getDomainById, getDomainByName, getDomainDnsRecords, getDomainOrder, getEmail, getEmailEvents, getEmailLinks, getEmailProvider, getEmailStats, getEmailTracking, getEmailTrackingStatus, getEntityInfo, getEnvironment, getEnvironmentCrons, getEnvironmentDomains, getEnvironments, getEnvironmentVariables, getEnvironmentVariableValue, getErrorDashboardStats, getErrorEvent, getErrorGroup, getErrorStats, getErrorTimeSeries, getEventDetail, getEventEntries, getEventsCount, getEventsTimeline, getEventTypeBreakdown, getEventVisitors, getExternalImage, getFile, getFlag, getFlagSnapshot, getFunnelMetrics, getGenaiTrace, getGeneralStats, getGitProvider, getGlobalEvents, getGlobalEventStats, getGlobalMcp, getGlobalSandboxStatus, getGlobalSkill, getGroupedPageMetrics, getHealth, getHourlyVisits, getHttpChallengeDebug, getImportStatus, getIncident, getIncidentUpdates, getIpAccessControl, getIpGeolocation, getJoinTokenStatus, getLastDeployment, getLatestScan, getLatestScansPerEnvironment, getLiveVisitorsList, getLogContext, getMcp, getMetricsOverTime, getMonitor, getNotificationProvider, getOnDemandCertStatus, getOrCreateDsn, getPageFlow, getPageHourlySessions, getPagePathDetail, getPagePaths, getPagePathsSparklines, getPagePathVisitors, getPendingAction, getPerformanceMetrics, getPgUpgrade, getPgUpgradeLogs, getPipelineStats, getPlatformInfo, getPostgresWalHealth, getPreferences, getPreviewGatewayLogs, getPreviewGatewaySettings, getPreviewGatewayStatus, getPricing, getPrivateIp, getProject, getProjectAlarmsSummary, getProjectBySlug, getProjectDeployments, getProjects, getProjectServiceEnvironmentVariables, getProjectSessionReplays, getProjectsHealth, getProjectsMonitorHealth, getProjectStatistics, getProjectTemplate, getPropertyBreakdown, getPropertyTimeline, getProviderConnections, getProviderMetadata, getProvidersMetadata, getProxyLogById, getProxyLogByRequestId, getProxyLogs, getPublicBranches, getPublicIp, getPublicRepository, getQuota, getRecentActivity, getRemoteExternalImage, getRepositoryBranches, getRepositoryById, getRepositoryByName, getRepositoryPresetByName, getRepositoryPresetLive, getRepositoryTags, getResolvedEnvironmentVariables, getResolvedEnvironmentVariableValue, getRestoreCapabilities, getRestoreRun, getRoute, getRun, getRunWithLogs, getS3Credentials, getS3Source, getSandbox, getSandboxStatus, getScan, getScanByDeployment, getScanVulnerabilities, getService, getServiceBySlug, getServiceEnvironmentVariable, getServiceEnvironmentVariables, getServiceHealthStatus, getServicePreviewEnvironmentVariableNames, getServicePreviewEnvironmentVariablesMasked, getServiceRuntime, getServiceStats, getServiceTypeParameters, getServiceTypes, getSessionDetails, getSessionEvents, getSessionLogs, getSessionReplay, getSessionReplayEvents, getSettings, getSkill, getSlowQueries, getStaticBundle, getStatusOverview, getTagsByRepositoryId, getTeam, getTimeBucketStats, getTodayStats, getTrace, getUnifiedTrace, getUniqueCounts, getUniqueEvents, getUpdateStatus, getUptimeHistory, getUsageByProvider, getUsageRecent, getUsageSummary, getUsageTimeseries, getUsageTopModels, getVisitorByGuid, getVisitorById, getVisitorDetails, getVisitorFacets, getVisitorInfo, getVisitorJourney, getVisitors, getVisitorSessions, getVisitorStats, getWebhook, grantProjectAccess, handleGitProviderOauthCallback, hasAnalyticsEvents, hasErrorGroups, hasPerformanceMetrics, importExternalService, ingestLogs, ingestLogsByPath, ingestMetrics, ingestMetricsByPath, ingestSentryEnvelope, ingestSentryEvent, ingestTraces, ingestTracesByPath, initSessionReplay, inspectDropArchive, jobLogs, jobStatus, killJob, kvDel, kvDisable, kvEnable, kvExpire, kvGet, kvIncr, kvKeys, kvSet, kvStatus, kvTtl, kvUpdate, latestRunForSource, linkCustomDomainToCertificate, linkServiceToProject, listAgentRuns, listAgents, listAiProviders, listAlertRules, listAlerts, listAllConversations, listAllRuns, listApiKeys, listAuditLogs, listAvailableContainers, listBackupAlerts, listBackupChildren, listBackupSchedules, listBackupsForSchedule, listCommitsByRepositoryId, listConnections, listContainers, listContainersAtPath, listConversations, listCustomDomainsForProject, listDashboards, listDeliveries, listDeploymentContainerLogs, listDeploymentTokens, listDnsProviders, listDomains, listDsns, listEmailDomains, listEmailProviders, listEmails, listEnrollmentTokens, listEntities, listErrorEvents, listErrorGroups, listEvents, listEventTypes, listExternalImages, listExternalPlugins, listExternalServiceBackups, listFlags, listFunnels, listGitProviders, listGlobalMcps, listGlobalSkills, listIncidents, listInsights, listIpAccessControl, listJobs, listKnownAiAgents, listManagedDomains, listMcps, listMetricLabelKeys, listMetricLabelValues, listMetricNames, listModels, listMonitors, listNotificationProviders, listOidcProviders, listOidcProviderUsers, listOidcRoleMappings, listOnDemandCerts, listOrders, listPeers, listPendingActions, listPgUpgrades, listPresets, listProjectAccess, listProjectAlarms, listProjectScans, listProjectSecrets, listProjectServices, listProjectTemplates, listProjectTemplateTags, listProviderKeys, listProviderZones, listPublicProviders, listReleaseFiles, listReleases, listRemoteExternalImages, listRepositoriesByConnection, listRepositoriesByProvider, listRestoreRunsForService, listRootContainers, listRoutes, listS3Sources, listSandboxes, listScheduleRunJobs, listScheduleRuns, listScheduleServices, listSecrets, listServiceHealthStatuses, listServiceProjects, listServices, listServiceSchedules, listSkills, listSourceBackups, listSourceFiles, listSourceMaps, listSources, listStaticBundles, listSyncedRepositories, listTeamMembers, listTeamProjects, listTeams, listUsers, listWebhooks, login, logout, lookupDnsARecords, mintEnrollmentToken, mkdir, nodeHeartbeat, nodeMetricsGetRange, observabilityFullEvent, observabilityListEvents, oidcCallback, type Options, patchAdminGate, patchPreviewGatewaySettings, pauseDeployment, pauseSandbox, planRestore, postDnsAck, previewAlert, previewFunnelMetrics, previewHostnameMode, promoteClusterMember, promoteDeployment, provisionDomain, purgeProjectLogs, pushExternalImage, queryData, queryGenaiTraces, queryLogs, queryMetrics, queryTraces, queryTraceSummaries, readFile, reAnalyze, recordConsoleEvent, recordEventMetrics, recordFlagExposure, recordSpeedMetrics, refreshRouteTable, regenerateDsn, registerExternalImage, registerNode, reinstallGitlabWebhook, rejectPendingAction, reloadPlugins, removeClusterMember, removeManagedDomain, removeRole, removeTeamMember, renameConversation, renewDomain, requestPasswordReset, resetPassword, resizeSandbox, resolveAlarm, restartContainer, restartPreviewGateway, restartSandbox, restoreFlag, restoreUser, resumeDeployment, resumeSandbox, retryCluster, retryDelivery, retryPgUpgrade, retryRun, revealGlobalMcpConfig, revealMcpConfig, revealNotificationProviderConfig, revealServiceParameter, revenueCreateIntegration, revenueDeleteIntegration, revenueGlobalEvents, revenueImportInvoicesCsv, revenueImportSubscriptionsCsv, revenueListIntegrations, revenueListProviders, revenueMetricsCustomers, revenueMetricsGlobalMrr, revenueMetricsGlobalSummary, revenueMetricsMrr, revenueMetricsSummary, revenueRecentEvents, revenueRotateToken, revenueUpdateConfig, revenueUpdateSecret, revokeDsn, revokeEnrollmentToken, revokeJoinToken, revokeProjectAccess, rollbackPgUpgrade, rollbackToDeployment, rootfsGc, rootfsReport, rotateApiKey, rotateDeploymentToken, runBackupForSource, runConnectionHealthCheck, runExternalServiceBackup, runScheduleNow, sandboxCreatePreviewLink, saveAgentToken, saveAiProviderCredential, searchLogs, sendEmail, setDefaultS3Source, setFlagEnvironment, setPreviewPassword, setupDns, setupDnsChallenge, setupEmailTracking, setupMfa, sleepEnvironment, smokeTestAgent, sourceSandbox, startAnalysis, startContainer, startFix, startGitProviderOauth, startOidcLoginBySlug, startPgUpgrade, startRestore, startService, statPath, stopContainer, stopSandbox, stopService, streamContainerMetrics, syncRepositories, tailDeploymentJobLogs, tailLogs, teardownDeployment, teardownEnvironment, testNotificationProvider, testOidcProvider, testProvider, testProviderConnection, testProviderKeyById, testProviderKeyInline, testS3ConnectionPreview, testS3SourceConnection, trackClick, trackOpen, triggerAgent, triggerProjectPipeline, triggerScan, triggerServiceHealthCheck, triggerWeeklyDigest, unlinkServiceFromProject, updateAgent, updateAiProvider, updateAlert, updateAlertRule, updateApiKey, updateAutomaticDeploy, updateBackupSchedule, updateCloudflareProvider, updateConnectionToken, updateCustomDomain, updateDashboard, updateDeploymentToken, updateEmailProvider, updateEnvironmentSettings, updateEnvironmentSubdomain, updateEnvironmentVariable, updateErrorGroup, updateFlag, updateFunnel, updateGitProviderCredentials, updateGitSettings, updateGlobalMcp, updateGlobalSkill, updateIncidentStatus, updateIpAccessControl, updateManagedDomain, updateMcp, updateNotificationEmailProvider, updateNotificationProvider, updateOidcProvider, updatePreferences, updateProject, updateProjectDeploymentConfig, updateProjectSecret, updateProjectSettings, updateProvider, updateProviderKey, updateRoute, updateS3Source, updateSelf, updateService, updateServiceResources, updateSessionDuration, updateSettings, updateSkill, updateSlackProvider, updateSpeedMetrics, updateTeam, updateTeamMemberRole, updateUser, updateWebhook, updateWebhookProvider, upgradePreviewGateway, upgradeService, uploadGlobalSkill, uploadReleaseFile, uploadSkill, uploadSourceFile, uploadSourceMap, uploadStaticBundle, upsertSecret, validateConnection, validateEmail, verifyAndEnableMfa, verifyDomain, verifyEmail, verifyManagedDomain, verifyMfaChallenge, verifyStepUp, wakeEnvironment, webhookTrigger, workflowDryRun, writeFile, writeFiles } from '../sdk.gen'; -import type { AcknowledgeAlarmData, ActivateAiProviderData, ActivateAiProviderResponse, ActivateApiKeyData, ActivateApiKeyResponse, ActivateConnectionData, ActivateProviderData, AddClusterMemberData, AddClusterMemberResponse, AddContextData, AddEnvironmentDomainData, AddEnvironmentDomainResponse, AddEventsData, AddEventsError, AddEventsResponse2, AddManagedDomainData, AddManagedDomainResponse, AddSessionReplayEventsData, AddSessionReplayEventsError, AddSessionReplayEventsResponse, AddTeamMemberData, AddTeamMemberResponse, AdminDrainNodeData, AdminDrainNodeResponse, AdminDrainStatusData, AdminDrainStatusResponse, AdminGetNodeData, AdminGetNodeResponse, AdminListNodeContainersData, AdminListNodeContainersResponse, AdminListNodesData, AdminListNodesResponse, AdminRemoveNodeData, AdminRemoveNodeResponse, AdminUndrainNodeData, AdminUndrainNodeResponse, ApplyHostnameModeData, ApplyHostnameModeResponse, ArchiveConversationData, ArchiveConversationResponse, ArchiveFlagData, ArchiveFlagResponse2, AssignRoleData, AttachScheduleServicesData, AttachScheduleServicesError, AttachScheduleServicesResponse2, BlobCopyData, BlobCopyError, BlobCopyResponse, BlobDeleteData, BlobDeleteError, BlobDeleteResponse, BlobDisableData, BlobDisableResponse, BlobDownloadData, BlobDownloadError, BlobEnableData, BlobEnableResponse, BlobListData, BlobListError, BlobListResponse, BlobPutData, BlobPutError, BlobPutResponse, BlobStatusData, BlobStatusResponse2, BlobUpdateData, BlobUpdateResponse, CancelBackupData, CancelBackupError, CancelBackupResponse2, CancelData, CancelDeploymentData, CancelDeploymentResponse, CancelDomainOrderData, CancelDomainOrderResponse, CancelPgUpgradeData, CancelPgUpgradeResponse, CancelRunData, CancelRunResponse, CancelScheduleRunData, CancelScheduleRunError, CancelScheduleRunResponse, ChangePasswordSelfData, ChangePasswordSelfResponse, ChangeProjectSourceData, ChangeProjectSourceResponse, ChatCompletionsData, ChatCompletionsError, ChatCompletionsResponse, CheckAnalyticsHasEventsData, CheckAnalyticsHasEventsResponse, CheckCommitExistsData, CheckCommitExistsResponse, CheckDomainStatusData, CheckDomainStatusResponse, CheckExplorerSupportData, CheckExplorerSupportResponse, CheckIpBlockedData, CheckIpBlockedError, CheckProviderDeletionSafetyData, CheckProviderDeletionSafetyResponse, ChunkUploadOptionsData, ChunkUploadOptionsResponse, CleanupExpiredBackupsData, CleanupExpiredBackupsError, CleanupExpiredBackupsResponse, ClearPreviewPasswordData, ClearPreviewPasswordResponse, CliDeviceApproveData, CliDeviceApproveResponse2, CliDeviceDenyData, CliDeviceDenyResponse, CliDeviceLookupData, CliDeviceLookupResponse2, CliDevicePollData, CliDevicePollResponse2, CliDeviceStartData, CliDeviceStartResponse2, CliLogoutData, CliLogoutResponse, CmdData, CmdKillData, CmdKillResponse, CmdLogsData, CmdResponse2, ConfirmPendingActionData, ConfirmPendingActionResponse, ContainerMetricsGetHistoryData, ContainerMetricsGetHistoryResponse, CreateAgentData, CreateAgentResponse, CreateAlertData, CreateAlertError, CreateAlertResponse, CreateAlertRuleData, CreateAlertRuleResponse, CreateApiKeyData, CreateApiKeyResponse2, CreateBackupScheduleData, CreateBackupScheduleError, CreateBackupScheduleResponse, CreateBitbucketProviderData, CreateBitbucketProviderResponse, CreateCloudflareProviderData, CreateCloudflareProviderResponse, CreateConversationData, CreateConversationResponse, CreateCustomDomainData, CreateCustomDomainResponse, CreateDashboardData, CreateDashboardError, CreateDashboardResponse, CreateDeploymentTokenData, CreateDeploymentTokenResponse2, CreateDnsProviderData, CreateDnsProviderResponse, CreateDomainData, CreateDomainResponse, CreateDsnData, CreateDsnResponse, CreateEmailDomainData, CreateEmailDomainResponse, CreateEmailProviderData, CreateEmailProviderResponse, CreateEnvironmentData, CreateEnvironmentResponse, CreateEnvironmentVariableData, CreateEnvironmentVariableResponse, CreateFlagData, CreateFlagResponse, CreateFunnelData, CreateFunnelResponse2, CreateGenericProviderData, CreateGenericProviderResponse, CreateGiteaPatProviderData, CreateGiteaPatProviderResponse, CreateGithubPatProviderData, CreateGithubPatProviderResponse, CreateGitlabOauthProviderData, CreateGitlabOauthProviderResponse, CreateGitlabPatProviderData, CreateGitlabPatProviderResponse, CreateGitProviderData, CreateGitProviderResponse, CreateGlobalMcpData, CreateGlobalMcpResponse, CreateGlobalSkillData, CreateGlobalSkillResponse, CreateIncidentData, CreateIncidentResponse, CreateIpAccessControlData, CreateIpAccessControlError, CreateIpAccessControlResponse, CreateMcpData, CreateMcpResponse, CreateMonitorData, CreateMonitorResponse, CreateNotificationEmailProviderData, CreateNotificationEmailProviderResponse, CreateNotificationProviderData, CreateNotificationProviderResponse, CreateOidcProviderData, CreateOidcProviderResponse, CreateOidcRoleMappingData, CreateOidcRoleMappingResponse, CreateOrRecreateOrderData, CreateOrRecreateOrderResponse, CreatePlanData, CreatePlanResponse2, CreatePrData, CreateProjectData, CreateProjectFromTemplateData, CreateProjectFromTemplateResponse2, CreateProjectReleaseData, CreateProjectReleaseResponse, CreateProjectResponse, CreateProjectSecretData, CreateProjectSecretResponse, CreateProviderKeyData, CreateProviderKeyError, CreateProviderKeyResponse, CreatePrResponse2, CreateReleaseData, CreateReleaseResponse, CreateRouteData, CreateRouteResponse, CreateS3SourceData, CreateS3SourceError, CreateS3SourceResponse, CreateSandboxData, CreateSandboxResponse, CreateServiceData, CreateServiceResponse, CreateSkillData, CreateSkillResponse, CreateSlackProviderData, CreateSlackProviderResponse, CreateTeamData, CreateTeamResponse, CreateUserData, CreateUserResponse, CreateWebhookData, CreateWebhookProviderData, CreateWebhookProviderResponse, CreateWebhookResponse, DeactivateApiKeyData, DeactivateApiKeyResponse, DeactivateConnectionData, DeactivateProviderData, DeleteAgentData, DeleteAgentResponse, DeleteAlertData, DeleteAlertError, DeleteAlertResponse, DeleteAlertRuleData, DeleteAlertRuleResponse, DeleteApiKeyData, DeleteApiKeyResponse, DeleteBackupData, DeleteBackupError, DeleteBackupResponse, DeleteBackupScheduleData, DeleteBackupScheduleError, DeleteBackupScheduleResponse, DeleteConnectionData, DeleteConnectionResponse, DeleteCustomDomainData, DeleteCustomDomainResponse, DeleteDashboardData, DeleteDashboardError, DeleteDashboardResponse, DeleteDeploymentTokenData, DeleteDeploymentTokenResponse, DeleteDnsProviderData, DeleteDnsProviderResponse, DeleteDomainData, DeleteDomainResponse, DeleteEmailDomainData, DeleteEmailDomainResponse, DeleteEmailProviderData, DeleteEmailProviderResponse, DeleteEnvironmentData, DeleteEnvironmentDomainData, DeleteEnvironmentDomainResponse, DeleteEnvironmentResponse, DeleteEnvironmentVariableData, DeleteEnvironmentVariableResponse, DeleteExternalImageData, DeleteExternalImageResponse, DeleteFunnelData, DeleteGitProviderData, DeleteGitProviderResponse, DeleteGlobalMcpData, DeleteGlobalMcpResponse, DeleteGlobalSkillData, DeleteGlobalSkillResponse, DeleteIpAccessControlData, DeleteIpAccessControlError, DeleteIpAccessControlResponse, DeleteMcpData, DeleteMcpResponse, DeleteMonitorData, DeleteMonitorResponse, DeleteNotificationProviderData, DeleteNotificationProviderResponse, DeleteOidcProviderData, DeleteOidcProviderResponse, DeleteOidcRoleMappingData, DeleteOidcRoleMappingResponse, DeletePreferencesData, DeletePreferencesResponse, DeleteProjectData, DeleteProjectResponse, DeleteProjectSecretData, DeleteProjectSecretResponse, DeleteProviderKeyData, DeleteProviderKeyError, DeleteProviderKeyResponse, DeleteProviderSafelyData, DeleteProviderSafelyResponse, DeleteReleaseSourceFilesData, DeleteReleaseSourceFilesResponse, DeleteReleaseSourceMapsData, DeleteReleaseSourceMapsResponse, DeleteRouteData, DeleteRouteResponse, DeleteS3SourceData, DeleteS3SourceError, DeleteS3SourceResponse, DeleteScanData, DeleteScanError, DeleteScanResponse, DeleteSecretData, DeleteSecretResponse, DeleteServiceData, DeleteServiceResponse, DeleteSessionReplayData, DeleteSessionReplayError, DeleteSkillData, DeleteSkillResponse, DeleteSourceMapData, DeleteSourceMapResponse, DeleteStaticBundleData, DeleteStaticBundleResponse, DeleteTeamData, DeleteTeamResponse, DeleteUserData, DeleteUserResponse, DeleteWebhookData, DeleteWebhookResponse, DeployFromImageData, DeployFromImageResponse, DeployFromImageUploadData, DeployFromImageUploadResponse, DeployFromStaticData, DeployFromStaticResponse, DeployFromUploadedSourceData, DeployFromUploadedSourceResponse, DeploymentMetricsGetLatestData, DeploymentMetricsGetLatestResponse, DeploymentMetricsGetRangeData, DeploymentMetricsGetRangeResponse, DeploymentMetricsToggleData, DestroySandboxData, DestroySandboxResponse, DetachScheduleServiceData, DetachScheduleServiceError, DetachScheduleServiceResponse, DetectPublicPresetsData, DetectPublicPresetsResponse, DisableBackupScheduleData, DisableBackupScheduleResponse, DisableMfaData, DisableMfaResponse, DiscoverWorkloadsData, DiscoverWorkloadsResponse, DomainData, DomainResponse2, DownloadGlobalSkillArchiveData, DownloadGlobalSkillArchiveResponse, DownloadObjectData, DownloadObjectResponse, DownloadSkillArchiveData, DownloadSkillArchiveResponse, EmailStatusData, EmailStatusResponse2, EmbeddingsData, EmbeddingsError, EmbeddingsResponse, EnableBackupScheduleData, EnableBackupScheduleResponse, EnrichVisitorData, EnrichVisitorResponse2, ExecData, ExecDetachedData, ExecDetachedResponse2, ExecResponse2, ExecuteDeploymentOperationData, ExecuteDeploymentOperationResponse, ExecuteImportData, ExecuteImportResponse2, ExtendTimeoutData, ExtendTimeoutResponse, ExternalServiceEnablePgStatStatementsData, ExternalServiceEnablePgStatStatementsResponse, ExternalServiceMetricsByDatabaseData, ExternalServiceMetricsByDatabaseResponse, ExternalServiceMetricsCreateAlertRuleData, ExternalServiceMetricsCreateAlertRuleResponse, ExternalServiceMetricsDeleteAlertRuleData, ExternalServiceMetricsDeleteAlertRuleResponse, ExternalServiceMetricsGetAlertRulesData, ExternalServiceMetricsGetAlertRulesResponse, ExternalServiceMetricsGetLatestData, ExternalServiceMetricsGetLatestResponse, ExternalServiceMetricsGetRangeData, ExternalServiceMetricsGetRangeResponse, ExternalServiceMetricsStatusData, ExternalServiceMetricsStatusResponse, ExternalServiceMetricsToggleData, ExternalServiceMetricsUpdateAlertRuleData, ExternalServiceMetricsUpdateAlertRuleResponse, ExternalServiceResetPgStatStatementsData, ExternalServiceResetPgStatStatementsResponse, FinalizeOrderData, FinalizeOrderResponse, FinalizeProjectReleaseData, FinalizeProjectReleaseResponse, FindConversationData, FindConversationResponse, GenerateJoinTokenData, GenerateJoinTokenResponse2, GeneratePresetDockerfileData, GeneratePresetDockerfileResponse, GetAccessInfoData, GetAccessInfoResponse, GetActiveVisitorsData, GetActiveVisitorsResponse, GetActivityGraphData, GetActivityGraphResponse, GetAdminGateData, GetAdminGateResponse, GetAgentData, GetAgentResponse, GetAggregatedBucketsData, GetAggregatedBucketsResponse, GetAiAgentBreakdownData, GetAiAgentBreakdownError, GetAiAgentBreakdownResponse, GetAiAgentPagesData, GetAiAgentPagesError, GetAiAgentPagesResponse, GetAiAgentTimelineData, GetAiAgentTimelineError, GetAiAgentTimelineResponse, GetAiPageBreakdownData, GetAiPageBreakdownError, GetAiPageBreakdownResponse, GetAiStatusBreakdownData, GetAiStatusBreakdownError, GetAiStatusBreakdownResponse, GetAlertData, GetAlertError, GetAlertResponse, GetAlertRuleData, GetAlertRuleResponse, GetAllRepositoriesByNameData, GetAllRepositoriesByNameResponse, GetAnalyticsActiveVisitorsData, GetAnalyticsActiveVisitorsResponse, GetAnalyticsEventsCountData, GetAnalyticsEventsCountResponse, GetAnalyticsSessionEventsData, GetAnalyticsSessionEventsResponse, GetAnalyticsVisitorSessionsData, GetAnalyticsVisitorSessionsResponse, GetApiKeyData, GetApiKeyPermissionsData, GetApiKeyPermissionsResponse, GetApiKeyResponse, GetAuditLogData, GetAuditLogResponse, GetBackupData, GetBackupError, GetBackupResponse, GetBackupScheduleData, GetBackupScheduleResponse, GetBranchesByRepositoryIdData, GetBranchesByRepositoryIdResponse, GetBucketedIncidentsData, GetBucketedIncidentsResponse, GetBucketedStatusData, GetBucketedStatusResponse, GetChallengeTokenData, GetChallengeTokenResponse, GetChatReadinessData, GetChatReadinessResponse, GetCliStatusData, GetClusterHealthData, GetClusterHealthResponse, GetClusterMemberData, GetClusterMemberResponse, GetCmdData, GetCmdResponse, GetContainerDetailData, GetContainerDetailResponse, GetContainerEnvironmentVariableData, GetContainerEnvironmentVariableResponse, GetContainerInfoData, GetContainerInfoResponse, GetContainerLogsByIdData, GetContainerLogsData, GetContainerMetricsData, GetContainerMetricsResponse, GetConversationData, GetConversationDetailData, GetConversationDetailError, GetConversationDetailResponse, GetConversationResponse, GetConversationsData, GetConversationsError, GetConversationsResponse, GetCronByIdData, GetCronByIdResponse, GetCronExecutionsData, GetCronExecutionsResponse, GetCrossProjectTraceSiblingsData, GetCrossProjectTraceSiblingsError, GetCrossProjectTraceSiblingsResponse, GetCurrentMonitorStatusData, GetCurrentMonitorStatusResponse, GetCurrentUserData, GetCurrentUserResponse, GetCustomDomainData, GetCustomDomainResponse, GetDashboardData, GetDashboardError, GetDashboardProjectsAnalyticsData, GetDashboardProjectsAnalyticsResponse, GetDashboardResponse, GetDeliveryData, GetDeliveryResponse, GetDeploymentContainerLogContentData, GetDeploymentContainerLogContentResponse, GetDeploymentData, GetDeploymentJobLogsData, GetDeploymentJobLogsResponse, GetDeploymentJobsData, GetDeploymentJobsResponse, GetDeploymentOperationsData, GetDeploymentOperationsResponse, GetDeploymentOperationStatusData, GetDeploymentOperationStatusResponse, GetDeploymentResponse, GetDeploymentTokenData, GetDeploymentTokenResponse, GetDiskStatusData, GetDiskStatusResponse, GetDnsChangesData, GetDnsChangesResponse, GetDnsProviderData, GetDnsProviderResponse, GetDomainByHostData, GetDomainByHostResponse, GetDomainByIdData, GetDomainByIdResponse, GetDomainByNameData, GetDomainByNameResponse, GetDomainData, GetDomainDnsRecordsData, GetDomainDnsRecordsResponse, GetDomainOrderData, GetDomainOrderResponse, GetDomainResponse, GetEmailData, GetEmailEventsData, GetEmailEventsResponse, GetEmailLinksData, GetEmailLinksResponse, GetEmailProviderData, GetEmailProviderResponse, GetEmailResponse, GetEmailStatsData, GetEmailStatsResponse, GetEmailTrackingData, GetEmailTrackingResponse, GetEmailTrackingStatusData, GetEmailTrackingStatusResponse, GetEntityInfoData, GetEntityInfoResponse, GetEnvironmentCronsData, GetEnvironmentCronsResponse, GetEnvironmentData, GetEnvironmentDomainsData, GetEnvironmentDomainsResponse, GetEnvironmentResponse, GetEnvironmentsData, GetEnvironmentsResponse, GetEnvironmentVariablesData, GetEnvironmentVariablesResponse, GetEnvironmentVariableValueData, GetEnvironmentVariableValueResponse, GetErrorDashboardStatsData, GetErrorDashboardStatsResponse, GetErrorEventData, GetErrorEventResponse, GetErrorGroupData, GetErrorGroupResponse, GetErrorStatsData, GetErrorStatsResponse, GetErrorTimeSeriesData, GetErrorTimeSeriesResponse, GetEventDetailData, GetEventDetailResponse, GetEventEntriesData, GetEventEntriesResponse, GetEventsCountData, GetEventsCountResponse, GetEventsTimelineData, GetEventsTimelineResponse, GetEventTypeBreakdownData, GetEventTypeBreakdownResponse, GetEventVisitorsData, GetEventVisitorsResponse, GetExternalImageData, GetExternalImageResponse, GetFileData, GetFileResponse, GetFlagData, GetFlagResponse, GetFlagSnapshotData, GetFlagSnapshotResponse, GetFunnelMetricsData, GetFunnelMetricsResponse, GetGenaiTraceData, GetGenaiTraceError, GetGenaiTraceResponse, GetGeneralStatsData, GetGeneralStatsResponse, GetGitProviderData, GetGitProviderResponse, GetGlobalEventsData, GetGlobalEventsResponse, GetGlobalEventStatsData, GetGlobalEventStatsResponse, GetGlobalMcpData, GetGlobalMcpResponse, GetGlobalSandboxStatusData, GetGlobalSandboxStatusResponse, GetGlobalSkillData, GetGlobalSkillResponse, GetGroupedPageMetricsData, GetGroupedPageMetricsError, GetGroupedPageMetricsResponse, GetHealthData, GetHealthError, GetHealthResponse, GetHourlyVisitsData, GetHourlyVisitsResponse, GetHttpChallengeDebugData, GetHttpChallengeDebugResponse, GetImportStatusData, GetImportStatusResponse, GetIncidentData, GetIncidentResponse, GetIncidentUpdatesData, GetIncidentUpdatesResponse, GetIpAccessControlData, GetIpAccessControlError, GetIpAccessControlResponse, GetIpGeolocationData, GetIpGeolocationError, GetIpGeolocationResponse, GetJoinTokenStatusData, GetJoinTokenStatusResponse, GetLastDeploymentData, GetLastDeploymentResponse, GetLatestScanData, GetLatestScanError, GetLatestScanResponse, GetLatestScansPerEnvironmentData, GetLatestScansPerEnvironmentError, GetLatestScansPerEnvironmentResponse, GetLiveVisitorsListData, GetLiveVisitorsListResponse, GetLogContextData, GetLogContextError, GetLogContextResponse, GetMcpData, GetMcpResponse, GetMetricsOverTimeData, GetMetricsOverTimeError, GetMetricsOverTimeResponse, GetMonitorData, GetMonitorResponse, GetNotificationProviderData, GetNotificationProviderResponse, GetOnDemandCertStatusData, GetOnDemandCertStatusResponse, GetOrCreateDsnData, GetOrCreateDsnResponse, GetPageFlowData, GetPageFlowResponse, GetPageHourlySessionsData, GetPageHourlySessionsResponse, GetPagePathDetailData, GetPagePathDetailResponse, GetPagePathsData, GetPagePathsResponse, GetPagePathsSparklinesData, GetPagePathsSparklinesResponse, GetPagePathVisitorsData, GetPagePathVisitorsResponse, GetPendingActionData, GetPendingActionResponse, GetPerformanceMetricsData, GetPerformanceMetricsError, GetPerformanceMetricsResponse, GetPgUpgradeData, GetPgUpgradeLogsData, GetPgUpgradeLogsResponse, GetPgUpgradeResponse, GetPipelineStatsData, GetPipelineStatsError, GetPipelineStatsResponse, GetPlatformInfoData, GetPlatformInfoResponse, GetPostgresWalHealthData, GetPostgresWalHealthResponse, GetPreferencesData, GetPreferencesResponse, GetPreviewGatewayLogsData, GetPreviewGatewayLogsResponse, GetPreviewGatewaySettingsData, GetPreviewGatewaySettingsResponse, GetPreviewGatewayStatusData, GetPreviewGatewayStatusResponse, GetPricingData, GetPricingError, GetPricingResponse, GetPrivateIpData, GetProjectAlarmsSummaryData, GetProjectAlarmsSummaryResponse, GetProjectBySlugData, GetProjectBySlugResponse, GetProjectData, GetProjectDeploymentsData, GetProjectDeploymentsResponse, GetProjectResponse, GetProjectsData, GetProjectServiceEnvironmentVariablesData, GetProjectServiceEnvironmentVariablesResponse, GetProjectSessionReplaysData, GetProjectSessionReplaysError, GetProjectSessionReplaysResponse2, GetProjectsHealthData, GetProjectsHealthError, GetProjectsHealthResponse, GetProjectsMonitorHealthData, GetProjectsMonitorHealthResponse, GetProjectsResponse, GetProjectStatisticsData, GetProjectStatisticsResponse, GetProjectTemplateData, GetProjectTemplateResponse, GetPropertyBreakdownData, GetPropertyBreakdownResponse, GetPropertyTimelineData, GetPropertyTimelineResponse, GetProviderConnectionsData, GetProviderConnectionsResponse, GetProviderMetadataData, GetProviderMetadataResponse, GetProvidersMetadataData, GetProvidersMetadataResponse, GetProxyLogByIdData, GetProxyLogByIdError, GetProxyLogByIdResponse, GetProxyLogByRequestIdData, GetProxyLogByRequestIdError, GetProxyLogByRequestIdResponse, GetProxyLogsData, GetProxyLogsError, GetProxyLogsResponse, GetPublicBranchesData, GetPublicBranchesResponse, GetPublicIpData, GetPublicRepositoryData, GetPublicRepositoryResponse, GetQuotaData, GetQuotaError, GetQuotaResponse, GetRecentActivityData, GetRecentActivityResponse, GetRemoteExternalImageData, GetRemoteExternalImageResponse, GetRepositoryBranchesData, GetRepositoryBranchesResponse, GetRepositoryByIdData, GetRepositoryByIdResponse, GetRepositoryByNameData, GetRepositoryByNameResponse, GetRepositoryPresetByNameData, GetRepositoryPresetByNameResponse, GetRepositoryPresetLiveData, GetRepositoryPresetLiveResponse, GetRepositoryTagsData, GetRepositoryTagsResponse, GetResolvedEnvironmentVariablesData, GetResolvedEnvironmentVariablesResponse, GetResolvedEnvironmentVariableValueData, GetResolvedEnvironmentVariableValueResponse, GetRestoreCapabilitiesData, GetRestoreCapabilitiesError, GetRestoreCapabilitiesResponse, GetRestoreRunData, GetRestoreRunError, GetRestoreRunResponse, GetRouteData, GetRouteResponse, GetRunData, GetRunResponse, GetRunWithLogsData, GetRunWithLogsResponse, GetS3CredentialsData, GetS3CredentialsResponse, GetS3SourceData, GetS3SourceError, GetS3SourceResponse, GetSandboxData, GetSandboxResponse, GetSandboxStatusData, GetSandboxStatusResponse, GetScanByDeploymentData, GetScanByDeploymentError, GetScanByDeploymentResponse, GetScanData, GetScanError, GetScanResponse, GetScanVulnerabilitiesData, GetScanVulnerabilitiesError, GetScanVulnerabilitiesResponse, GetServiceBySlugData, GetServiceBySlugResponse, GetServiceData, GetServiceEnvironmentVariableData, GetServiceEnvironmentVariableResponse, GetServiceEnvironmentVariablesData, GetServiceEnvironmentVariablesResponse, GetServiceHealthStatusData, GetServiceHealthStatusResponse, GetServicePreviewEnvironmentVariableNamesData, GetServicePreviewEnvironmentVariableNamesResponse, GetServicePreviewEnvironmentVariablesMaskedData, GetServicePreviewEnvironmentVariablesMaskedResponse, GetServiceResponse, GetServiceRuntimeData, GetServiceRuntimeResponse, GetServiceStatsData, GetServiceStatsResponse, GetServiceTypeParametersData, GetServiceTypesData, GetServiceTypesResponse, GetSessionDetailsData, GetSessionDetailsResponse, GetSessionEventsData, GetSessionEventsResponse, GetSessionLogsData, GetSessionLogsResponse, GetSessionReplayData, GetSessionReplayError, GetSessionReplayEventsData, GetSessionReplayEventsError, GetSessionReplayEventsResponse, GetSessionReplayResponse2, GetSettingsData, GetSettingsResponse, GetSkillData, GetSkillResponse, GetSlowQueriesData, GetSlowQueriesResponse, GetStaticBundleData, GetStaticBundleResponse, GetStatusOverviewData, GetStatusOverviewResponse, GetTagsByRepositoryIdData, GetTagsByRepositoryIdResponse, GetTeamData, GetTeamResponse, GetTimeBucketStatsData, GetTimeBucketStatsError, GetTimeBucketStatsResponse, GetTodayStatsData, GetTodayStatsError, GetTodayStatsResponse, GetTraceData, GetTraceError, GetTraceResponse, GetUnifiedTraceData, GetUnifiedTraceError, GetUnifiedTraceResponse, GetUniqueCountsData, GetUniqueCountsResponse, GetUniqueEventsData, GetUniqueEventsResponse, GetUpdateStatusData, GetUpdateStatusResponse, GetUptimeHistoryData, GetUptimeHistoryResponse, GetUsageByProviderData, GetUsageByProviderError, GetUsageByProviderResponse, GetUsageRecentData, GetUsageRecentError, GetUsageRecentResponse, GetUsageSummaryData, GetUsageSummaryError, GetUsageSummaryResponse, GetUsageTimeseriesData, GetUsageTimeseriesError, GetUsageTimeseriesResponse, GetUsageTopModelsData, GetUsageTopModelsError, GetUsageTopModelsResponse, GetVisitorByGuidData, GetVisitorByGuidResponse, GetVisitorByIdData, GetVisitorByIdResponse, GetVisitorDetailsData, GetVisitorDetailsResponse, GetVisitorFacetsData, GetVisitorFacetsResponse, GetVisitorInfoData, GetVisitorInfoResponse, GetVisitorJourneyData, GetVisitorJourneyResponse, GetVisitorsData, GetVisitorSessionsData, GetVisitorSessionsError, GetVisitorSessionsResponse2, GetVisitorsResponse, GetVisitorStatsData, GetVisitorStatsResponse, GetWebhookData, GetWebhookResponse, GrantProjectAccessData, GrantProjectAccessResponse, HandleGitProviderOauthCallbackData, HasAnalyticsEventsData, HasAnalyticsEventsResponse2, HasErrorGroupsData, HasErrorGroupsResponse2, HasPerformanceMetricsData, HasPerformanceMetricsError, HasPerformanceMetricsResponse, ImportExternalServiceData, ImportExternalServiceResponse, IngestLogsByPathData, IngestLogsByPathError, IngestLogsData, IngestLogsError, IngestMetricsByPathData, IngestMetricsByPathError, IngestMetricsData, IngestMetricsError, IngestSentryEnvelopeData, IngestSentryEventData, IngestSentryEventResponse, IngestTracesByPathData, IngestTracesByPathError, IngestTracesData, IngestTracesError, InitSessionReplayData, InitSessionReplayError, InitSessionReplayResponse, InspectDropArchiveData, InspectDropArchiveResponse, JobLogsData, JobStatusData, JobStatusResponse2, KillJobData, KillJobResponse, KvDelData, KvDelResponse, KvDisableData, KvDisableResponse, KvEnableData, KvEnableResponse, KvExpireData, KvExpireResponse, KvGetData, KvGetResponse, KvIncrData, KvIncrResponse, KvKeysData, KvKeysResponse, KvSetData, KvSetResponse, KvStatusData, KvStatusResponse2, KvTtlData, KvTtlResponse, KvUpdateData, KvUpdateResponse, LatestRunForSourceData, LatestRunForSourceResponse, LinkCustomDomainToCertificateData, LinkCustomDomainToCertificateResponse, LinkServiceToProjectData, LinkServiceToProjectResponse, ListAgentRunsData, ListAgentRunsResponse, ListAgentsData, ListAgentsResponse2, ListAiProvidersData, ListAiProvidersResponse, ListAlertRulesData, ListAlertRulesResponse, ListAlertsData, ListAlertsError, ListAlertsResponse, ListAllConversationsData, ListAllConversationsResponse, ListAllRunsData, ListAllRunsResponse, ListApiKeysData, ListApiKeysResponse, ListAuditLogsData, ListAuditLogsResponse, ListAvailableContainersData, ListAvailableContainersResponse, ListBackupAlertsData, ListBackupAlertsError, ListBackupAlertsResponse, ListBackupChildrenData, ListBackupChildrenError, ListBackupChildrenResponse, ListBackupSchedulesData, ListBackupSchedulesError, ListBackupSchedulesResponse, ListBackupsForScheduleData, ListBackupsForScheduleResponse, ListCommitsByRepositoryIdData, ListCommitsByRepositoryIdResponse, ListConnectionsData, ListConnectionsResponse, ListContainersAtPathData, ListContainersAtPathResponse, ListContainersData, ListContainersResponse, ListConversationsData, ListConversationsResponse, ListCustomDomainsForProjectData, ListCustomDomainsForProjectResponse, ListDashboardsData, ListDashboardsError, ListDashboardsResponse, ListDeliveriesData, ListDeliveriesResponse, ListDeploymentContainerLogsData, ListDeploymentContainerLogsResponse, ListDeploymentTokensData, ListDeploymentTokensResponse, ListDnsProvidersData, ListDnsProvidersResponse, ListDomainsData, ListDomainsResponse2, ListDsnsData, ListDsnsResponse, ListEmailDomainsData, ListEmailDomainsResponse, ListEmailProvidersData, ListEmailProvidersResponse, ListEmailsData, ListEmailsResponse, ListEnrollmentTokensData, ListEnrollmentTokensResponse, ListEntitiesData, ListEntitiesResponse, ListErrorEventsData, ListErrorEventsResponse, ListErrorGroupsData, ListErrorGroupsResponse, ListEventsData, ListEventsResponse, ListEventTypesData, ListEventTypesResponse, ListExternalImagesData, ListExternalImagesResponse, ListExternalPluginsData, ListExternalPluginsResponse, ListExternalServiceBackupsData, ListExternalServiceBackupsError, ListExternalServiceBackupsResponse, ListFlagsData, ListFlagsResponse, ListFunnelsData, ListFunnelsResponse, ListGitProvidersData, ListGitProvidersResponse, ListGlobalMcpsData, ListGlobalMcpsResponse, ListGlobalSkillsData, ListGlobalSkillsResponse, ListIncidentsData, ListInsightsData, ListInsightsError, ListInsightsResponse, ListIpAccessControlData, ListIpAccessControlError, ListIpAccessControlResponse, ListJobsData, ListJobsResponse2, ListKnownAiAgentsData, ListKnownAiAgentsError, ListKnownAiAgentsResponse, ListManagedDomainsData, ListManagedDomainsResponse, ListMcpsData, ListMcpsResponse2, ListMetricLabelKeysData, ListMetricLabelKeysError, ListMetricLabelKeysResponse, ListMetricLabelValuesData, ListMetricLabelValuesError, ListMetricLabelValuesResponse, ListMetricNamesData, ListMetricNamesError, ListMetricNamesResponse, ListModelsData, ListModelsError, ListModelsResponse, ListMonitorsData, ListMonitorsResponse, ListNotificationProvidersData, ListNotificationProvidersResponse, ListOidcProvidersData, ListOidcProvidersResponse, ListOidcProviderUsersData, ListOidcProviderUsersResponse, ListOidcRoleMappingsData, ListOidcRoleMappingsResponse, ListOnDemandCertsData, ListOnDemandCertsResponse2, ListOrdersData, ListOrdersResponse2, ListPeersData, ListPeersResponse, ListPendingActionsData, ListPendingActionsResponse, ListPgUpgradesData, ListPgUpgradesResponse, ListPresetsData, ListPresetsResponse2, ListProjectAccessData, ListProjectAccessResponse, ListProjectAlarmsData, ListProjectAlarmsResponse, ListProjectScansData, ListProjectScansError, ListProjectScansResponse, ListProjectSecretsData, ListProjectSecretsResponse, ListProjectServicesData, ListProjectServicesResponse, ListProjectTemplatesData, ListProjectTemplatesResponse, ListProjectTemplateTagsData, ListProjectTemplateTagsResponse, ListProviderKeysData, ListProviderKeysError, ListProviderKeysResponse, ListProviderZonesData, ListProviderZonesResponse, ListPublicProvidersData, ListPublicProvidersResponse, ListReleaseFilesData, ListReleaseFilesResponse, ListReleasesData, ListReleasesResponse, ListRemoteExternalImagesData, ListRemoteExternalImagesResponse, ListRepositoriesByConnectionData, ListRepositoriesByConnectionResponse, ListRepositoriesByProviderData, ListRepositoriesByProviderResponse, ListRestoreRunsForServiceData, ListRestoreRunsForServiceResponse, ListRootContainersData, ListRootContainersResponse, ListRoutesData, ListRoutesResponse, ListS3SourcesData, ListS3SourcesError, ListS3SourcesResponse, ListSandboxesData, ListSandboxesResponse2, ListScheduleRunJobsData, ListScheduleRunJobsError, ListScheduleRunJobsResponse, ListScheduleRunsData, ListScheduleRunsError, ListScheduleRunsResponse, ListScheduleServicesData, ListScheduleServicesError, ListScheduleServicesResponse, ListSecretsData, ListSecretsResponse2, ListServiceHealthStatusesData, ListServiceHealthStatusesResponse, ListServiceProjectsData, ListServiceProjectsResponse, ListServiceSchedulesData, ListServiceSchedulesError, ListServiceSchedulesResponse, ListServicesData, ListServicesResponse, ListSkillsData, ListSkillsResponse2, ListSourceBackupsData, ListSourceBackupsError, ListSourceBackupsResponse, ListSourceFilesData, ListSourceFilesResponse, ListSourceMapsData, ListSourceMapsResponse, ListSourcesData, ListSourcesResponse, ListStaticBundlesData, ListStaticBundlesResponse, ListSyncedRepositoriesData, ListSyncedRepositoriesResponse, ListTeamMembersData, ListTeamMembersResponse, ListTeamProjectsData, ListTeamProjectsResponse, ListTeamsData, ListTeamsResponse, ListUsersData, ListUsersResponse, ListWebhooksData, ListWebhooksResponse, LoginData, LoginResponse, LogoutData, LookupDnsARecordsData, LookupDnsARecordsError, LookupDnsARecordsResponse, MintEnrollmentTokenData, MintEnrollmentTokenResponse2, MkdirData, MkdirResponse, NodeHeartbeatData, NodeHeartbeatResponse, NodeMetricsGetRangeData, NodeMetricsGetRangeResponse, ObservabilityFullEventData, ObservabilityFullEventError, ObservabilityFullEventResponse, ObservabilityListEventsData, ObservabilityListEventsError, ObservabilityListEventsResponse, OidcCallbackData, PatchAdminGateData, PatchAdminGateResponse, PatchPreviewGatewaySettingsData, PatchPreviewGatewaySettingsResponse, PauseDeploymentData, PauseDeploymentResponse, PauseSandboxData, PauseSandboxResponse, PlanRestoreData, PlanRestoreError, PlanRestoreResponse, PostDnsAckData, PostDnsAckResponse, PreviewAlertData, PreviewAlertError, PreviewAlertResponse, PreviewFunnelMetricsData, PreviewFunnelMetricsResponse, PreviewHostnameModeData, PreviewHostnameModeResponse, PromoteClusterMemberData, PromoteDeploymentData, PromoteDeploymentResponse, ProvisionDomainData, ProvisionDomainResponse, PurgeProjectLogsData, PurgeProjectLogsError, PushExternalImageData, PushExternalImageResponse, QueryDataData, QueryDataResponse2, QueryGenaiTracesData, QueryGenaiTracesError, QueryGenaiTracesResponse, QueryLogsData, QueryLogsError, QueryLogsResponse, QueryMetricsData, QueryMetricsError, QueryMetricsResponse, QueryTracesData, QueryTracesError, QueryTracesResponse, QueryTraceSummariesData, QueryTraceSummariesError, QueryTraceSummariesResponse, ReadFileData, ReadFileResponse2, ReAnalyzeData, RecordConsoleEventData, RecordEventMetricsData, RecordEventMetricsResponse, RecordFlagExposureData, RecordFlagExposureResponse, RecordSpeedMetricsData, RecordSpeedMetricsError, RecordSpeedMetricsResponse, RefreshRouteTableData, RefreshRouteTableResponse, RegenerateDsnData, RegenerateDsnResponse, RegisterExternalImageData, RegisterExternalImageResponse, RegisterNodeData, RegisterNodeResponse2, ReinstallGitlabWebhookData, ReinstallGitlabWebhookResponse, RejectPendingActionData, RejectPendingActionResponse, ReloadPluginsData, ReloadPluginsResponse, RemoveClusterMemberData, RemoveClusterMemberResponse, RemoveManagedDomainData, RemoveManagedDomainResponse, RemoveRoleData, RemoveRoleResponse, RemoveTeamMemberData, RemoveTeamMemberResponse, RenameConversationData, RenameConversationResponse, RenewDomainData, RenewDomainResponse, RequestPasswordResetData, RequestPasswordResetResponse, ResetPasswordData, ResetPasswordResponse, ResizeSandboxData, ResizeSandboxResponse, ResolveAlarmData, RestartContainerData, RestartContainerResponse, RestartPreviewGatewayData, RestartPreviewGatewayResponse, RestartSandboxData, RestartSandboxResponse, RestoreFlagData, RestoreFlagResponse, RestoreUserData, RestoreUserResponse, ResumeDeploymentData, ResumeDeploymentResponse, ResumeSandboxData, ResumeSandboxResponse, RetryClusterData, RetryClusterResponse, RetryDeliveryData, RetryDeliveryResponse, RetryPgUpgradeData, RetryPgUpgradeResponse, RetryRunData, RetryRunResponse, RevealGlobalMcpConfigData, RevealGlobalMcpConfigResponse, RevealMcpConfigData, RevealMcpConfigResponse, RevealNotificationProviderConfigData, RevealNotificationProviderConfigResponse, RevealServiceParameterData, RevealServiceParameterResponse, RevenueCreateIntegrationData, RevenueCreateIntegrationResponse, RevenueDeleteIntegrationData, RevenueDeleteIntegrationResponse, RevenueGlobalEventsData, RevenueGlobalEventsResponse, RevenueImportInvoicesCsvData, RevenueImportInvoicesCsvResponse, RevenueImportSubscriptionsCsvData, RevenueImportSubscriptionsCsvResponse, RevenueListIntegrationsData, RevenueListIntegrationsResponse, RevenueListProvidersData, RevenueListProvidersResponse, RevenueMetricsCustomersData, RevenueMetricsCustomersResponse, RevenueMetricsGlobalMrrData, RevenueMetricsGlobalMrrResponse, RevenueMetricsGlobalSummaryData, RevenueMetricsGlobalSummaryResponse, RevenueMetricsMrrData, RevenueMetricsMrrResponse, RevenueMetricsSummaryData, RevenueMetricsSummaryResponse, RevenueRecentEventsData, RevenueRecentEventsResponse, RevenueRotateTokenData, RevenueRotateTokenResponse, RevenueUpdateConfigData, RevenueUpdateConfigResponse, RevenueUpdateSecretData, RevenueUpdateSecretResponse, RevokeDsnData, RevokeDsnResponse, RevokeEnrollmentTokenData, RevokeEnrollmentTokenResponse, RevokeJoinTokenData, RevokeJoinTokenResponse, RevokeProjectAccessData, RevokeProjectAccessResponse, RollbackPgUpgradeData, RollbackPgUpgradeResponse, RollbackToDeploymentData, RollbackToDeploymentResponse, RootfsGcData, RootfsReportData, RotateApiKeyData, RotateApiKeyResponse, RotateDeploymentTokenData, RotateDeploymentTokenResponse, RunBackupForSourceData, RunBackupForSourceError, RunBackupForSourceResponse, RunConnectionHealthCheckData, RunConnectionHealthCheckResponse, RunExternalServiceBackupData, RunExternalServiceBackupError, RunExternalServiceBackupResponse, RunScheduleNowData, RunScheduleNowError, RunScheduleNowResponse, SandboxCreatePreviewLinkData, SandboxCreatePreviewLinkResponse, SaveAgentTokenData, SaveAgentTokenResponse2, SaveAiProviderCredentialData, SaveAiProviderCredentialResponse, SearchLogsData, SearchLogsError, SearchLogsResponse2, SendEmailData, SendEmailResponse, SetDefaultS3SourceData, SetDefaultS3SourceError, SetDefaultS3SourceResponse, SetFlagEnvironmentData, SetFlagEnvironmentResponse, SetPreviewPasswordData, SetPreviewPasswordResponse2, SetupDnsChallengeData, SetupDnsChallengeResponse2, SetupDnsData, SetupDnsResponse2, SetupEmailTrackingData, SetupEmailTrackingResponse, SetupMfaData, SetupMfaResponse, SleepEnvironmentData, SleepEnvironmentResponse, SmokeTestAgentData, SmokeTestAgentResponse, SourceSandboxData, SourceSandboxResponse, StartAnalysisData, StartAnalysisResponse, StartContainerData, StartContainerResponse, StartFixData, StartGitProviderOauthData, StartOidcLoginBySlugData, StartPgUpgradeData, StartPgUpgradeResponse, StartRestoreData, StartRestoreError, StartRestoreResponse, StartServiceData, StartServiceResponse, StatPathData, StatPathResponse, StopContainerData, StopContainerResponse, StopSandboxData, StopSandboxResponse, StopServiceData, StopServiceResponse, StreamContainerMetricsData, SyncRepositoriesData, SyncRepositoriesResponse, TailDeploymentJobLogsData, TailLogsData, TailLogsError, TeardownDeploymentData, TeardownDeploymentResponse, TeardownEnvironmentData, TeardownEnvironmentResponse, TestNotificationProviderData, TestNotificationProviderResponse, TestOidcProviderData, TestOidcProviderResponse, TestProviderConnectionData, TestProviderConnectionResponse, TestProviderData, TestProviderKeyByIdData, TestProviderKeyByIdError, TestProviderKeyByIdResponse, TestProviderKeyInlineData, TestProviderKeyInlineError, TestProviderKeyInlineResponse, TestProviderResponse2, TestS3ConnectionPreviewData, TestS3ConnectionPreviewError, TestS3ConnectionPreviewResponse, TestS3SourceConnectionData, TestS3SourceConnectionError, TestS3SourceConnectionResponse, TrackClickData, TrackOpenData, TriggerAgentData, TriggerAgentResponse, TriggerProjectPipelineData, TriggerProjectPipelineResponse, TriggerScanData, TriggerScanError, TriggerScanResponse2, TriggerServiceHealthCheckData, TriggerServiceHealthCheckResponse, TriggerWeeklyDigestData, TriggerWeeklyDigestResponse, UnlinkServiceFromProjectData, UnlinkServiceFromProjectResponse, UpdateAgentData, UpdateAgentResponse, UpdateAiProviderData, UpdateAiProviderResponse2, UpdateAlertData, UpdateAlertError, UpdateAlertResponse, UpdateAlertRuleData, UpdateAlertRuleResponse, UpdateApiKeyData, UpdateApiKeyResponse, UpdateAutomaticDeployData, UpdateAutomaticDeployResponse, UpdateBackupScheduleData, UpdateBackupScheduleError, UpdateBackupScheduleResponse, UpdateCloudflareProviderData, UpdateCloudflareProviderResponse, UpdateConnectionTokenData, UpdateConnectionTokenResponse, UpdateCustomDomainData, UpdateCustomDomainResponse, UpdateDashboardData, UpdateDashboardError, UpdateDashboardResponse, UpdateDeploymentTokenData, UpdateDeploymentTokenResponse, UpdateEmailProviderData, UpdateEmailProviderResponse, UpdateEnvironmentSettingsData, UpdateEnvironmentSettingsResponse, UpdateEnvironmentSubdomainData, UpdateEnvironmentSubdomainResponse, UpdateEnvironmentVariableData, UpdateEnvironmentVariableResponse, UpdateErrorGroupData, UpdateFlagData, UpdateFlagResponse, UpdateFunnelData, UpdateGitProviderCredentialsData, UpdateGitProviderCredentialsResponse, UpdateGitSettingsData, UpdateGitSettingsResponse, UpdateGlobalMcpData, UpdateGlobalMcpResponse, UpdateGlobalSkillData, UpdateGlobalSkillResponse, UpdateIncidentStatusData, UpdateIncidentStatusResponse, UpdateIpAccessControlData, UpdateIpAccessControlError, UpdateIpAccessControlResponse, UpdateManagedDomainData, UpdateManagedDomainResponse, UpdateMcpData, UpdateMcpResponse, UpdateNotificationEmailProviderData, UpdateNotificationEmailProviderResponse, UpdateNotificationProviderData, UpdateNotificationProviderResponse, UpdateOidcProviderData, UpdateOidcProviderResponse, UpdatePreferencesData, UpdatePreferencesResponse, UpdateProjectData, UpdateProjectDeploymentConfigData, UpdateProjectDeploymentConfigResponse, UpdateProjectResponse, UpdateProjectSecretData, UpdateProjectSecretResponse, UpdateProjectSettingsData, UpdateProjectSettingsResponse, UpdateProviderData, UpdateProviderKeyData, UpdateProviderKeyError, UpdateProviderKeyResponse, UpdateProviderResponse, UpdateRouteData, UpdateRouteResponse, UpdateS3SourceData, UpdateS3SourceError, UpdateS3SourceResponse, UpdateSelfData, UpdateSelfResponse, UpdateServiceData, UpdateServiceResourcesData, UpdateServiceResourcesResponse, UpdateServiceResponse, UpdateSessionDurationData, UpdateSessionDurationError, UpdateSessionDurationResponse2, UpdateSettingsData, UpdateSettingsResponse, UpdateSkillData, UpdateSkillResponse, UpdateSlackProviderData, UpdateSlackProviderResponse, UpdateSpeedMetricsData, UpdateSpeedMetricsError, UpdateSpeedMetricsResponse, UpdateTeamData, UpdateTeamMemberRoleData, UpdateTeamMemberRoleResponse, UpdateTeamResponse, UpdateUserData, UpdateUserResponse, UpdateWebhookData, UpdateWebhookProviderData, UpdateWebhookProviderResponse, UpdateWebhookResponse, UpgradePreviewGatewayData, UpgradePreviewGatewayResponse, UpgradeServiceData, UpgradeServiceResponse, UploadGlobalSkillData, UploadGlobalSkillResponse, UploadReleaseFileData, UploadReleaseFileResponse, UploadSkillData, UploadSkillResponse, UploadSourceFileData, UploadSourceFileResponse, UploadSourceMapData, UploadSourceMapResponse, UploadStaticBundleData, UploadStaticBundleResponse, UpsertSecretData, UpsertSecretResponse, ValidateConnectionData, ValidateConnectionResponse, ValidateEmailData, ValidateEmailResponse2, VerifyAndEnableMfaData, VerifyAndEnableMfaResponse, VerifyDomainData, VerifyDomainResponse, VerifyEmailData, VerifyEmailResponse, VerifyManagedDomainData, VerifyManagedDomainResponse, VerifyMfaChallengeData, VerifyMfaChallengeResponse, VerifyStepUpData, VerifyStepUpResponse, WakeEnvironmentData, WakeEnvironmentResponse, WebhookTriggerData, WebhookTriggerResponse2, WorkflowDryRunData, WorkflowDryRunResponse, WriteFileData, WriteFileResponse, WriteFilesData, WriteFilesResponse2 } from '../types.gen'; +import { acknowledgeAlarm, activateAiProvider, activateApiKey, activateConnection, activateProvider, addClusterMember, addContext, addEnvironmentDomain, addEvents, addManagedDomain, addSessionReplayEvents, addTeamMember, adminDrainNode, adminDrainStatus, adminGetNode, adminListNodeContainers, adminListNodes, adminRemoveNode, adminUndrainNode, applyHostnameMode, archiveConversation, archiveFlag, assignRole, attachScheduleServices, blobCopy, blobDelete, blobDisable, blobDownload, blobEnable, blobList, blobPut, blobStatus, blobUpdate, cancel, cancelBackup, cancelDeployment, cancelDomainOrder, cancelPgUpgrade, cancelRun, cancelScheduleRun, changePasswordSelf, changeProjectSource, chatCompletions, checkAnalyticsHasEvents, checkCommitExists, checkDomainStatus, checkExplorerSupport, checkIpBlocked, checkProviderDeletionSafety, chunkUploadOptions, cleanupExpiredBackups, clearPreviewPassword, cliDeviceApprove, cliDeviceDeny, cliDeviceLookup, cliDevicePoll, cliDeviceStart, cliLogout, cmd, cmdKill, cmdLogs, confirmPendingAction, containerMetricsGetHistory, createAgent, createAlert, createAlertRule, createApiKey, createBackupSchedule, createBitbucketProvider, createCloudflareProvider, createConversation, createCustomDomain, createDashboard, createDeploymentToken, createDnsProvider, createDomain, createDsn, createEmailDomain, createEmailProvider, createEnvironment, createEnvironmentVariable, createFlag, createFunnel, createGenericProvider, createGiteaPatProvider, createGithubPatProvider, createGitlabOauthProvider, createGitlabPatProvider, createGitProvider, createGlobalMcp, createGlobalSkill, createIncident, createIpAccessControl, createMcp, createMonitor, createNotificationEmailProvider, createNotificationProvider, createOidcProvider, createOidcRoleMapping, createOrRecreateOrder, createPlan, createPr, createProject, createProjectFromTemplate, createProjectRelease, createProjectSecret, createProviderKey, createRelease, createRoute, createS3Source, createSandbox, createService, createSkill, createSlackProvider, createTeam, createUser, createWebhook, createWebhookProvider, deactivateApiKey, deactivateConnection, deactivateProvider, deleteAgent, deleteAlert, deleteAlertRule, deleteApiKey, deleteBackup, deleteBackupSchedule, deleteConnection, deleteCustomDomain, deleteDashboard, deleteDeploymentToken, deleteDnsProvider, deleteDomain, deleteEmailDomain, deleteEmailProvider, deleteEnvironment, deleteEnvironmentDomain, deleteEnvironmentVariable, deleteExternalImage, deleteFunnel, deleteGitProvider, deleteGlobalMcp, deleteGlobalSkill, deleteIpAccessControl, deleteMcp, deleteMonitor, deleteNotificationProvider, deleteOidcProvider, deleteOidcRoleMapping, deletePreferences, deleteProject, deleteProjectSecret, deleteProviderKey, deleteProviderSafely, deleteReleaseSourceFiles, deleteReleaseSourceMaps, deleteRoute, deleteS3Source, deleteScan, deleteSecret, deleteService, deleteSessionReplay, deleteSkill, deleteSourceMap, deleteStaticBundle, deleteTeam, deleteUser, deleteWebhook, deployFromImage, deployFromImageUpload, deployFromStatic, deployFromUploadedSource, deploymentMetricsGetLatest, deploymentMetricsGetRange, deploymentMetricsToggle, destroySandbox, detachScheduleService, detectPublicPresets, disableBackupSchedule, disableMfa, disconnectCloud, discoverWorkloads, domain, downloadGlobalSkillArchive, downloadObject, downloadSkillArchive, emailStatus, embeddings, enableBackupSchedule, enrichVisitor, enrollCloud, exec, execDetached, executeDeploymentOperation, executeImport, extendTimeout, externalServiceEnablePgStatStatements, externalServiceMetricsByDatabase, externalServiceMetricsCreateAlertRule, externalServiceMetricsDeleteAlertRule, externalServiceMetricsGetAlertRules, externalServiceMetricsGetLatest, externalServiceMetricsGetRange, externalServiceMetricsStatus, externalServiceMetricsToggle, externalServiceMetricsUpdateAlertRule, externalServiceResetPgStatStatements, finalizeOrder, finalizeProjectRelease, findConversation, generateJoinToken, generatePresetDockerfile, getAccessInfo, getActiveVisitors, getActivityGraph, getAdminGate, getAgent, getAggregatedBuckets, getAiAgentBreakdown, getAiAgentPages, getAiAgentTimeline, getAiPageBreakdown, getAiStatusBreakdown, getAlert, getAlertRule, getAllRepositoriesByName, getAnalyticsActiveVisitors, getAnalyticsEventsCount, getAnalyticsSessionEvents, getAnalyticsVisitorSessions, getApiKey, getApiKeyPermissions, getAuditLog, getBackup, getBackupSchedule, getBranchesByRepositoryId, getBucketedIncidents, getBucketedStatus, getChallengeToken, getChatReadiness, getCliStatus, getCloudCapability, getCloudStatus, getClusterHealth, getClusterMember, getCmd, getContainerDetail, getContainerEnvironmentVariable, getContainerInfo, getContainerLogs, getContainerLogsById, getContainerMetrics, getConversation, getConversationDetail, getConversations, getCronById, getCronExecutions, getCrossProjectTraceSiblings, getCurrentMonitorStatus, getCurrentUser, getCustomDomain, getDashboard, getDashboardProjectsAnalytics, getDelivery, getDeployment, getDeploymentContainerLogContent, getDeploymentJobLogs, getDeploymentJobs, getDeploymentOperations, getDeploymentOperationStatus, getDeploymentToken, getDiskStatus, getDnsChanges, getDnsProvider, getDomain, getDomainByHost, getDomainById, getDomainByName, getDomainDnsRecords, getDomainOrder, getEmail, getEmailEvents, getEmailLinks, getEmailProvider, getEmailStats, getEmailTracking, getEmailTrackingStatus, getEntityInfo, getEnvironment, getEnvironmentCrons, getEnvironmentDomains, getEnvironments, getEnvironmentVariables, getEnvironmentVariableValue, getErrorDashboardStats, getErrorEvent, getErrorGroup, getErrorStats, getErrorTimeSeries, getEventDetail, getEventEntries, getEventsCount, getEventsTimeline, getEventTypeBreakdown, getEventVisitors, getExternalImage, getFile, getFlag, getFlagSnapshot, getFunnelMetrics, getGenaiTrace, getGeneralStats, getGitProvider, getGlobalEvents, getGlobalEventStats, getGlobalMcp, getGlobalSandboxStatus, getGlobalSkill, getGroupedPageMetrics, getHealth, getHourlyVisits, getHttpChallengeDebug, getImportStatus, getIncident, getIncidentUpdates, getIpAccessControl, getIpGeolocation, getJoinTokenStatus, getLastDeployment, getLatestScan, getLatestScansPerEnvironment, getLiveVisitorsList, getLogContext, getMcp, getMetricsOverTime, getMonitor, getNotificationProvider, getOnDemandCertStatus, getOrCreateDsn, getPageFlow, getPageHourlySessions, getPagePathDetail, getPagePaths, getPagePathsSparklines, getPagePathVisitors, getPendingAction, getPerformanceMetrics, getPgUpgrade, getPgUpgradeLogs, getPipelineStats, getPlatformInfo, getPostgresWalHealth, getPreferences, getPreviewGatewayLogs, getPreviewGatewaySettings, getPreviewGatewayStatus, getPricing, getPrivateIp, getProject, getProjectAlarmsSummary, getProjectBySlug, getProjectDeployments, getProjects, getProjectServiceEnvironmentVariables, getProjectSessionReplays, getProjectsHealth, getProjectsMonitorHealth, getProjectStatistics, getProjectTemplate, getPropertyBreakdown, getPropertyTimeline, getProviderConnections, getProviderMetadata, getProvidersMetadata, getProxyLogById, getProxyLogByRequestId, getProxyLogs, getPublicBranches, getPublicIp, getPublicRepository, getQuota, getRecentActivity, getRemoteExternalImage, getRepositoryBranches, getRepositoryById, getRepositoryByName, getRepositoryPresetByName, getRepositoryPresetLive, getRepositoryTags, getResolvedEnvironmentVariables, getResolvedEnvironmentVariableValue, getRestoreCapabilities, getRestoreRun, getRoute, getRun, getRunWithLogs, getS3Credentials, getS3Source, getSandbox, getSandboxStatus, getScan, getScanByDeployment, getScanVulnerabilities, getService, getServiceBySlug, getServiceEnvironmentVariable, getServiceEnvironmentVariables, getServiceHealthStatus, getServicePreviewEnvironmentVariableNames, getServicePreviewEnvironmentVariablesMasked, getServiceRuntime, getServiceStats, getServiceTypeParameters, getServiceTypes, getSessionDetails, getSessionEvents, getSessionLogs, getSessionReplay, getSessionReplayEvents, getSettings, getSkill, getSlowQueries, getStaticBundle, getStatusOverview, getTagsByRepositoryId, getTeam, getTimeBucketStats, getTodayStats, getTrace, getUnifiedTrace, getUniqueCounts, getUniqueEvents, getUpdateStatus, getUptimeHistory, getUsageByProvider, getUsageRecent, getUsageSummary, getUsageTimeseries, getUsageTopModels, getVisitorByGuid, getVisitorById, getVisitorDetails, getVisitorFacets, getVisitorInfo, getVisitorJourney, getVisitors, getVisitorSessions, getVisitorStats, getWebhook, grantProjectAccess, handleGitProviderOauthCallback, hasAnalyticsEvents, hasErrorGroups, hasPerformanceMetrics, importExternalService, ingestLogs, ingestLogsByPath, ingestMetrics, ingestMetricsByPath, ingestSentryEnvelope, ingestSentryEvent, ingestTraces, ingestTracesByPath, initSessionReplay, inspectDropArchive, jobLogs, jobStatus, killJob, kvDel, kvDisable, kvEnable, kvExpire, kvGet, kvIncr, kvKeys, kvSet, kvStatus, kvTtl, kvUpdate, latestRunForSource, linkCustomDomainToCertificate, linkServiceToProject, listAgentRuns, listAgents, listAiProviders, listAlertRules, listAlerts, listAllConversations, listAllRuns, listApiKeys, listAuditLogs, listAvailableContainers, listBackupAlerts, listBackupChildren, listBackupSchedules, listBackupsForSchedule, listCommitsByRepositoryId, listConnections, listContainers, listContainersAtPath, listConversations, listCustomDomainsForProject, listDashboards, listDeliveries, listDeploymentContainerLogs, listDeploymentTokens, listDnsProviders, listDomains, listDsns, listEmailDomains, listEmailProviders, listEmails, listEnrollmentTokens, listEntities, listErrorEvents, listErrorGroups, listEvents, listEventTypes, listExternalImages, listExternalPlugins, listExternalServiceBackups, listFlags, listFunnels, listGitProviders, listGlobalMcps, listGlobalSkills, listIncidents, listInsights, listIpAccessControl, listJobs, listKnownAiAgents, listManagedDomains, listMcps, listMetricLabelKeys, listMetricLabelValues, listMetricNames, listModels, listMonitors, listNotificationProviders, listOidcProviders, listOidcProviderUsers, listOidcRoleMappings, listOnDemandCerts, listOrders, listPeers, listPendingActions, listPgUpgrades, listPresets, listProjectAccess, listProjectAlarms, listProjectScans, listProjectSecrets, listProjectServices, listProjectTemplates, listProjectTemplateTags, listProviderKeys, listProviderZones, listPublicProviders, listReleaseFiles, listReleases, listRemoteExternalImages, listRepositoriesByConnection, listRepositoriesByProvider, listRestoreRunsForService, listRootContainers, listRoutes, listS3Sources, listSandboxes, listScheduleRunJobs, listScheduleRuns, listScheduleServices, listSecrets, listServiceHealthStatuses, listServiceProjects, listServices, listServiceSchedules, listSkills, listSourceBackups, listSourceFiles, listSourceMaps, listSources, listStaticBundles, listSyncedRepositories, listTeamMembers, listTeamProjects, listTeams, listUsers, listWebhooks, login, logout, lookupDnsARecords, mintEnrollmentToken, mkdir, nodeHeartbeat, nodeMetricsGetRange, observabilityFullEvent, observabilityListEvents, oidcCallback, type Options, patchAdminGate, patchPreviewGatewaySettings, pauseDeployment, pauseSandbox, planRestore, postDnsAck, previewAlert, previewFunnelMetrics, previewHostnameMode, promoteClusterMember, promoteDeployment, provisionDomain, purgeProjectLogs, pushExternalImage, queryData, queryGenaiTraces, queryLogs, queryMetrics, queryTraces, queryTraceSummaries, readFile, reAnalyze, recordConsoleEvent, recordEventMetrics, recordFlagExposure, recordSpeedMetrics, refreshRouteTable, regenerateDsn, registerExternalImage, registerNode, reinstallGitlabWebhook, rejectPendingAction, reloadPlugins, removeClusterMember, removeManagedDomain, removeRole, removeTeamMember, renameConversation, renewDomain, requestPasswordReset, resetPassword, resizeSandbox, resolveAlarm, restartContainer, restartPreviewGateway, restartSandbox, restoreFlag, restoreUser, resumeDeployment, resumeSandbox, retryCluster, retryDelivery, retryPgUpgrade, retryRun, revealGlobalMcpConfig, revealMcpConfig, revealNotificationProviderConfig, revealServiceParameter, revenueCreateIntegration, revenueDeleteIntegration, revenueGlobalEvents, revenueImportInvoicesCsv, revenueImportSubscriptionsCsv, revenueListIntegrations, revenueListProviders, revenueMetricsCustomers, revenueMetricsGlobalMrr, revenueMetricsGlobalSummary, revenueMetricsMrr, revenueMetricsSummary, revenueRecentEvents, revenueRotateToken, revenueUpdateConfig, revenueUpdateSecret, revokeDsn, revokeEnrollmentToken, revokeJoinToken, revokeProjectAccess, rollbackPgUpgrade, rollbackToDeployment, rootfsGc, rootfsReport, rotateApiKey, rotateDeploymentToken, runBackupForSource, runConnectionHealthCheck, runExternalServiceBackup, runScheduleNow, sandboxCreatePreviewLink, saveAgentToken, saveAiProviderCredential, searchLogs, sendEmail, setDefaultS3Source, setFlagEnvironment, setPreviewPassword, setupDns, setupDnsChallenge, setupEmailTracking, setupMfa, sleepEnvironment, smokeTestAgent, sourceSandbox, startAnalysis, startContainer, startFix, startGitProviderOauth, startOidcLoginBySlug, startPgUpgrade, startRestore, startService, statPath, stopContainer, stopSandbox, stopService, streamContainerMetrics, syncRepositories, tailDeploymentJobLogs, tailLogs, teardownDeployment, teardownEnvironment, testNotificationProvider, testOidcProvider, testProvider, testProviderConnection, testProviderKeyById, testProviderKeyInline, testS3ConnectionPreview, testS3SourceConnection, trackClick, trackOpen, triggerAgent, triggerProjectPipeline, triggerScan, triggerServiceHealthCheck, triggerWeeklyDigest, unlinkServiceFromProject, updateAgent, updateAiProvider, updateAlert, updateAlertRule, updateApiKey, updateAutomaticDeploy, updateBackupSchedule, updateCloudflareProvider, updateConnectionToken, updateCustomDomain, updateDashboard, updateDeploymentToken, updateEmailProvider, updateEnvironmentSettings, updateEnvironmentSubdomain, updateEnvironmentVariable, updateErrorGroup, updateFlag, updateFunnel, updateGitProviderCredentials, updateGitSettings, updateGlobalMcp, updateGlobalSkill, updateIncidentStatus, updateIpAccessControl, updateManagedDomain, updateMcp, updateNotificationEmailProvider, updateNotificationProvider, updateOidcProvider, updatePreferences, updateProject, updateProjectDeploymentConfig, updateProjectSecret, updateProjectSettings, updateProvider, updateProviderKey, updateRoute, updateS3Source, updateSelf, updateService, updateServiceResources, updateSessionDuration, updateSettings, updateSkill, updateSlackProvider, updateSpeedMetrics, updateTeam, updateTeamMemberRole, updateUser, updateWebhook, updateWebhookProvider, upgradePreviewGateway, upgradeService, uploadGlobalSkill, uploadReleaseFile, uploadSkill, uploadSourceFile, uploadSourceMap, uploadStaticBundle, upsertSecret, validateConnection, validateEmail, verifyAndEnableMfa, verifyDomain, verifyEmail, verifyManagedDomain, verifyMfaChallenge, verifyStepUp, wakeEnvironment, webhookTrigger, workflowDryRun, writeFile, writeFiles } from '../sdk.gen'; +import type { AcknowledgeAlarmData, ActivateAiProviderData, ActivateAiProviderResponse, ActivateApiKeyData, ActivateApiKeyResponse, ActivateConnectionData, ActivateProviderData, AddClusterMemberData, AddClusterMemberResponse, AddContextData, AddEnvironmentDomainData, AddEnvironmentDomainResponse, AddEventsData, AddEventsError, AddEventsResponse2, AddManagedDomainData, AddManagedDomainResponse, AddSessionReplayEventsData, AddSessionReplayEventsError, AddSessionReplayEventsResponse, AddTeamMemberData, AddTeamMemberResponse, AdminDrainNodeData, AdminDrainNodeResponse, AdminDrainStatusData, AdminDrainStatusResponse, AdminGetNodeData, AdminGetNodeResponse, AdminListNodeContainersData, AdminListNodeContainersResponse, AdminListNodesData, AdminListNodesResponse, AdminRemoveNodeData, AdminRemoveNodeResponse, AdminUndrainNodeData, AdminUndrainNodeResponse, ApplyHostnameModeData, ApplyHostnameModeResponse, ArchiveConversationData, ArchiveConversationResponse, ArchiveFlagData, ArchiveFlagResponse2, AssignRoleData, AttachScheduleServicesData, AttachScheduleServicesError, AttachScheduleServicesResponse2, BlobCopyData, BlobCopyError, BlobCopyResponse, BlobDeleteData, BlobDeleteError, BlobDeleteResponse, BlobDisableData, BlobDisableResponse, BlobDownloadData, BlobDownloadError, BlobEnableData, BlobEnableResponse, BlobListData, BlobListError, BlobListResponse, BlobPutData, BlobPutError, BlobPutResponse, BlobStatusData, BlobStatusResponse2, BlobUpdateData, BlobUpdateResponse, CancelBackupData, CancelBackupError, CancelBackupResponse2, CancelData, CancelDeploymentData, CancelDeploymentResponse, CancelDomainOrderData, CancelDomainOrderResponse, CancelPgUpgradeData, CancelPgUpgradeResponse, CancelRunData, CancelRunResponse, CancelScheduleRunData, CancelScheduleRunError, CancelScheduleRunResponse, ChangePasswordSelfData, ChangePasswordSelfResponse, ChangeProjectSourceData, ChangeProjectSourceResponse, ChatCompletionsData, ChatCompletionsError, ChatCompletionsResponse, CheckAnalyticsHasEventsData, CheckAnalyticsHasEventsResponse, CheckCommitExistsData, CheckCommitExistsResponse, CheckDomainStatusData, CheckDomainStatusResponse, CheckExplorerSupportData, CheckExplorerSupportResponse, CheckIpBlockedData, CheckIpBlockedError, CheckProviderDeletionSafetyData, CheckProviderDeletionSafetyResponse, ChunkUploadOptionsData, ChunkUploadOptionsResponse, CleanupExpiredBackupsData, CleanupExpiredBackupsError, CleanupExpiredBackupsResponse, ClearPreviewPasswordData, ClearPreviewPasswordResponse, CliDeviceApproveData, CliDeviceApproveResponse2, CliDeviceDenyData, CliDeviceDenyResponse, CliDeviceLookupData, CliDeviceLookupResponse2, CliDevicePollData, CliDevicePollResponse2, CliDeviceStartData, CliDeviceStartResponse2, CliLogoutData, CliLogoutResponse, CmdData, CmdKillData, CmdKillResponse, CmdLogsData, CmdResponse2, ConfirmPendingActionData, ConfirmPendingActionResponse, ContainerMetricsGetHistoryData, ContainerMetricsGetHistoryResponse, CreateAgentData, CreateAgentResponse, CreateAlertData, CreateAlertError, CreateAlertResponse, CreateAlertRuleData, CreateAlertRuleResponse, CreateApiKeyData, CreateApiKeyResponse2, CreateBackupScheduleData, CreateBackupScheduleError, CreateBackupScheduleResponse, CreateBitbucketProviderData, CreateBitbucketProviderResponse, CreateCloudflareProviderData, CreateCloudflareProviderResponse, CreateConversationData, CreateConversationResponse, CreateCustomDomainData, CreateCustomDomainResponse, CreateDashboardData, CreateDashboardError, CreateDashboardResponse, CreateDeploymentTokenData, CreateDeploymentTokenResponse2, CreateDnsProviderData, CreateDnsProviderResponse, CreateDomainData, CreateDomainResponse, CreateDsnData, CreateDsnResponse, CreateEmailDomainData, CreateEmailDomainResponse, CreateEmailProviderData, CreateEmailProviderResponse, CreateEnvironmentData, CreateEnvironmentResponse, CreateEnvironmentVariableData, CreateEnvironmentVariableResponse, CreateFlagData, CreateFlagResponse, CreateFunnelData, CreateFunnelResponse2, CreateGenericProviderData, CreateGenericProviderResponse, CreateGiteaPatProviderData, CreateGiteaPatProviderResponse, CreateGithubPatProviderData, CreateGithubPatProviderResponse, CreateGitlabOauthProviderData, CreateGitlabOauthProviderResponse, CreateGitlabPatProviderData, CreateGitlabPatProviderResponse, CreateGitProviderData, CreateGitProviderResponse, CreateGlobalMcpData, CreateGlobalMcpResponse, CreateGlobalSkillData, CreateGlobalSkillResponse, CreateIncidentData, CreateIncidentResponse, CreateIpAccessControlData, CreateIpAccessControlError, CreateIpAccessControlResponse, CreateMcpData, CreateMcpResponse, CreateMonitorData, CreateMonitorResponse, CreateNotificationEmailProviderData, CreateNotificationEmailProviderResponse, CreateNotificationProviderData, CreateNotificationProviderResponse, CreateOidcProviderData, CreateOidcProviderResponse, CreateOidcRoleMappingData, CreateOidcRoleMappingResponse, CreateOrRecreateOrderData, CreateOrRecreateOrderResponse, CreatePlanData, CreatePlanResponse2, CreatePrData, CreateProjectData, CreateProjectFromTemplateData, CreateProjectFromTemplateResponse2, CreateProjectReleaseData, CreateProjectReleaseResponse, CreateProjectResponse, CreateProjectSecretData, CreateProjectSecretResponse, CreateProviderKeyData, CreateProviderKeyError, CreateProviderKeyResponse, CreatePrResponse2, CreateReleaseData, CreateReleaseResponse, CreateRouteData, CreateRouteResponse, CreateS3SourceData, CreateS3SourceError, CreateS3SourceResponse, CreateSandboxData, CreateSandboxResponse, CreateServiceData, CreateServiceResponse, CreateSkillData, CreateSkillResponse, CreateSlackProviderData, CreateSlackProviderResponse, CreateTeamData, CreateTeamResponse, CreateUserData, CreateUserResponse, CreateWebhookData, CreateWebhookProviderData, CreateWebhookProviderResponse, CreateWebhookResponse, DeactivateApiKeyData, DeactivateApiKeyResponse, DeactivateConnectionData, DeactivateProviderData, DeleteAgentData, DeleteAgentResponse, DeleteAlertData, DeleteAlertError, DeleteAlertResponse, DeleteAlertRuleData, DeleteAlertRuleResponse, DeleteApiKeyData, DeleteApiKeyResponse, DeleteBackupData, DeleteBackupError, DeleteBackupResponse, DeleteBackupScheduleData, DeleteBackupScheduleError, DeleteBackupScheduleResponse, DeleteConnectionData, DeleteConnectionResponse, DeleteCustomDomainData, DeleteCustomDomainResponse, DeleteDashboardData, DeleteDashboardError, DeleteDashboardResponse, DeleteDeploymentTokenData, DeleteDeploymentTokenResponse, DeleteDnsProviderData, DeleteDnsProviderResponse, DeleteDomainData, DeleteDomainResponse, DeleteEmailDomainData, DeleteEmailDomainResponse, DeleteEmailProviderData, DeleteEmailProviderResponse, DeleteEnvironmentData, DeleteEnvironmentDomainData, DeleteEnvironmentDomainResponse, DeleteEnvironmentResponse, DeleteEnvironmentVariableData, DeleteEnvironmentVariableResponse, DeleteExternalImageData, DeleteExternalImageResponse, DeleteFunnelData, DeleteGitProviderData, DeleteGitProviderResponse, DeleteGlobalMcpData, DeleteGlobalMcpResponse, DeleteGlobalSkillData, DeleteGlobalSkillResponse, DeleteIpAccessControlData, DeleteIpAccessControlError, DeleteIpAccessControlResponse, DeleteMcpData, DeleteMcpResponse, DeleteMonitorData, DeleteMonitorResponse, DeleteNotificationProviderData, DeleteNotificationProviderResponse, DeleteOidcProviderData, DeleteOidcProviderResponse, DeleteOidcRoleMappingData, DeleteOidcRoleMappingResponse, DeletePreferencesData, DeletePreferencesResponse, DeleteProjectData, DeleteProjectResponse, DeleteProjectSecretData, DeleteProjectSecretResponse, DeleteProviderKeyData, DeleteProviderKeyError, DeleteProviderKeyResponse, DeleteProviderSafelyData, DeleteProviderSafelyResponse, DeleteReleaseSourceFilesData, DeleteReleaseSourceFilesResponse, DeleteReleaseSourceMapsData, DeleteReleaseSourceMapsResponse, DeleteRouteData, DeleteRouteResponse, DeleteS3SourceData, DeleteS3SourceError, DeleteS3SourceResponse, DeleteScanData, DeleteScanError, DeleteScanResponse, DeleteSecretData, DeleteSecretResponse, DeleteServiceData, DeleteServiceResponse, DeleteSessionReplayData, DeleteSessionReplayError, DeleteSkillData, DeleteSkillResponse, DeleteSourceMapData, DeleteSourceMapResponse, DeleteStaticBundleData, DeleteStaticBundleResponse, DeleteTeamData, DeleteTeamResponse, DeleteUserData, DeleteUserResponse, DeleteWebhookData, DeleteWebhookResponse, DeployFromImageData, DeployFromImageResponse, DeployFromImageUploadData, DeployFromImageUploadResponse, DeployFromStaticData, DeployFromStaticResponse, DeployFromUploadedSourceData, DeployFromUploadedSourceResponse, DeploymentMetricsGetLatestData, DeploymentMetricsGetLatestResponse, DeploymentMetricsGetRangeData, DeploymentMetricsGetRangeResponse, DeploymentMetricsToggleData, DestroySandboxData, DestroySandboxResponse, DetachScheduleServiceData, DetachScheduleServiceError, DetachScheduleServiceResponse, DetectPublicPresetsData, DetectPublicPresetsResponse, DisableBackupScheduleData, DisableBackupScheduleResponse, DisableMfaData, DisableMfaResponse, DisconnectCloudData, DisconnectCloudResponse, DiscoverWorkloadsData, DiscoverWorkloadsResponse, DomainData, DomainResponse2, DownloadGlobalSkillArchiveData, DownloadGlobalSkillArchiveResponse, DownloadObjectData, DownloadObjectResponse, DownloadSkillArchiveData, DownloadSkillArchiveResponse, EmailStatusData, EmailStatusResponse2, EmbeddingsData, EmbeddingsError, EmbeddingsResponse, EnableBackupScheduleData, EnableBackupScheduleResponse, EnrichVisitorData, EnrichVisitorResponse2, EnrollCloudData, EnrollCloudResponse, ExecData, ExecDetachedData, ExecDetachedResponse2, ExecResponse2, ExecuteDeploymentOperationData, ExecuteDeploymentOperationResponse, ExecuteImportData, ExecuteImportResponse2, ExtendTimeoutData, ExtendTimeoutResponse, ExternalServiceEnablePgStatStatementsData, ExternalServiceEnablePgStatStatementsResponse, ExternalServiceMetricsByDatabaseData, ExternalServiceMetricsByDatabaseResponse, ExternalServiceMetricsCreateAlertRuleData, ExternalServiceMetricsCreateAlertRuleResponse, ExternalServiceMetricsDeleteAlertRuleData, ExternalServiceMetricsDeleteAlertRuleResponse, ExternalServiceMetricsGetAlertRulesData, ExternalServiceMetricsGetAlertRulesResponse, ExternalServiceMetricsGetLatestData, ExternalServiceMetricsGetLatestResponse, ExternalServiceMetricsGetRangeData, ExternalServiceMetricsGetRangeResponse, ExternalServiceMetricsStatusData, ExternalServiceMetricsStatusResponse, ExternalServiceMetricsToggleData, ExternalServiceMetricsUpdateAlertRuleData, ExternalServiceMetricsUpdateAlertRuleResponse, ExternalServiceResetPgStatStatementsData, ExternalServiceResetPgStatStatementsResponse, FinalizeOrderData, FinalizeOrderResponse, FinalizeProjectReleaseData, FinalizeProjectReleaseResponse, FindConversationData, FindConversationResponse, GenerateJoinTokenData, GenerateJoinTokenResponse2, GeneratePresetDockerfileData, GeneratePresetDockerfileResponse, GetAccessInfoData, GetAccessInfoResponse, GetActiveVisitorsData, GetActiveVisitorsResponse, GetActivityGraphData, GetActivityGraphResponse, GetAdminGateData, GetAdminGateResponse, GetAgentData, GetAgentResponse, GetAggregatedBucketsData, GetAggregatedBucketsResponse, GetAiAgentBreakdownData, GetAiAgentBreakdownError, GetAiAgentBreakdownResponse, GetAiAgentPagesData, GetAiAgentPagesError, GetAiAgentPagesResponse, GetAiAgentTimelineData, GetAiAgentTimelineError, GetAiAgentTimelineResponse, GetAiPageBreakdownData, GetAiPageBreakdownError, GetAiPageBreakdownResponse, GetAiStatusBreakdownData, GetAiStatusBreakdownError, GetAiStatusBreakdownResponse, GetAlertData, GetAlertError, GetAlertResponse, GetAlertRuleData, GetAlertRuleResponse, GetAllRepositoriesByNameData, GetAllRepositoriesByNameResponse, GetAnalyticsActiveVisitorsData, GetAnalyticsActiveVisitorsResponse, GetAnalyticsEventsCountData, GetAnalyticsEventsCountResponse, GetAnalyticsSessionEventsData, GetAnalyticsSessionEventsResponse, GetAnalyticsVisitorSessionsData, GetAnalyticsVisitorSessionsResponse, GetApiKeyData, GetApiKeyPermissionsData, GetApiKeyPermissionsResponse, GetApiKeyResponse, GetAuditLogData, GetAuditLogResponse, GetBackupData, GetBackupError, GetBackupResponse, GetBackupScheduleData, GetBackupScheduleResponse, GetBranchesByRepositoryIdData, GetBranchesByRepositoryIdResponse, GetBucketedIncidentsData, GetBucketedIncidentsResponse, GetBucketedStatusData, GetBucketedStatusResponse, GetChallengeTokenData, GetChallengeTokenResponse, GetChatReadinessData, GetChatReadinessResponse, GetCliStatusData, GetCloudCapabilityData, GetCloudCapabilityResponse, GetCloudStatusData, GetCloudStatusResponse, GetClusterHealthData, GetClusterHealthResponse, GetClusterMemberData, GetClusterMemberResponse, GetCmdData, GetCmdResponse, GetContainerDetailData, GetContainerDetailResponse, GetContainerEnvironmentVariableData, GetContainerEnvironmentVariableResponse, GetContainerInfoData, GetContainerInfoResponse, GetContainerLogsByIdData, GetContainerLogsData, GetContainerMetricsData, GetContainerMetricsResponse, GetConversationData, GetConversationDetailData, GetConversationDetailError, GetConversationDetailResponse, GetConversationResponse, GetConversationsData, GetConversationsError, GetConversationsResponse, GetCronByIdData, GetCronByIdResponse, GetCronExecutionsData, GetCronExecutionsResponse, GetCrossProjectTraceSiblingsData, GetCrossProjectTraceSiblingsError, GetCrossProjectTraceSiblingsResponse, GetCurrentMonitorStatusData, GetCurrentMonitorStatusResponse, GetCurrentUserData, GetCurrentUserResponse, GetCustomDomainData, GetCustomDomainResponse, GetDashboardData, GetDashboardError, GetDashboardProjectsAnalyticsData, GetDashboardProjectsAnalyticsResponse, GetDashboardResponse, GetDeliveryData, GetDeliveryResponse, GetDeploymentContainerLogContentData, GetDeploymentContainerLogContentResponse, GetDeploymentData, GetDeploymentJobLogsData, GetDeploymentJobLogsResponse, GetDeploymentJobsData, GetDeploymentJobsResponse, GetDeploymentOperationsData, GetDeploymentOperationsResponse, GetDeploymentOperationStatusData, GetDeploymentOperationStatusResponse, GetDeploymentResponse, GetDeploymentTokenData, GetDeploymentTokenResponse, GetDiskStatusData, GetDiskStatusResponse, GetDnsChangesData, GetDnsChangesResponse, GetDnsProviderData, GetDnsProviderResponse, GetDomainByHostData, GetDomainByHostResponse, GetDomainByIdData, GetDomainByIdResponse, GetDomainByNameData, GetDomainByNameResponse, GetDomainData, GetDomainDnsRecordsData, GetDomainDnsRecordsResponse, GetDomainOrderData, GetDomainOrderResponse, GetDomainResponse, GetEmailData, GetEmailEventsData, GetEmailEventsResponse, GetEmailLinksData, GetEmailLinksResponse, GetEmailProviderData, GetEmailProviderResponse, GetEmailResponse, GetEmailStatsData, GetEmailStatsResponse, GetEmailTrackingData, GetEmailTrackingResponse, GetEmailTrackingStatusData, GetEmailTrackingStatusResponse, GetEntityInfoData, GetEntityInfoResponse, GetEnvironmentCronsData, GetEnvironmentCronsResponse, GetEnvironmentData, GetEnvironmentDomainsData, GetEnvironmentDomainsResponse, GetEnvironmentResponse, GetEnvironmentsData, GetEnvironmentsResponse, GetEnvironmentVariablesData, GetEnvironmentVariablesResponse, GetEnvironmentVariableValueData, GetEnvironmentVariableValueResponse, GetErrorDashboardStatsData, GetErrorDashboardStatsResponse, GetErrorEventData, GetErrorEventResponse, GetErrorGroupData, GetErrorGroupResponse, GetErrorStatsData, GetErrorStatsResponse, GetErrorTimeSeriesData, GetErrorTimeSeriesResponse, GetEventDetailData, GetEventDetailResponse, GetEventEntriesData, GetEventEntriesResponse, GetEventsCountData, GetEventsCountResponse, GetEventsTimelineData, GetEventsTimelineResponse, GetEventTypeBreakdownData, GetEventTypeBreakdownResponse, GetEventVisitorsData, GetEventVisitorsResponse, GetExternalImageData, GetExternalImageResponse, GetFileData, GetFileResponse, GetFlagData, GetFlagResponse, GetFlagSnapshotData, GetFlagSnapshotResponse, GetFunnelMetricsData, GetFunnelMetricsResponse, GetGenaiTraceData, GetGenaiTraceError, GetGenaiTraceResponse, GetGeneralStatsData, GetGeneralStatsResponse, GetGitProviderData, GetGitProviderResponse, GetGlobalEventsData, GetGlobalEventsResponse, GetGlobalEventStatsData, GetGlobalEventStatsResponse, GetGlobalMcpData, GetGlobalMcpResponse, GetGlobalSandboxStatusData, GetGlobalSandboxStatusResponse, GetGlobalSkillData, GetGlobalSkillResponse, GetGroupedPageMetricsData, GetGroupedPageMetricsError, GetGroupedPageMetricsResponse, GetHealthData, GetHealthError, GetHealthResponse, GetHourlyVisitsData, GetHourlyVisitsResponse, GetHttpChallengeDebugData, GetHttpChallengeDebugResponse, GetImportStatusData, GetImportStatusResponse, GetIncidentData, GetIncidentResponse, GetIncidentUpdatesData, GetIncidentUpdatesResponse, GetIpAccessControlData, GetIpAccessControlError, GetIpAccessControlResponse, GetIpGeolocationData, GetIpGeolocationError, GetIpGeolocationResponse, GetJoinTokenStatusData, GetJoinTokenStatusResponse, GetLastDeploymentData, GetLastDeploymentResponse, GetLatestScanData, GetLatestScanError, GetLatestScanResponse, GetLatestScansPerEnvironmentData, GetLatestScansPerEnvironmentError, GetLatestScansPerEnvironmentResponse, GetLiveVisitorsListData, GetLiveVisitorsListResponse, GetLogContextData, GetLogContextError, GetLogContextResponse, GetMcpData, GetMcpResponse, GetMetricsOverTimeData, GetMetricsOverTimeError, GetMetricsOverTimeResponse, GetMonitorData, GetMonitorResponse, GetNotificationProviderData, GetNotificationProviderResponse, GetOnDemandCertStatusData, GetOnDemandCertStatusResponse, GetOrCreateDsnData, GetOrCreateDsnResponse, GetPageFlowData, GetPageFlowResponse, GetPageHourlySessionsData, GetPageHourlySessionsResponse, GetPagePathDetailData, GetPagePathDetailResponse, GetPagePathsData, GetPagePathsResponse, GetPagePathsSparklinesData, GetPagePathsSparklinesResponse, GetPagePathVisitorsData, GetPagePathVisitorsResponse, GetPendingActionData, GetPendingActionResponse, GetPerformanceMetricsData, GetPerformanceMetricsError, GetPerformanceMetricsResponse, GetPgUpgradeData, GetPgUpgradeLogsData, GetPgUpgradeLogsResponse, GetPgUpgradeResponse, GetPipelineStatsData, GetPipelineStatsError, GetPipelineStatsResponse, GetPlatformInfoData, GetPlatformInfoResponse, GetPostgresWalHealthData, GetPostgresWalHealthResponse, GetPreferencesData, GetPreferencesResponse, GetPreviewGatewayLogsData, GetPreviewGatewayLogsResponse, GetPreviewGatewaySettingsData, GetPreviewGatewaySettingsResponse, GetPreviewGatewayStatusData, GetPreviewGatewayStatusResponse, GetPricingData, GetPricingError, GetPricingResponse, GetPrivateIpData, GetProjectAlarmsSummaryData, GetProjectAlarmsSummaryResponse, GetProjectBySlugData, GetProjectBySlugResponse, GetProjectData, GetProjectDeploymentsData, GetProjectDeploymentsResponse, GetProjectResponse, GetProjectsData, GetProjectServiceEnvironmentVariablesData, GetProjectServiceEnvironmentVariablesResponse, GetProjectSessionReplaysData, GetProjectSessionReplaysError, GetProjectSessionReplaysResponse2, GetProjectsHealthData, GetProjectsHealthError, GetProjectsHealthResponse, GetProjectsMonitorHealthData, GetProjectsMonitorHealthResponse, GetProjectsResponse, GetProjectStatisticsData, GetProjectStatisticsResponse, GetProjectTemplateData, GetProjectTemplateResponse, GetPropertyBreakdownData, GetPropertyBreakdownResponse, GetPropertyTimelineData, GetPropertyTimelineResponse, GetProviderConnectionsData, GetProviderConnectionsResponse, GetProviderMetadataData, GetProviderMetadataResponse, GetProvidersMetadataData, GetProvidersMetadataResponse, GetProxyLogByIdData, GetProxyLogByIdError, GetProxyLogByIdResponse, GetProxyLogByRequestIdData, GetProxyLogByRequestIdError, GetProxyLogByRequestIdResponse, GetProxyLogsData, GetProxyLogsError, GetProxyLogsResponse, GetPublicBranchesData, GetPublicBranchesResponse, GetPublicIpData, GetPublicRepositoryData, GetPublicRepositoryResponse, GetQuotaData, GetQuotaError, GetQuotaResponse, GetRecentActivityData, GetRecentActivityResponse, GetRemoteExternalImageData, GetRemoteExternalImageResponse, GetRepositoryBranchesData, GetRepositoryBranchesResponse, GetRepositoryByIdData, GetRepositoryByIdResponse, GetRepositoryByNameData, GetRepositoryByNameResponse, GetRepositoryPresetByNameData, GetRepositoryPresetByNameResponse, GetRepositoryPresetLiveData, GetRepositoryPresetLiveResponse, GetRepositoryTagsData, GetRepositoryTagsResponse, GetResolvedEnvironmentVariablesData, GetResolvedEnvironmentVariablesResponse, GetResolvedEnvironmentVariableValueData, GetResolvedEnvironmentVariableValueResponse, GetRestoreCapabilitiesData, GetRestoreCapabilitiesError, GetRestoreCapabilitiesResponse, GetRestoreRunData, GetRestoreRunError, GetRestoreRunResponse, GetRouteData, GetRouteResponse, GetRunData, GetRunResponse, GetRunWithLogsData, GetRunWithLogsResponse, GetS3CredentialsData, GetS3CredentialsResponse, GetS3SourceData, GetS3SourceError, GetS3SourceResponse, GetSandboxData, GetSandboxResponse, GetSandboxStatusData, GetSandboxStatusResponse, GetScanByDeploymentData, GetScanByDeploymentError, GetScanByDeploymentResponse, GetScanData, GetScanError, GetScanResponse, GetScanVulnerabilitiesData, GetScanVulnerabilitiesError, GetScanVulnerabilitiesResponse, GetServiceBySlugData, GetServiceBySlugResponse, GetServiceData, GetServiceEnvironmentVariableData, GetServiceEnvironmentVariableResponse, GetServiceEnvironmentVariablesData, GetServiceEnvironmentVariablesResponse, GetServiceHealthStatusData, GetServiceHealthStatusResponse, GetServicePreviewEnvironmentVariableNamesData, GetServicePreviewEnvironmentVariableNamesResponse, GetServicePreviewEnvironmentVariablesMaskedData, GetServicePreviewEnvironmentVariablesMaskedResponse, GetServiceResponse, GetServiceRuntimeData, GetServiceRuntimeResponse, GetServiceStatsData, GetServiceStatsResponse, GetServiceTypeParametersData, GetServiceTypesData, GetServiceTypesResponse, GetSessionDetailsData, GetSessionDetailsResponse, GetSessionEventsData, GetSessionEventsResponse, GetSessionLogsData, GetSessionLogsResponse, GetSessionReplayData, GetSessionReplayError, GetSessionReplayEventsData, GetSessionReplayEventsError, GetSessionReplayEventsResponse, GetSessionReplayResponse2, GetSettingsData, GetSettingsResponse, GetSkillData, GetSkillResponse, GetSlowQueriesData, GetSlowQueriesResponse, GetStaticBundleData, GetStaticBundleResponse, GetStatusOverviewData, GetStatusOverviewResponse, GetTagsByRepositoryIdData, GetTagsByRepositoryIdResponse, GetTeamData, GetTeamResponse, GetTimeBucketStatsData, GetTimeBucketStatsError, GetTimeBucketStatsResponse, GetTodayStatsData, GetTodayStatsError, GetTodayStatsResponse, GetTraceData, GetTraceError, GetTraceResponse, GetUnifiedTraceData, GetUnifiedTraceError, GetUnifiedTraceResponse, GetUniqueCountsData, GetUniqueCountsResponse, GetUniqueEventsData, GetUniqueEventsResponse, GetUpdateStatusData, GetUpdateStatusResponse, GetUptimeHistoryData, GetUptimeHistoryResponse, GetUsageByProviderData, GetUsageByProviderError, GetUsageByProviderResponse, GetUsageRecentData, GetUsageRecentError, GetUsageRecentResponse, GetUsageSummaryData, GetUsageSummaryError, GetUsageSummaryResponse, GetUsageTimeseriesData, GetUsageTimeseriesError, GetUsageTimeseriesResponse, GetUsageTopModelsData, GetUsageTopModelsError, GetUsageTopModelsResponse, GetVisitorByGuidData, GetVisitorByGuidResponse, GetVisitorByIdData, GetVisitorByIdResponse, GetVisitorDetailsData, GetVisitorDetailsResponse, GetVisitorFacetsData, GetVisitorFacetsResponse, GetVisitorInfoData, GetVisitorInfoResponse, GetVisitorJourneyData, GetVisitorJourneyResponse, GetVisitorsData, GetVisitorSessionsData, GetVisitorSessionsError, GetVisitorSessionsResponse2, GetVisitorsResponse, GetVisitorStatsData, GetVisitorStatsResponse, GetWebhookData, GetWebhookResponse, GrantProjectAccessData, GrantProjectAccessResponse, HandleGitProviderOauthCallbackData, HasAnalyticsEventsData, HasAnalyticsEventsResponse2, HasErrorGroupsData, HasErrorGroupsResponse2, HasPerformanceMetricsData, HasPerformanceMetricsError, HasPerformanceMetricsResponse, ImportExternalServiceData, ImportExternalServiceResponse, IngestLogsByPathData, IngestLogsByPathError, IngestLogsData, IngestLogsError, IngestMetricsByPathData, IngestMetricsByPathError, IngestMetricsData, IngestMetricsError, IngestSentryEnvelopeData, IngestSentryEventData, IngestSentryEventResponse, IngestTracesByPathData, IngestTracesByPathError, IngestTracesData, IngestTracesError, InitSessionReplayData, InitSessionReplayError, InitSessionReplayResponse, InspectDropArchiveData, InspectDropArchiveResponse, JobLogsData, JobStatusData, JobStatusResponse2, KillJobData, KillJobResponse, KvDelData, KvDelResponse, KvDisableData, KvDisableResponse, KvEnableData, KvEnableResponse, KvExpireData, KvExpireResponse, KvGetData, KvGetResponse, KvIncrData, KvIncrResponse, KvKeysData, KvKeysResponse, KvSetData, KvSetResponse, KvStatusData, KvStatusResponse2, KvTtlData, KvTtlResponse, KvUpdateData, KvUpdateResponse, LatestRunForSourceData, LatestRunForSourceResponse, LinkCustomDomainToCertificateData, LinkCustomDomainToCertificateResponse, LinkServiceToProjectData, LinkServiceToProjectResponse, ListAgentRunsData, ListAgentRunsResponse, ListAgentsData, ListAgentsResponse2, ListAiProvidersData, ListAiProvidersResponse, ListAlertRulesData, ListAlertRulesResponse, ListAlertsData, ListAlertsError, ListAlertsResponse, ListAllConversationsData, ListAllConversationsResponse, ListAllRunsData, ListAllRunsResponse, ListApiKeysData, ListApiKeysResponse, ListAuditLogsData, ListAuditLogsResponse, ListAvailableContainersData, ListAvailableContainersResponse, ListBackupAlertsData, ListBackupAlertsError, ListBackupAlertsResponse, ListBackupChildrenData, ListBackupChildrenError, ListBackupChildrenResponse, ListBackupSchedulesData, ListBackupSchedulesError, ListBackupSchedulesResponse, ListBackupsForScheduleData, ListBackupsForScheduleResponse, ListCommitsByRepositoryIdData, ListCommitsByRepositoryIdResponse, ListConnectionsData, ListConnectionsResponse, ListContainersAtPathData, ListContainersAtPathResponse, ListContainersData, ListContainersResponse, ListConversationsData, ListConversationsResponse, ListCustomDomainsForProjectData, ListCustomDomainsForProjectResponse, ListDashboardsData, ListDashboardsError, ListDashboardsResponse, ListDeliveriesData, ListDeliveriesResponse, ListDeploymentContainerLogsData, ListDeploymentContainerLogsResponse, ListDeploymentTokensData, ListDeploymentTokensResponse, ListDnsProvidersData, ListDnsProvidersResponse, ListDomainsData, ListDomainsResponse2, ListDsnsData, ListDsnsResponse, ListEmailDomainsData, ListEmailDomainsResponse, ListEmailProvidersData, ListEmailProvidersResponse, ListEmailsData, ListEmailsResponse, ListEnrollmentTokensData, ListEnrollmentTokensResponse, ListEntitiesData, ListEntitiesResponse, ListErrorEventsData, ListErrorEventsResponse, ListErrorGroupsData, ListErrorGroupsResponse, ListEventsData, ListEventsResponse, ListEventTypesData, ListEventTypesResponse, ListExternalImagesData, ListExternalImagesResponse, ListExternalPluginsData, ListExternalPluginsResponse, ListExternalServiceBackupsData, ListExternalServiceBackupsError, ListExternalServiceBackupsResponse, ListFlagsData, ListFlagsResponse, ListFunnelsData, ListFunnelsResponse, ListGitProvidersData, ListGitProvidersResponse, ListGlobalMcpsData, ListGlobalMcpsResponse, ListGlobalSkillsData, ListGlobalSkillsResponse, ListIncidentsData, ListInsightsData, ListInsightsError, ListInsightsResponse, ListIpAccessControlData, ListIpAccessControlError, ListIpAccessControlResponse, ListJobsData, ListJobsResponse2, ListKnownAiAgentsData, ListKnownAiAgentsError, ListKnownAiAgentsResponse, ListManagedDomainsData, ListManagedDomainsResponse, ListMcpsData, ListMcpsResponse2, ListMetricLabelKeysData, ListMetricLabelKeysError, ListMetricLabelKeysResponse, ListMetricLabelValuesData, ListMetricLabelValuesError, ListMetricLabelValuesResponse, ListMetricNamesData, ListMetricNamesError, ListMetricNamesResponse, ListModelsData, ListModelsError, ListModelsResponse, ListMonitorsData, ListMonitorsResponse, ListNotificationProvidersData, ListNotificationProvidersResponse, ListOidcProvidersData, ListOidcProvidersResponse, ListOidcProviderUsersData, ListOidcProviderUsersResponse, ListOidcRoleMappingsData, ListOidcRoleMappingsResponse, ListOnDemandCertsData, ListOnDemandCertsResponse2, ListOrdersData, ListOrdersResponse2, ListPeersData, ListPeersResponse, ListPendingActionsData, ListPendingActionsResponse, ListPgUpgradesData, ListPgUpgradesResponse, ListPresetsData, ListPresetsResponse2, ListProjectAccessData, ListProjectAccessResponse, ListProjectAlarmsData, ListProjectAlarmsResponse, ListProjectScansData, ListProjectScansError, ListProjectScansResponse, ListProjectSecretsData, ListProjectSecretsResponse, ListProjectServicesData, ListProjectServicesResponse, ListProjectTemplatesData, ListProjectTemplatesResponse, ListProjectTemplateTagsData, ListProjectTemplateTagsResponse, ListProviderKeysData, ListProviderKeysError, ListProviderKeysResponse, ListProviderZonesData, ListProviderZonesResponse, ListPublicProvidersData, ListPublicProvidersResponse, ListReleaseFilesData, ListReleaseFilesResponse, ListReleasesData, ListReleasesResponse, ListRemoteExternalImagesData, ListRemoteExternalImagesResponse, ListRepositoriesByConnectionData, ListRepositoriesByConnectionResponse, ListRepositoriesByProviderData, ListRepositoriesByProviderResponse, ListRestoreRunsForServiceData, ListRestoreRunsForServiceResponse, ListRootContainersData, ListRootContainersResponse, ListRoutesData, ListRoutesResponse, ListS3SourcesData, ListS3SourcesError, ListS3SourcesResponse, ListSandboxesData, ListSandboxesResponse2, ListScheduleRunJobsData, ListScheduleRunJobsError, ListScheduleRunJobsResponse, ListScheduleRunsData, ListScheduleRunsError, ListScheduleRunsResponse, ListScheduleServicesData, ListScheduleServicesError, ListScheduleServicesResponse, ListSecretsData, ListSecretsResponse2, ListServiceHealthStatusesData, ListServiceHealthStatusesResponse, ListServiceProjectsData, ListServiceProjectsResponse, ListServiceSchedulesData, ListServiceSchedulesError, ListServiceSchedulesResponse, ListServicesData, ListServicesResponse, ListSkillsData, ListSkillsResponse2, ListSourceBackupsData, ListSourceBackupsError, ListSourceBackupsResponse, ListSourceFilesData, ListSourceFilesResponse, ListSourceMapsData, ListSourceMapsResponse, ListSourcesData, ListSourcesResponse, ListStaticBundlesData, ListStaticBundlesResponse, ListSyncedRepositoriesData, ListSyncedRepositoriesResponse, ListTeamMembersData, ListTeamMembersResponse, ListTeamProjectsData, ListTeamProjectsResponse, ListTeamsData, ListTeamsResponse, ListUsersData, ListUsersResponse, ListWebhooksData, ListWebhooksResponse, LoginData, LoginResponse, LogoutData, LookupDnsARecordsData, LookupDnsARecordsError, LookupDnsARecordsResponse, MintEnrollmentTokenData, MintEnrollmentTokenResponse2, MkdirData, MkdirResponse, NodeHeartbeatData, NodeHeartbeatResponse, NodeMetricsGetRangeData, NodeMetricsGetRangeResponse, ObservabilityFullEventData, ObservabilityFullEventError, ObservabilityFullEventResponse, ObservabilityListEventsData, ObservabilityListEventsError, ObservabilityListEventsResponse, OidcCallbackData, PatchAdminGateData, PatchAdminGateResponse, PatchPreviewGatewaySettingsData, PatchPreviewGatewaySettingsResponse, PauseDeploymentData, PauseDeploymentResponse, PauseSandboxData, PauseSandboxResponse, PlanRestoreData, PlanRestoreError, PlanRestoreResponse, PostDnsAckData, PostDnsAckResponse, PreviewAlertData, PreviewAlertError, PreviewAlertResponse, PreviewFunnelMetricsData, PreviewFunnelMetricsResponse, PreviewHostnameModeData, PreviewHostnameModeResponse, PromoteClusterMemberData, PromoteDeploymentData, PromoteDeploymentResponse, ProvisionDomainData, ProvisionDomainResponse, PurgeProjectLogsData, PurgeProjectLogsError, PushExternalImageData, PushExternalImageResponse, QueryDataData, QueryDataResponse2, QueryGenaiTracesData, QueryGenaiTracesError, QueryGenaiTracesResponse, QueryLogsData, QueryLogsError, QueryLogsResponse, QueryMetricsData, QueryMetricsError, QueryMetricsResponse, QueryTracesData, QueryTracesError, QueryTracesResponse, QueryTraceSummariesData, QueryTraceSummariesError, QueryTraceSummariesResponse, ReadFileData, ReadFileResponse2, ReAnalyzeData, RecordConsoleEventData, RecordEventMetricsData, RecordEventMetricsResponse, RecordFlagExposureData, RecordFlagExposureResponse, RecordSpeedMetricsData, RecordSpeedMetricsError, RecordSpeedMetricsResponse, RefreshRouteTableData, RefreshRouteTableResponse, RegenerateDsnData, RegenerateDsnResponse, RegisterExternalImageData, RegisterExternalImageResponse, RegisterNodeData, RegisterNodeResponse2, ReinstallGitlabWebhookData, ReinstallGitlabWebhookResponse, RejectPendingActionData, RejectPendingActionResponse, ReloadPluginsData, ReloadPluginsResponse, RemoveClusterMemberData, RemoveClusterMemberResponse, RemoveManagedDomainData, RemoveManagedDomainResponse, RemoveRoleData, RemoveRoleResponse, RemoveTeamMemberData, RemoveTeamMemberResponse, RenameConversationData, RenameConversationResponse, RenewDomainData, RenewDomainResponse, RequestPasswordResetData, RequestPasswordResetResponse, ResetPasswordData, ResetPasswordResponse, ResizeSandboxData, ResizeSandboxResponse, ResolveAlarmData, RestartContainerData, RestartContainerResponse, RestartPreviewGatewayData, RestartPreviewGatewayResponse, RestartSandboxData, RestartSandboxResponse, RestoreFlagData, RestoreFlagResponse, RestoreUserData, RestoreUserResponse, ResumeDeploymentData, ResumeDeploymentResponse, ResumeSandboxData, ResumeSandboxResponse, RetryClusterData, RetryClusterResponse, RetryDeliveryData, RetryDeliveryResponse, RetryPgUpgradeData, RetryPgUpgradeResponse, RetryRunData, RetryRunResponse, RevealGlobalMcpConfigData, RevealGlobalMcpConfigResponse, RevealMcpConfigData, RevealMcpConfigResponse, RevealNotificationProviderConfigData, RevealNotificationProviderConfigResponse, RevealServiceParameterData, RevealServiceParameterResponse, RevenueCreateIntegrationData, RevenueCreateIntegrationResponse, RevenueDeleteIntegrationData, RevenueDeleteIntegrationResponse, RevenueGlobalEventsData, RevenueGlobalEventsResponse, RevenueImportInvoicesCsvData, RevenueImportInvoicesCsvResponse, RevenueImportSubscriptionsCsvData, RevenueImportSubscriptionsCsvResponse, RevenueListIntegrationsData, RevenueListIntegrationsResponse, RevenueListProvidersData, RevenueListProvidersResponse, RevenueMetricsCustomersData, RevenueMetricsCustomersResponse, RevenueMetricsGlobalMrrData, RevenueMetricsGlobalMrrResponse, RevenueMetricsGlobalSummaryData, RevenueMetricsGlobalSummaryResponse, RevenueMetricsMrrData, RevenueMetricsMrrResponse, RevenueMetricsSummaryData, RevenueMetricsSummaryResponse, RevenueRecentEventsData, RevenueRecentEventsResponse, RevenueRotateTokenData, RevenueRotateTokenResponse, RevenueUpdateConfigData, RevenueUpdateConfigResponse, RevenueUpdateSecretData, RevenueUpdateSecretResponse, RevokeDsnData, RevokeDsnResponse, RevokeEnrollmentTokenData, RevokeEnrollmentTokenResponse, RevokeJoinTokenData, RevokeJoinTokenResponse, RevokeProjectAccessData, RevokeProjectAccessResponse, RollbackPgUpgradeData, RollbackPgUpgradeResponse, RollbackToDeploymentData, RollbackToDeploymentResponse, RootfsGcData, RootfsReportData, RotateApiKeyData, RotateApiKeyResponse, RotateDeploymentTokenData, RotateDeploymentTokenResponse, RunBackupForSourceData, RunBackupForSourceError, RunBackupForSourceResponse, RunConnectionHealthCheckData, RunConnectionHealthCheckResponse, RunExternalServiceBackupData, RunExternalServiceBackupError, RunExternalServiceBackupResponse, RunScheduleNowData, RunScheduleNowError, RunScheduleNowResponse, SandboxCreatePreviewLinkData, SandboxCreatePreviewLinkResponse, SaveAgentTokenData, SaveAgentTokenResponse2, SaveAiProviderCredentialData, SaveAiProviderCredentialResponse, SearchLogsData, SearchLogsError, SearchLogsResponse2, SendEmailData, SendEmailResponse, SetDefaultS3SourceData, SetDefaultS3SourceError, SetDefaultS3SourceResponse, SetFlagEnvironmentData, SetFlagEnvironmentResponse, SetPreviewPasswordData, SetPreviewPasswordResponse2, SetupDnsChallengeData, SetupDnsChallengeResponse2, SetupDnsData, SetupDnsResponse2, SetupEmailTrackingData, SetupEmailTrackingResponse, SetupMfaData, SetupMfaResponse, SleepEnvironmentData, SleepEnvironmentResponse, SmokeTestAgentData, SmokeTestAgentResponse, SourceSandboxData, SourceSandboxResponse, StartAnalysisData, StartAnalysisResponse, StartContainerData, StartContainerResponse, StartFixData, StartGitProviderOauthData, StartOidcLoginBySlugData, StartPgUpgradeData, StartPgUpgradeResponse, StartRestoreData, StartRestoreError, StartRestoreResponse, StartServiceData, StartServiceResponse, StatPathData, StatPathResponse, StopContainerData, StopContainerResponse, StopSandboxData, StopSandboxResponse, StopServiceData, StopServiceResponse, StreamContainerMetricsData, SyncRepositoriesData, SyncRepositoriesResponse, TailDeploymentJobLogsData, TailLogsData, TailLogsError, TeardownDeploymentData, TeardownDeploymentResponse, TeardownEnvironmentData, TeardownEnvironmentResponse, TestNotificationProviderData, TestNotificationProviderResponse, TestOidcProviderData, TestOidcProviderResponse, TestProviderConnectionData, TestProviderConnectionResponse, TestProviderData, TestProviderKeyByIdData, TestProviderKeyByIdError, TestProviderKeyByIdResponse, TestProviderKeyInlineData, TestProviderKeyInlineError, TestProviderKeyInlineResponse, TestProviderResponse2, TestS3ConnectionPreviewData, TestS3ConnectionPreviewError, TestS3ConnectionPreviewResponse, TestS3SourceConnectionData, TestS3SourceConnectionError, TestS3SourceConnectionResponse, TrackClickData, TrackOpenData, TriggerAgentData, TriggerAgentResponse, TriggerProjectPipelineData, TriggerProjectPipelineResponse, TriggerScanData, TriggerScanError, TriggerScanResponse2, TriggerServiceHealthCheckData, TriggerServiceHealthCheckResponse, TriggerWeeklyDigestData, TriggerWeeklyDigestResponse, UnlinkServiceFromProjectData, UnlinkServiceFromProjectResponse, UpdateAgentData, UpdateAgentResponse, UpdateAiProviderData, UpdateAiProviderResponse2, UpdateAlertData, UpdateAlertError, UpdateAlertResponse, UpdateAlertRuleData, UpdateAlertRuleResponse, UpdateApiKeyData, UpdateApiKeyResponse, UpdateAutomaticDeployData, UpdateAutomaticDeployResponse, UpdateBackupScheduleData, UpdateBackupScheduleError, UpdateBackupScheduleResponse, UpdateCloudflareProviderData, UpdateCloudflareProviderResponse, UpdateConnectionTokenData, UpdateConnectionTokenResponse, UpdateCustomDomainData, UpdateCustomDomainResponse, UpdateDashboardData, UpdateDashboardError, UpdateDashboardResponse, UpdateDeploymentTokenData, UpdateDeploymentTokenResponse, UpdateEmailProviderData, UpdateEmailProviderResponse, UpdateEnvironmentSettingsData, UpdateEnvironmentSettingsResponse, UpdateEnvironmentSubdomainData, UpdateEnvironmentSubdomainResponse, UpdateEnvironmentVariableData, UpdateEnvironmentVariableResponse, UpdateErrorGroupData, UpdateFlagData, UpdateFlagResponse, UpdateFunnelData, UpdateGitProviderCredentialsData, UpdateGitProviderCredentialsResponse, UpdateGitSettingsData, UpdateGitSettingsResponse, UpdateGlobalMcpData, UpdateGlobalMcpResponse, UpdateGlobalSkillData, UpdateGlobalSkillResponse, UpdateIncidentStatusData, UpdateIncidentStatusResponse, UpdateIpAccessControlData, UpdateIpAccessControlError, UpdateIpAccessControlResponse, UpdateManagedDomainData, UpdateManagedDomainResponse, UpdateMcpData, UpdateMcpResponse, UpdateNotificationEmailProviderData, UpdateNotificationEmailProviderResponse, UpdateNotificationProviderData, UpdateNotificationProviderResponse, UpdateOidcProviderData, UpdateOidcProviderResponse, UpdatePreferencesData, UpdatePreferencesResponse, UpdateProjectData, UpdateProjectDeploymentConfigData, UpdateProjectDeploymentConfigResponse, UpdateProjectResponse, UpdateProjectSecretData, UpdateProjectSecretResponse, UpdateProjectSettingsData, UpdateProjectSettingsResponse, UpdateProviderData, UpdateProviderKeyData, UpdateProviderKeyError, UpdateProviderKeyResponse, UpdateProviderResponse, UpdateRouteData, UpdateRouteResponse, UpdateS3SourceData, UpdateS3SourceError, UpdateS3SourceResponse, UpdateSelfData, UpdateSelfResponse, UpdateServiceData, UpdateServiceResourcesData, UpdateServiceResourcesResponse, UpdateServiceResponse, UpdateSessionDurationData, UpdateSessionDurationError, UpdateSessionDurationResponse2, UpdateSettingsData, UpdateSettingsResponse, UpdateSkillData, UpdateSkillResponse, UpdateSlackProviderData, UpdateSlackProviderResponse, UpdateSpeedMetricsData, UpdateSpeedMetricsError, UpdateSpeedMetricsResponse, UpdateTeamData, UpdateTeamMemberRoleData, UpdateTeamMemberRoleResponse, UpdateTeamResponse, UpdateUserData, UpdateUserResponse, UpdateWebhookData, UpdateWebhookProviderData, UpdateWebhookProviderResponse, UpdateWebhookResponse, UpgradePreviewGatewayData, UpgradePreviewGatewayResponse, UpgradeServiceData, UpgradeServiceResponse, UploadGlobalSkillData, UploadGlobalSkillResponse, UploadReleaseFileData, UploadReleaseFileResponse, UploadSkillData, UploadSkillResponse, UploadSourceFileData, UploadSourceFileResponse, UploadSourceMapData, UploadSourceMapResponse, UploadStaticBundleData, UploadStaticBundleResponse, UpsertSecretData, UpsertSecretResponse, ValidateConnectionData, ValidateConnectionResponse, ValidateEmailData, ValidateEmailResponse2, VerifyAndEnableMfaData, VerifyAndEnableMfaResponse, VerifyDomainData, VerifyDomainResponse, VerifyEmailData, VerifyEmailResponse, VerifyManagedDomainData, VerifyManagedDomainResponse, VerifyMfaChallengeData, VerifyMfaChallengeResponse, VerifyStepUpData, VerifyStepUpResponse, WakeEnvironmentData, WakeEnvironmentResponse, WebhookTriggerData, WebhookTriggerResponse2, WorkflowDryRunData, WorkflowDryRunResponse, WriteFileData, WriteFileResponse, WriteFilesData, WriteFilesResponse2 } from '../types.gen'; export type QueryKey = [ Pick & { @@ -2749,6 +2749,64 @@ export const blobDownloadOptions = (options: Options) => query queryKey: blobDownloadQueryKey(options) }); +export const disconnectCloudMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await disconnectCloud({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const getCloudCapabilityQueryKey = (options?: Options) => createQueryKey('getCloudCapability', options); + +export const getCloudCapabilityOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getCloudCapability({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getCloudCapabilityQueryKey(options) +}); + +export const enrollCloudMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await enrollCloud({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const getCloudStatusQueryKey = (options?: Options) => createQueryKey('getCloudStatus', options); + +export const getCloudStatusOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getCloudStatus({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getCloudStatusQueryKey(options) +}); + export const getDashboardProjectsAnalyticsQueryKey = (options: Options) => createQueryKey('getDashboardProjectsAnalytics', options); /** diff --git a/web/src/api/client/index.ts b/web/src/api/client/index.ts index 88eb76c4a..727290de7 100644 --- a/web/src/api/client/index.ts +++ b/web/src/api/client/index.ts @@ -1,4 +1,4 @@ // This file is auto-generated by @hey-api/openapi-ts -export { acknowledgeAlarm, activateAiProvider, activateApiKey, activateConnection, activateProvider, addClusterMember, addContext, addEnvironmentDomain, addEvents, addManagedDomain, addSessionReplayEvents, addTeamMember, adminDrainNode, adminDrainStatus, adminGetNode, adminListNodeContainers, adminListNodes, adminRemoveNode, adminUndrainNode, applyHostnameMode, archiveConversation, archiveFlag, assignRole, attachScheduleServices, blobCopy, blobDelete, blobDisable, blobDownload, blobEnable, blobHead, blobList, blobPut, blobStatus, blobUpdate, cancel, cancelBackup, cancelDeployment, cancelDomainOrder, cancelPgUpgrade, cancelRun, cancelScheduleRun, changePasswordSelf, changeProjectSource, chatCompletions, checkAnalyticsHasEvents, checkCommitExists, checkDomainStatus, checkExplorerSupport, checkIpBlocked, checkProviderDeletionSafety, chunkUploadOptions, cleanupExpiredBackups, clearPreviewPassword, cliDeviceApprove, cliDeviceDeny, cliDeviceLookup, cliDevicePoll, cliDeviceStart, cliLogout, cmd, cmdKill, cmdLogs, confirmPendingAction, containerMetricsGetHistory, createAgent, createAlert, createAlertRule, createApiKey, createBackupSchedule, createBitbucketProvider, createCloudflareProvider, createConversation, createCustomDomain, createDashboard, createDeploymentToken, createDnsProvider, createDomain, createDsn, createEmailDomain, createEmailProvider, createEnvironment, createEnvironmentVariable, createFlag, createFunnel, createGenericProvider, createGiteaPatProvider, createGithubPatProvider, createGitlabOauthProvider, createGitlabPatProvider, createGitProvider, createGlobalMcp, createGlobalSkill, createIncident, createIpAccessControl, createMcp, createMonitor, createNotificationEmailProvider, createNotificationProvider, createOidcProvider, createOidcRoleMapping, createOrRecreateOrder, createPlan, createPr, createProject, createProjectFromTemplate, createProjectRelease, createProjectSecret, createProviderKey, createRelease, createRoute, createS3Source, createSandbox, createService, createSkill, createSlackProvider, createTeam, createUser, createWebhook, createWebhookProvider, deactivateApiKey, deactivateConnection, deactivateProvider, deleteAgent, deleteAlert, deleteAlertRule, deleteApiKey, deleteBackup, deleteBackupSchedule, deleteConnection, deleteCustomDomain, deleteDashboard, deleteDeploymentToken, deleteDnsProvider, deleteDomain, deleteEmailDomain, deleteEmailProvider, deleteEnvironment, deleteEnvironmentDomain, deleteEnvironmentVariable, deleteExternalImage, deleteFunnel, deleteGitProvider, deleteGlobalMcp, deleteGlobalSkill, deleteIpAccessControl, deleteMcp, deleteMonitor, deleteNotificationProvider, deleteOidcProvider, deleteOidcRoleMapping, deletePreferences, deleteProject, deleteProjectSecret, deleteProviderKey, deleteProviderSafely, deleteReleaseSourceFiles, deleteReleaseSourceMaps, deleteRoute, deleteS3Source, deleteScan, deleteSecret, deleteService, deleteSessionReplay, deleteSkill, deleteSourceMap, deleteStaticBundle, deleteTeam, deleteUser, deleteWebhook, deployFromImage, deployFromImageUpload, deployFromStatic, deployFromUploadedSource, deploymentMetricsGetLatest, deploymentMetricsGetRange, deploymentMetricsToggle, destroySandbox, detachScheduleService, detectPublicPresets, disableBackupSchedule, disableMfa, discoverWorkloads, domain, downloadGlobalSkillArchive, downloadObject, downloadSkillArchive, emailStatus, embeddings, enableBackupSchedule, enrichVisitor, exec, execDetached, executeDeploymentOperation, executeImport, extendTimeout, externalServiceEnablePgStatStatements, externalServiceMetricsByDatabase, externalServiceMetricsCreateAlertRule, externalServiceMetricsDeleteAlertRule, externalServiceMetricsGetAlertRules, externalServiceMetricsGetLatest, externalServiceMetricsGetRange, externalServiceMetricsStatus, externalServiceMetricsToggle, externalServiceMetricsUpdateAlertRule, externalServiceResetPgStatStatements, finalizeOrder, finalizeProjectRelease, findConversation, generateJoinToken, generatePresetDockerfile, getAccessInfo, getActiveVisitors, getActivityGraph, getAdminGate, getAgent, getAggregatedBuckets, getAiAgentBreakdown, getAiAgentPages, getAiAgentTimeline, getAiPageBreakdown, getAiStatusBreakdown, getAlert, getAlertRule, getAllRepositoriesByName, getAnalyticsActiveVisitors, getAnalyticsEventsCount, getAnalyticsSessionEvents, getAnalyticsVisitorSessions, getApiKey, getApiKeyPermissions, getAuditLog, getBackup, getBackupSchedule, getBranchesByRepositoryId, getBucketedIncidents, getBucketedStatus, getChallengeToken, getChatReadiness, getCliStatus, getClusterHealth, getClusterMember, getCmd, getContainerDetail, getContainerEnvironmentVariable, getContainerInfo, getContainerLogs, getContainerLogsById, getContainerMetrics, getConversation, getConversationDetail, getConversations, getCronById, getCronExecutions, getCrossProjectTraceSiblings, getCurrentMonitorStatus, getCurrentUser, getCustomDomain, getDashboard, getDashboardProjectsAnalytics, getDelivery, getDeployment, getDeploymentContainerLogContent, getDeploymentJobLogs, getDeploymentJobs, getDeploymentOperations, getDeploymentOperationStatus, getDeploymentToken, getDiskStatus, getDnsChanges, getDnsProvider, getDomain, getDomainByHost, getDomainById, getDomainByName, getDomainDnsRecords, getDomainOrder, getEmail, getEmailEvents, getEmailLinks, getEmailProvider, getEmailStats, getEmailTracking, getEmailTrackingStatus, getEntityInfo, getEnvironment, getEnvironmentCrons, getEnvironmentDomains, getEnvironments, getEnvironmentVariables, getEnvironmentVariableValue, getErrorDashboardStats, getErrorEvent, getErrorGroup, getErrorStats, getErrorTimeSeries, getEventDetail, getEventEntries, getEventsCount, getEventsTimeline, getEventTypeBreakdown, getEventVisitors, getExternalImage, getFile, getFlag, getFlagSnapshot, getFunnelMetrics, getGenaiTrace, getGeneralStats, getGitProvider, getGlobalEvents, getGlobalEventStats, getGlobalMcp, getGlobalSandboxStatus, getGlobalSkill, getGroupedPageMetrics, getHealth, getHourlyVisits, getHttpChallengeDebug, getImportStatus, getIncident, getIncidentUpdates, getIpAccessControl, getIpGeolocation, getJoinTokenStatus, getLastDeployment, getLatestScan, getLatestScansPerEnvironment, getLiveVisitorsList, getLogContext, getMcp, getMetricsOverTime, getMonitor, getNotificationProvider, getOnDemandCertStatus, getOrCreateDsn, getPageFlow, getPageHourlySessions, getPagePathDetail, getPagePaths, getPagePathsSparklines, getPagePathVisitors, getPendingAction, getPerformanceMetrics, getPgUpgrade, getPgUpgradeLogs, getPipelineStats, getPlatformInfo, getPostgresWalHealth, getPreferences, getPreviewGatewayLogs, getPreviewGatewaySettings, getPreviewGatewayStatus, getPricing, getPrivateIp, getProject, getProjectAlarmsSummary, getProjectBySlug, getProjectDeployments, getProjects, getProjectServiceEnvironmentVariables, getProjectSessionReplays, getProjectsHealth, getProjectsMonitorHealth, getProjectStatistics, getProjectTemplate, getPropertyBreakdown, getPropertyTimeline, getProviderConnections, getProviderMetadata, getProvidersMetadata, getProxyLogById, getProxyLogByRequestId, getProxyLogs, getPublicBranches, getPublicIp, getPublicRepository, getQuota, getRecentActivity, getRemoteExternalImage, getRepositoryBranches, getRepositoryById, getRepositoryByName, getRepositoryPresetByName, getRepositoryPresetLive, getRepositoryTags, getResolvedEnvironmentVariables, getResolvedEnvironmentVariableValue, getRestoreCapabilities, getRestoreRun, getRoute, getRun, getRunWithLogs, getS3Credentials, getS3Source, getSandbox, getSandboxStatus, getScan, getScanByDeployment, getScanVulnerabilities, getService, getServiceBySlug, getServiceEnvironmentVariable, getServiceEnvironmentVariables, getServiceHealthStatus, getServicePreviewEnvironmentVariableNames, getServicePreviewEnvironmentVariablesMasked, getServiceRuntime, getServiceStats, getServiceTypeParameters, getServiceTypes, getSessionDetails, getSessionEvents, getSessionLogs, getSessionReplay, getSessionReplayEvents, getSettings, getSkill, getSlowQueries, getStaticBundle, getStatusOverview, getTagsByRepositoryId, getTeam, getTimeBucketStats, getTodayStats, getTrace, getUnifiedTrace, getUniqueCounts, getUniqueEvents, getUpdateStatus, getUptimeHistory, getUsageByProvider, getUsageRecent, getUsageSummary, getUsageTimeseries, getUsageTopModels, getVisitorByGuid, getVisitorById, getVisitorDetails, getVisitorFacets, getVisitorInfo, getVisitorJourney, getVisitors, getVisitorSessions, getVisitorStats, getWebhook, grantProjectAccess, handleGitProviderOauthCallback, hasAnalyticsEvents, hasErrorGroups, hasPerformanceMetrics, importExternalService, ingestLogs, ingestLogsByPath, ingestMetrics, ingestMetricsByPath, ingestSentryEnvelope, ingestSentryEvent, ingestTraces, ingestTracesByPath, initSessionReplay, inspectDropArchive, jobLogs, jobStatus, killJob, kvDel, kvDisable, kvEnable, kvExpire, kvGet, kvIncr, kvKeys, kvSet, kvStatus, kvTtl, kvUpdate, latestRunForSource, linkCustomDomainToCertificate, linkServiceToProject, listAgentRuns, listAgents, listAiProviders, listAlertRules, listAlerts, listAllConversations, listAllRuns, listApiKeys, listAuditLogs, listAvailableContainers, listBackupAlerts, listBackupChildren, listBackupSchedules, listBackupsForSchedule, listCommitsByRepositoryId, listConnections, listContainers, listContainersAtPath, listConversations, listCustomDomainsForProject, listDashboards, listDeliveries, listDeploymentContainerLogs, listDeploymentTokens, listDnsProviders, listDomains, listDsns, listEmailDomains, listEmailProviders, listEmails, listEnrollmentTokens, listEntities, listErrorEvents, listErrorGroups, listEvents, listEventTypes, listExternalImages, listExternalPlugins, listExternalServiceBackups, listFlags, listFunnels, listGitProviders, listGlobalMcps, listGlobalSkills, listIncidents, listInsights, listIpAccessControl, listJobs, listKnownAiAgents, listManagedDomains, listMcps, listMetricLabelKeys, listMetricLabelValues, listMetricNames, listModels, listMonitors, listNotificationProviders, listOidcProviders, listOidcProviderUsers, listOidcRoleMappings, listOnDemandCerts, listOrders, listPeers, listPendingActions, listPgUpgrades, listPresets, listProjectAccess, listProjectAlarms, listProjectScans, listProjectSecrets, listProjectServices, listProjectTemplates, listProjectTemplateTags, listProviderKeys, listProviderZones, listPublicProviders, listReleaseFiles, listReleases, listRemoteExternalImages, listRepositoriesByConnection, listRepositoriesByProvider, listRestoreRunsForService, listRootContainers, listRoutes, listS3Sources, listSandboxes, listScheduleRunJobs, listScheduleRuns, listScheduleServices, listSecrets, listServiceHealthStatuses, listServiceProjects, listServices, listServiceSchedules, listSkills, listSourceBackups, listSourceFiles, listSourceMaps, listSources, listStaticBundles, listSyncedRepositories, listTeamMembers, listTeamProjects, listTeams, listUsers, listWebhooks, login, logout, lookupDnsARecords, mintEnrollmentToken, mkdir, nodeHeartbeat, nodeMetricsGetRange, observabilityFullEvent, observabilityListEvents, oidcCallback, type Options, patchAdminGate, patchPreviewGatewaySettings, pauseDeployment, pauseSandbox, planRestore, postDnsAck, previewAlert, previewFunnelMetrics, previewHostnameMode, promoteClusterMember, promoteDeployment, provisionDomain, purgeProjectLogs, pushExternalImage, queryData, queryGenaiTraces, queryLogs, queryMetrics, queryTraces, queryTraceSummaries, readFile, reAnalyze, recordConsoleEvent, recordEventMetrics, recordFlagExposure, recordSpeedMetrics, refreshRouteTable, regenerateDsn, registerExternalImage, registerNode, reinstallGitlabWebhook, rejectPendingAction, reloadPlugins, removeClusterMember, removeManagedDomain, removeRole, removeTeamMember, renameConversation, renewDomain, requestPasswordReset, resetPassword, resizeSandbox, resolveAlarm, restartContainer, restartPreviewGateway, restartSandbox, restoreFlag, restoreUser, resumeDeployment, resumeSandbox, retryCluster, retryDelivery, retryPgUpgrade, retryRun, revealGlobalMcpConfig, revealMcpConfig, revealNotificationProviderConfig, revealServiceParameter, revenueCreateIntegration, revenueDeleteIntegration, revenueGlobalEvents, revenueImportInvoicesCsv, revenueImportSubscriptionsCsv, revenueListIntegrations, revenueListProviders, revenueMetricsCustomers, revenueMetricsGlobalMrr, revenueMetricsGlobalSummary, revenueMetricsMrr, revenueMetricsSummary, revenueRecentEvents, revenueRotateToken, revenueUpdateConfig, revenueUpdateSecret, revokeDsn, revokeEnrollmentToken, revokeJoinToken, revokeProjectAccess, rollbackPgUpgrade, rollbackToDeployment, rootfsGc, rootfsReport, rotateApiKey, rotateDeploymentToken, runBackupForSource, runConnectionHealthCheck, runExternalServiceBackup, runScheduleNow, sandboxCreatePreviewLink, saveAgentToken, saveAiProviderCredential, searchLogs, sendEmail, setDefaultS3Source, setFlagEnvironment, setPreviewPassword, setupDns, setupDnsChallenge, setupEmailTracking, setupMfa, sleepEnvironment, smokeTestAgent, sourceSandbox, startAnalysis, startContainer, startFix, startGitProviderOauth, startOidcLoginBySlug, startPgUpgrade, startRestore, startService, statPath, stopContainer, stopSandbox, stopService, streamContainerMetrics, streamEvents, streamRunEvents, syncRepositories, tailDeploymentJobLogs, tailLogs, teardownDeployment, teardownEnvironment, testNotificationProvider, testOidcProvider, testProvider, testProviderConnection, testProviderKeyById, testProviderKeyInline, testS3ConnectionPreview, testS3SourceConnection, trackClick, trackOpen, triggerAgent, triggerProjectPipeline, triggerScan, triggerServiceHealthCheck, triggerWeeklyDigest, unlinkServiceFromProject, updateAgent, updateAiProvider, updateAlert, updateAlertRule, updateApiKey, updateAutomaticDeploy, updateBackupSchedule, updateCloudflareProvider, updateConnectionToken, updateCustomDomain, updateDashboard, updateDeploymentToken, updateEmailProvider, updateEnvironmentSettings, updateEnvironmentSubdomain, updateEnvironmentVariable, updateErrorGroup, updateFlag, updateFunnel, updateGitProviderCredentials, updateGitSettings, updateGlobalMcp, updateGlobalSkill, updateIncidentStatus, updateIpAccessControl, updateManagedDomain, updateMcp, updateNotificationEmailProvider, updateNotificationProvider, updateOidcProvider, updatePreferences, updateProject, updateProjectDeploymentConfig, updateProjectSecret, updateProjectSettings, updateProvider, updateProviderKey, updateRoute, updateS3Source, updateSelf, updateService, updateServiceResources, updateSessionDuration, updateSettings, updateSkill, updateSlackProvider, updateSpeedMetrics, updateTeam, updateTeamMemberRole, updateUser, updateWebhook, updateWebhookProvider, upgradePreviewGateway, upgradeService, uploadGlobalSkill, uploadReleaseFile, uploadSkill, uploadSourceFile, uploadSourceMap, uploadStaticBundle, upsertSecret, validateConnection, validateEmail, verifyAndEnableMfa, verifyDomain, verifyEmail, verifyManagedDomain, verifyMfaChallenge, verifyStepUp, wakeEnvironment, webhookTrigger, workflowDryRun, writeFile, writeFiles } from './sdk.gen'; -export type { AcknowledgeAlarmData, AcknowledgeAlarmErrors, AcknowledgeAlarmResponses, AcmeOrderResponse, ActivateAiProviderData, ActivateAiProviderErrors, ActivateAiProviderResponse, ActivateAiProviderResponses, ActivateApiKeyData, ActivateApiKeyErrors, ActivateApiKeyResponse, ActivateApiKeyResponses, ActivateConnectionData, ActivateConnectionErrors, ActivateConnectionResponses, ActivateProviderData, ActivateProviderErrors, ActivateProviderResponse, ActivateProviderResponses, ActiveVisitor, ActiveVisitorsQuery, ActiveVisitorsResponse, ActivityDay, ActivityEvent, ActivityGraphQuery, ActivityGraphResponse, AddClusterMemberData, AddClusterMemberErrors, AddClusterMemberRequest, AddClusterMemberResponse, AddClusterMemberResponses, AddContextData, AddContextErrors, AddContextRequest, AddContextResponses, AddEnvironmentDomainData, AddEnvironmentDomainErrors, AddEnvironmentDomainRequest, AddEnvironmentDomainResponse, AddEnvironmentDomainResponses, AddEventsData, AddEventsError, AddEventsErrors, AddEventsRequest, AddEventsResponse, AddEventsResponse2, AddEventsResponses, AddManagedDomainApiRequest, AddManagedDomainData, AddManagedDomainErrors, AddManagedDomainResponse, AddManagedDomainResponses, AddSessionReplayEventsData, AddSessionReplayEventsError, AddSessionReplayEventsErrors, AddSessionReplayEventsResponse, AddSessionReplayEventsResponses, AddTeamMemberData, AddTeamMemberErrors, AddTeamMemberResponse, AddTeamMemberResponses, AdminDrainNodeData, AdminDrainNodeErrors, AdminDrainNodeResponse, AdminDrainNodeResponses, AdminDrainStatusData, AdminDrainStatusErrors, AdminDrainStatusResponse, AdminDrainStatusResponses, AdminGateResponse, AdminGateSource, AdminGetNodeData, AdminGetNodeErrors, AdminGetNodeResponse, AdminGetNodeResponses, AdminListNodeContainersData, AdminListNodeContainersErrors, AdminListNodeContainersResponse, AdminListNodeContainersResponses, AdminListNodesData, AdminListNodesErrors, AdminListNodesResponse, AdminListNodesResponses, AdminRemoveNodeData, AdminRemoveNodeErrors, AdminRemoveNodeResponse, AdminRemoveNodeResponses, AdminUndrainNodeData, AdminUndrainNodeErrors, AdminUndrainNodeResponse, AdminUndrainNodeResponses, AgentConfigResponse, AgentRunLogResponse, AgentRunResponse, AgentRunWithLogsResponse, AgentSandboxSettings, AgentSandboxSettingsMasked, AggregatedBucketItem, AggregatedBucketsQuery, AggregatedBucketsResponse, AggregationLevel, AggregationTemporality, AiAgentBreakdownResponse, AiAgentBreakdownRow, AiAgentDescriptor, AiAgentPageRow, AiAgentPagesResponse, AiAgentTimelineResponse, AiAgentTimelineRow, AiChatLimitsSettings, AiConfigSettings, AiPageBreakdownResponse, AiPageBreakdownRow, AiStatusBreakdownResponse, AiStatusBreakdownRow, AlarmListResponse, AlarmResponse, AlarmSummaryResponse, AlertRuleResponse, AllocEntry, AnalyticsSessionEventsResponse, AnnotatedSpan, AnomalyAlgorithm, AnomalyParams, AnomalyPreviewPointResponse, AnomalyPreviewRequest, AnomalyPreviewResponse, ApiKeyListResponse, ApiKeyResponse, ApplyHostnameModeData, ApplyHostnameModeErrors, ApplyHostnameModeRequest, ApplyHostnameModeResponse, ApplyHostnameModeResponses, AppSettings, AppSettingsResponse, ArchiveConversationData, ArchiveConversationErrors, ArchiveConversationResponse, ArchiveConversationResponses, ArchiveFlagData, ArchiveFlagErrors, ArchiveFlagResponse, ArchiveFlagResponse2, ArchiveFlagResponses, ArchiveMode, AssignRoleData, AssignRoleErrors, AssignRoleRequest, AssignRoleResponses, AttachScheduleServicesData, AttachScheduleServicesError, AttachScheduleServicesErrors, AttachScheduleServicesRequest, AttachScheduleServicesResponse, AttachScheduleServicesResponse2, AttachScheduleServicesResponses, AuditLogIpInfo, AuditLogResponse, AuditLogUserInfo, AuthFlavorDto, AuthResponse, AuthStatusResponse, AuthTokenResponse, AutofixerRunResponse, AutofixerRunWithLogsResponse, AutofixRunConfig, AutoWatchParams, AvailableContainerInfo, AvailablePermissions, BackupAlertListResponse, BackupAlertResponse, BackupResponse, BackupScheduleResponse, BitbucketAuthInput, BlobCopyData, BlobCopyError, BlobCopyErrors, BlobCopyResponse, BlobCopyResponses, BlobDeleteData, BlobDeleteError, BlobDeleteErrors, BlobDeleteResponse, BlobDeleteResponses, BlobDisableData, BlobDisableErrors, BlobDisableResponse, BlobDisableResponses, BlobDownloadData, BlobDownloadError, BlobDownloadErrors, BlobDownloadResponses, BlobEnableData, BlobEnableErrors, BlobEnableResponse, BlobEnableResponses, BlobHeadData, BlobHeadError, BlobHeadErrors, BlobHeadResponses, BlobListData, BlobListError, BlobListErrors, BlobListResponse, BlobListResponses, BlobPutData, BlobPutError, BlobPutErrors, BlobPutResponse, BlobPutResponses, BlobResponse, BlobStatusData, BlobStatusErrors, BlobStatusResponse, BlobStatusResponse2, BlobStatusResponses, BlobUpdateData, BlobUpdateErrors, BlobUpdateResponse, BlobUpdateResponses, BranchInfo, BranchListResponse, BrowserCount, BrowsersQuery, BuildConfiguration, BuildLimitsSettings, CancelBackupData, CancelBackupError, CancelBackupErrors, CancelBackupResponse, CancelBackupResponse2, CancelBackupResponses, CancelData, CancelDeploymentData, CancelDeploymentErrors, CancelDeploymentResponse, CancelDeploymentResponses, CancelDomainOrderData, CancelDomainOrderErrors, CancelDomainOrderResponse, CancelDomainOrderResponses, CancelErrors, CancelPgUpgradeData, CancelPgUpgradeErrors, CancelPgUpgradeResponse, CancelPgUpgradeResponses, CancelResponses, CancelRunData, CancelRunErrors, CancelRunResponse, CancelRunResponses, CancelScheduleRunData, CancelScheduleRunError, CancelScheduleRunErrors, CancelScheduleRunResponse, CancelScheduleRunResponses, CertStatusResponse, ChallengeConfig, ChallengeError, ChallengeValidationStatus, ChangePasswordRequest, ChangePasswordSelfData, ChangePasswordSelfErrors, ChangePasswordSelfResponse, ChangePasswordSelfResponses, ChangeProjectSourceData, ChangeProjectSourceErrors, ChangeProjectSourceRequest, ChangeProjectSourceResponse, ChangeProjectSourceResponses, ChatCompletionChoice, ChatCompletionRequest, ChatCompletionResponse, ChatCompletionsData, ChatCompletionsError, ChatCompletionsErrors, ChatCompletionsResponse, ChatCompletionsResponses, ChatMessage, ChatReadinessResponse, CheckAnalyticsHasEventsData, CheckAnalyticsHasEventsErrors, CheckAnalyticsHasEventsResponse, CheckAnalyticsHasEventsResponses, CheckCommitExistsData, CheckCommitExistsErrors, CheckCommitExistsResponse, CheckCommitExistsResponses, CheckDomainStatusData, CheckDomainStatusErrors, CheckDomainStatusResponse, CheckDomainStatusResponses, CheckExplorerSupportData, CheckExplorerSupportErrors, CheckExplorerSupportResponse, CheckExplorerSupportResponses, CheckIpBlockedData, CheckIpBlockedError, CheckIpBlockedErrors, CheckIpBlockedResponses, CheckProviderDeletionSafetyData, CheckProviderDeletionSafetyErrors, CheckProviderDeletionSafetyResponse, CheckProviderDeletionSafetyResponses, ChildBackupEntryResponse, ChildBackupListResponse, ChunkUploadOptionsData, ChunkUploadOptionsResponse, ChunkUploadOptionsResponses, CleanupExpiredBackupsData, CleanupExpiredBackupsError, CleanupExpiredBackupsErrors, CleanupExpiredBackupsRequest, CleanupExpiredBackupsResponse, CleanupExpiredBackupsResponses, ClearPreviewPasswordData, ClearPreviewPasswordErrors, ClearPreviewPasswordResponse, ClearPreviewPasswordResponses, CliDeviceApproveData, CliDeviceApproveErrors, CliDeviceApproveRequest, CliDeviceApproveResponse, CliDeviceApproveResponse2, CliDeviceApproveResponses, CliDeviceDenyData, CliDeviceDenyErrors, CliDeviceDenyResponse, CliDeviceDenyResponses, CliDeviceLookupData, CliDeviceLookupErrors, CliDeviceLookupResponse, CliDeviceLookupResponse2, CliDeviceLookupResponses, CliDevicePollData, CliDevicePollErrors, CliDevicePollRequest, CliDevicePollResponse, CliDevicePollResponse2, CliDevicePollResponses, CliDeviceStartData, CliDeviceStartErrors, CliDeviceStartRequest, CliDeviceStartResponse, CliDeviceStartResponse2, CliDeviceStartResponses, ClientOptions, CliLoginRequest, CliLogoutData, CliLogoutErrors, CliLogoutResponse, CliLogoutResponses, CloudflareConfig, CloudProvider, ClusterCapacity, ClusterDnsSettings, ClusterHealthReportResponse, ClusterMemberHealthResponse, ClusterMemberRequest, CmdBody, CmdData, CmdErrors, CmdInner, CmdKillBody, CmdKillData, CmdKillErrors, CmdKillResponse, CmdKillResponses, CmdLogsData, CmdLogsErrors, CmdLogsResponses, CmdResponse, CmdResponse2, CmdResponses, CommitExistsResponse, CommitInfo, CommitListResponse, Comparator, ComposePublicPort, ConfirmPendingActionData, ConfirmPendingActionErrors, ConfirmPendingActionResponse, ConfirmPendingActionResponses, ConnectionListQuery, ConnectionListResponse, ConnectionResponse, ConnectionTestResult, ConsoleEventPayload, ContainerActionResponse, ContainerDetailResponse, ContainerEnvironmentVariableValueResponse, ContainerInfoResponse, ContainerInventoryItem, ContainerListResponse, ContainerLogSettings, ContainerLogsQuery, ContainerMetricHistoryPoint, ContainerMetricsGetHistoryData, ContainerMetricsGetHistoryErrors, ContainerMetricsGetHistoryResponse, ContainerMetricsGetHistoryResponses, ContainerMetricsHistoryQuery, ContainerMetricsResponse, ContainerResponse, ContainerRuntimeInfo, ContainerStatsSample, ContentPart, ContextLine, ContextLogsRequest, ContextLogsResponse, ConversationDetailResponse, ConversationResponse, ConversationsQueryParams, ConversationSummary, CopyBlobRequest, CostAnalysis, CreateAgentData, CreateAgentErrors, CreateAgentResponse, CreateAgentResponses, CreateAlertData, CreateAlertError, CreateAlertErrors, CreateAlertResponse, CreateAlertResponses, CreateAlertRuleData, CreateAlertRuleErrors, CreateAlertRuleRequest, CreateAlertRuleResponse, CreateAlertRuleResponses, CreateApiKeyData, CreateApiKeyErrors, CreateApiKeyRequest, CreateApiKeyResponse, CreateApiKeyResponse2, CreateApiKeyResponses, CreateBackupScheduleData, CreateBackupScheduleError, CreateBackupScheduleErrors, CreateBackupScheduleRequest, CreateBackupScheduleResponse, CreateBackupScheduleResponses, CreateBitbucketProviderData, CreateBitbucketProviderErrors, CreateBitbucketProviderResponse, CreateBitbucketProviderResponses, CreateBitbucketRequest, CreateCloudflareProviderData, CreateCloudflareProviderErrors, CreateCloudflareProviderRequest, CreateCloudflareProviderResponse, CreateCloudflareProviderResponses, CreateConversationData, CreateConversationErrors, CreateConversationRequest, CreateConversationResponse, CreateConversationResponses, CreateCustomDomainData, CreateCustomDomainErrors, CreateCustomDomainResponse, CreateCustomDomainResponses, CreateDashboardData, CreateDashboardError, CreateDashboardErrors, CreateDashboardRequest, CreateDashboardResponse, CreateDashboardResponses, CreateDeploymentTokenData, CreateDeploymentTokenErrors, CreateDeploymentTokenRequest, CreateDeploymentTokenResponse, CreateDeploymentTokenResponse2, CreateDeploymentTokenResponses, CreateDnsProviderData, CreateDnsProviderErrors, CreateDnsProviderRequest, CreateDnsProviderResponse, CreateDnsProviderResponses, CreateDomainData, CreateDomainErrors, CreateDomainRequest, CreateDomainResponse, CreateDomainResponses, CreatedResource, CreateDsnData, CreateDsnErrors, CreateDsnRequest, CreateDsnResponse, CreateDsnResponses, CreateEmailDomainData, CreateEmailDomainErrors, CreateEmailDomainRequest, CreateEmailDomainResponse, CreateEmailDomainResponses, CreateEmailProviderData, CreateEmailProviderErrors, CreateEmailProviderRequest, CreateEmailProviderResponse, CreateEmailProviderResponses, CreateEnvironmentData, CreateEnvironmentErrors, CreateEnvironmentRequest, CreateEnvironmentResponse, CreateEnvironmentResponses, CreateEnvironmentVariableData, CreateEnvironmentVariableErrors, CreateEnvironmentVariableRequest, CreateEnvironmentVariableResponse, CreateEnvironmentVariableResponses, CreateExternalServiceRequest, CreateFlagData, CreateFlagErrors, CreateFlagRequest, CreateFlagResponse, CreateFlagResponses, CreateFunnelData, CreateFunnelErrors, CreateFunnelRequest, CreateFunnelResponse, CreateFunnelResponse2, CreateFunnelResponses, CreateFunnelStep, CreateGenericProviderData, CreateGenericProviderErrors, CreateGenericProviderResponse, CreateGenericProviderResponses, CreateGenericRequest, CreateGiteaPatProviderData, CreateGiteaPatProviderErrors, CreateGiteaPatProviderResponse, CreateGiteaPatProviderResponses, CreateGiteaPatRequest, CreateGithubPatProviderData, CreateGithubPatProviderErrors, CreateGithubPatProviderResponse, CreateGithubPatProviderResponses, CreateGitHubPatRequest, CreateGitlabOauthProviderData, CreateGitlabOauthProviderErrors, CreateGitlabOauthProviderResponse, CreateGitlabOauthProviderResponses, CreateGitLabOAuthRequest, CreateGitlabPatProviderData, CreateGitlabPatProviderErrors, CreateGitlabPatProviderResponse, CreateGitlabPatProviderResponses, CreateGitLabPatRequest, CreateGitProviderData, CreateGitProviderErrors, CreateGitProviderResponse, CreateGitProviderResponses, CreateGlobalMcpData, CreateGlobalMcpErrors, CreateGlobalMcpResponse, CreateGlobalMcpResponses, CreateGlobalSkillData, CreateGlobalSkillErrors, CreateGlobalSkillResponse, CreateGlobalSkillResponses, CreateIncidentData, CreateIncidentErrors, CreateIncidentRequest, CreateIncidentResponse, CreateIncidentResponses, CreateIntegrationBody, CreateIpAccessControlData, CreateIpAccessControlError, CreateIpAccessControlErrors, CreateIpAccessControlRequest, CreateIpAccessControlResponse, CreateIpAccessControlResponses, CreateMcpData, CreateMcpErrors, CreateMcpRequest, CreateMcpResponse, CreateMcpResponses, CreateMetricAlertRequest, CreateMonitorData, CreateMonitorErrors, CreateMonitorRequest, CreateMonitorResponse, CreateMonitorResponses, CreateNotificationEmailProviderData, CreateNotificationEmailProviderErrors, CreateNotificationEmailProviderRequest, CreateNotificationEmailProviderResponse, CreateNotificationEmailProviderResponses, CreateNotificationProviderData, CreateNotificationProviderErrors, CreateNotificationProviderResponse, CreateNotificationProviderResponses, CreateOidcProviderData, CreateOidcProviderErrors, CreateOidcProviderRequest, CreateOidcProviderResponse, CreateOidcProviderResponses, CreateOidcRoleMappingData, CreateOidcRoleMappingRequest, CreateOidcRoleMappingResponse, CreateOidcRoleMappingResponses, CreateOrRecreateOrderData, CreateOrRecreateOrderErrors, CreateOrRecreateOrderResponse, CreateOrRecreateOrderResponses, CreatePlanData, CreatePlanErrors, CreatePlanRequest, CreatePlanResponse, CreatePlanResponse2, CreatePlanResponses, CreatePrData, CreatePrErrors, CreateProjectAccessRequest, CreateProjectData, CreateProjectErrors, CreateProjectFromTemplateData, CreateProjectFromTemplateErrors, CreateProjectFromTemplateRequest, CreateProjectFromTemplateResponse, CreateProjectFromTemplateResponse2, CreateProjectFromTemplateResponses, CreateProjectReleaseData, CreateProjectReleaseErrors, CreateProjectReleaseResponse, CreateProjectReleaseResponses, CreateProjectRequest, CreateProjectResponse, CreateProjectResponses, CreateProjectSecretData, CreateProjectSecretErrors, CreateProjectSecretRequest, CreateProjectSecretResponse, CreateProjectSecretResponses, CreateProviderKeyData, CreateProviderKeyError, CreateProviderKeyErrors, CreateProviderKeyRequest, CreateProviderKeyResponse, CreateProviderKeyResponses, CreateProviderRequest, CreatePrResponse, CreatePrResponse2, CreatePrResponses, CreateReleaseData, CreateReleaseErrors, CreateReleaseResponse, CreateReleaseResponses, CreateRouteData, CreateRouteErrors, CreateRouteRequest, CreateRouteResponse, CreateRouteResponses, CreateS3SourceData, CreateS3SourceError, CreateS3SourceErrors, CreateS3SourceRequest, CreateS3SourceResponse, CreateS3SourceResponses, CreateSandboxBody, CreateSandboxData, CreateSandboxErrors, CreateSandboxResponse, CreateSandboxResponses, CreateServiceData, CreateServiceErrors, CreateServiceResponse, CreateServiceResponses, CreateSkillData, CreateSkillErrors, CreateSkillRequest, CreateSkillResponse, CreateSkillResponses, CreateSlackProviderData, CreateSlackProviderErrors, CreateSlackProviderRequest, CreateSlackProviderResponse, CreateSlackProviderResponses, CreateTeamData, CreateTeamErrors, CreateTeamMemberRequest, CreateTeamRequest, CreateTeamResponse, CreateTeamResponses, CreateUserData, CreateUserErrors, CreateUserRequest, CreateUserResponse, CreateUserResponses, CreateWebhookData, CreateWebhookErrors, CreateWebhookProviderData, CreateWebhookProviderErrors, CreateWebhookProviderRequest, CreateWebhookProviderResponse, CreateWebhookProviderResponses, CreateWebhookRequestBody, CreateWebhookResponse, CreateWebhookResponses, CronExecutionInfo, CronInfo, CrossProjectSiblingRef, CrossProjectTraceResponse, CurrentStatusResponse, CustomDomainRequest, CustomDomainResponse, CustomerMovementResponse, DashboardLayout, DashboardProjectsAnalyticsQuery, DashboardProjectsAnalyticsResponse, DashboardSection, DashboardTile, DatabaseMetricsResponse, DatabaseMetricsRow, DataImplication, DataImplicationSeverity, DeactivateApiKeyData, DeactivateApiKeyErrors, DeactivateApiKeyResponse, DeactivateApiKeyResponses, DeactivateConnectionData, DeactivateConnectionErrors, DeactivateConnectionResponses, DeactivateProviderData, DeactivateProviderErrors, DeactivateProviderResponses, DeleteAgentData, DeleteAgentErrors, DeleteAgentResponse, DeleteAgentResponses, DeleteAlertData, DeleteAlertError, DeleteAlertErrors, DeleteAlertResponse, DeleteAlertResponses, DeleteAlertRuleData, DeleteAlertRuleErrors, DeleteAlertRuleResponse, DeleteAlertRuleResponses, DeleteApiKeyData, DeleteApiKeyErrors, DeleteApiKeyResponse, DeleteApiKeyResponses, DeleteBackupData, DeleteBackupError, DeleteBackupErrors, DeleteBackupResponse, DeleteBackupResponses, DeleteBackupScheduleData, DeleteBackupScheduleError, DeleteBackupScheduleErrors, DeleteBackupScheduleResponse, DeleteBackupScheduleResponses, DeleteBlobRequest, DeleteBlobResponse, DeleteConnectionData, DeleteConnectionErrors, DeleteConnectionResponse, DeleteConnectionResponses, DeleteCustomDomainData, DeleteCustomDomainErrors, DeleteCustomDomainResponse, DeleteCustomDomainResponses, DeleteDashboardData, DeleteDashboardError, DeleteDashboardErrors, DeleteDashboardResponse, DeleteDashboardResponses, DeleteDeploymentTokenData, DeleteDeploymentTokenErrors, DeleteDeploymentTokenResponse, DeleteDeploymentTokenResponses, DeleteDnsProviderData, DeleteDnsProviderErrors, DeleteDnsProviderResponse, DeleteDnsProviderResponses, DeleteDomainData, DeleteDomainErrors, DeleteDomainResponse, DeleteDomainResponses, DeleteEmailDomainData, DeleteEmailDomainErrors, DeleteEmailDomainResponse, DeleteEmailDomainResponses, DeleteEmailProviderData, DeleteEmailProviderErrors, DeleteEmailProviderResponse, DeleteEmailProviderResponses, DeleteEnvironmentData, DeleteEnvironmentDomainData, DeleteEnvironmentDomainErrors, DeleteEnvironmentDomainResponse, DeleteEnvironmentDomainResponses, DeleteEnvironmentErrors, DeleteEnvironmentResponse, DeleteEnvironmentResponses, DeleteEnvironmentVariableData, DeleteEnvironmentVariableErrors, DeleteEnvironmentVariableResponse, DeleteEnvironmentVariableResponses, DeleteExternalImageData, DeleteExternalImageErrors, DeleteExternalImageResponse, DeleteExternalImageResponses, DeleteFunnelData, DeleteFunnelErrors, DeleteFunnelResponses, DeleteGitProviderData, DeleteGitProviderErrors, DeleteGitProviderResponse, DeleteGitProviderResponses, DeleteGlobalMcpData, DeleteGlobalMcpErrors, DeleteGlobalMcpResponse, DeleteGlobalMcpResponses, DeleteGlobalSkillData, DeleteGlobalSkillErrors, DeleteGlobalSkillResponse, DeleteGlobalSkillResponses, DeleteIpAccessControlData, DeleteIpAccessControlError, DeleteIpAccessControlErrors, DeleteIpAccessControlResponse, DeleteIpAccessControlResponses, DeleteMcpData, DeleteMcpErrors, DeleteMcpResponse, DeleteMcpResponses, DeleteMonitorData, DeleteMonitorErrors, DeleteMonitorResponse, DeleteMonitorResponses, DeleteNotificationProviderData, DeleteNotificationProviderErrors, DeleteNotificationProviderResponse, DeleteNotificationProviderResponses, DeleteOidcProviderData, DeleteOidcProviderResponse, DeleteOidcProviderResponses, DeleteOidcRoleMappingData, DeleteOidcRoleMappingResponse, DeleteOidcRoleMappingResponses, DeletePreferencesData, DeletePreferencesErrors, DeletePreferencesResponse, DeletePreferencesResponses, DeleteProjectData, DeleteProjectErrors, DeleteProjectResponse, DeleteProjectResponses, DeleteProjectSecretData, DeleteProjectSecretErrors, DeleteProjectSecretResponse, DeleteProjectSecretResponses, DeleteProviderKeyData, DeleteProviderKeyError, DeleteProviderKeyErrors, DeleteProviderKeyResponse, DeleteProviderKeyResponses, DeleteProviderSafelyData, DeleteProviderSafelyErrors, DeleteProviderSafelyResponse, DeleteProviderSafelyResponses, DeleteReleaseSourceFilesData, DeleteReleaseSourceFilesErrors, DeleteReleaseSourceFilesResponse, DeleteReleaseSourceFilesResponses, DeleteReleaseSourceMapsData, DeleteReleaseSourceMapsErrors, DeleteReleaseSourceMapsResponse, DeleteReleaseSourceMapsResponses, DeleteResponse, DeleteRouteData, DeleteRouteErrors, DeleteRouteResponse, DeleteRouteResponses, DeleteS3SourceData, DeleteS3SourceError, DeleteS3SourceErrors, DeleteS3SourceResponse, DeleteS3SourceResponses, DeleteScanData, DeleteScanError, DeleteScanErrors, DeleteScanResponse, DeleteScanResponses, DeleteSecretData, DeleteSecretErrors, DeleteSecretResponse, DeleteSecretResponses, DeleteServiceData, DeleteServiceErrors, DeleteServiceResponse, DeleteServiceResponses, DeleteSessionReplayData, DeleteSessionReplayError, DeleteSessionReplayErrors, DeleteSessionReplayResponses, DeleteSkillData, DeleteSkillErrors, DeleteSkillResponse, DeleteSkillResponses, DeleteSourceMapData, DeleteSourceMapErrors, DeleteSourceMapResponse, DeleteSourceMapResponses, DeleteStaticBundleData, DeleteStaticBundleErrors, DeleteStaticBundleResponse, DeleteStaticBundleResponses, DeleteTeamData, DeleteTeamErrors, DeleteTeamResponse, DeleteTeamResponses, DeleteUserData, DeleteUserErrors, DeleteUserResponse, DeleteUserResponses, DeleteWebhookData, DeleteWebhookErrors, DeleteWebhookResponse, DeleteWebhookResponses, DelRequest, DelResponse, DeployFromImageData, DeployFromImageErrors, DeployFromImageRequest, DeployFromImageResponse, DeployFromImageResponses, DeployFromImageUploadData, DeployFromImageUploadErrors, DeployFromImageUploadQuery, DeployFromImageUploadResponse, DeployFromImageUploadResponses, DeployFromStaticData, DeployFromStaticErrors, DeployFromStaticRequest, DeployFromStaticResponse, DeployFromStaticResponses, DeployFromUploadedSourceData, DeployFromUploadedSourceErrors, DeployFromUploadedSourceResponse, DeployFromUploadedSourceResponses, DeploymentConfig, DeploymentConfigSnapshot, DeploymentConfiguration, DeploymentContainerLogContentResponse, DeploymentContainerLogResponse, DeploymentContainerLogsListResponse, DeploymentEnvironmentResponse, DeploymentJobResponse, DeploymentJobsResponse, DeploymentListResponse, DeploymentMetadata, DeploymentMetricsGetLatestData, DeploymentMetricsGetLatestErrors, DeploymentMetricsGetLatestResponse, DeploymentMetricsGetLatestResponses, DeploymentMetricsGetRangeData, DeploymentMetricsGetRangeErrors, DeploymentMetricsGetRangeResponse, DeploymentMetricsGetRangeResponses, DeploymentMetricsToggleData, DeploymentMetricsToggleErrors, DeploymentMetricsToggleResponses, DeploymentResponse, DeploymentStateResponse, DeploymentStrategy, DeploymentTokenListResponse, DeploymentTokenResponse, DestroySandboxData, DestroySandboxErrors, DestroySandboxResponse, DestroySandboxResponses, DetachScheduleServiceData, DetachScheduleServiceError, DetachScheduleServiceErrors, DetachScheduleServiceResponse, DetachScheduleServiceResponses, DetectionConfig, DetectPublicPresetsData, DetectPublicPresetsErrors, DetectPublicPresetsResponse, DetectPublicPresetsResponses, DeviceCount, DigestSections, Direction, DisableBackupScheduleData, DisableBackupScheduleErrors, DisableBackupScheduleResponse, DisableBackupScheduleResponses, DisableBlobResponse, DisableKvResponse, DisableMfaData, DisableMfaErrors, DisableMfaRequest, DisableMfaResponse, DisableMfaResponses, DiscoverRequest, DiscoverResponse, DiscoverWorkloadsData, DiscoverWorkloadsErrors, DiscoverWorkloadsResponse, DiscoverWorkloadsResponses, DiskInfo, DiskSpaceAlert, DiskSpaceAlertSettings, DiskSpaceCheckResult, DnsAckRequest, DnsAckResponse, DnsChallengeRecordResult, DnsChangesResponse, DnsCompletionResponse, DnsLookupError, DnsLookupRequest, DnsLookupResponse, DnsProviderCredentials, DnsProviderResponse, DnsProviderSettings, DnsProviderSettingsMasked, DnsProviderType, DnsRecord, DnsRecordChange, DnsRecordContent, DnsRecordResponse, DnsRecordSetupResult, DnsRecordStatusResponse, DnsZone, DockerComposePresetConfig, DockerfilePresetConfig, DockerfileVariant, DockerRegistrySettings, DockerRegistrySettingsMasked, DomainAction, DomainChallengeResponse, DomainData, DomainEnvironmentResponse, DomainError, DomainErrors, DomainPlan, DomainResponse, DomainResponse2, DomainResponses, DownloadGlobalSkillArchiveData, DownloadGlobalSkillArchiveErrors, DownloadGlobalSkillArchiveResponse, DownloadGlobalSkillArchiveResponses, DownloadObjectData, DownloadObjectErrors, DownloadObjectResponse, DownloadObjectResponses, DownloadSkillArchiveData, DownloadSkillArchiveErrors, DownloadSkillArchiveResponse, DownloadSkillArchiveResponses, DrainNodeResponse, DrainStatusResponse, DropArchiveUpload, DropInspectionResponse, DropOffPoint, DropPresetCandidate, EmailConfig, EmailDomainResponse, EmailDomainWithDnsResponse, EmailProviderResponse, EmailProviderTypeRoute, EmailRequest, EmailResponse, EmailStatsResponse, EmailStatusData, EmailStatusErrors, EmailStatusResponse, EmailStatusResponse2, EmailStatusResponses, EmailTrackingResponse, EmailTrackingSetupResponse, EmailTrackingStatusResponse, EmbeddingData, EmbeddingInput, EmbeddingRequest, EmbeddingResponse, EmbeddingsData, EmbeddingsError, EmbeddingsErrors, EmbeddingsResponse, EmbeddingsResponses, EmbeddingUsage, EnableBackupScheduleData, EnableBackupScheduleErrors, EnableBackupScheduleResponse, EnableBackupScheduleResponses, EnableBlobRequest, EnableBlobResponse, EnableKvRequest, EnableKvResponse, EnablePgStatStatementsResponse, EndpointDto, EnqueuedJob, EnrichVisitorData, EnrichVisitorErrors, EnrichVisitorRequest, EnrichVisitorResponse, EnrichVisitorResponse2, EnrichVisitorResponses, EnrollmentTokenInfo, EnrollmentTokenListResponse, EntityInfoResponse, EntityResponse, EnvironmentConfiguration, EnvironmentDomainResponse, EnvironmentInfo, EnvironmentResponse, EnvironmentVariable, EnvironmentVariableInfo, EnvironmentVariableResponse, EnvironmentVariableValueResponse, EnvVarInput, EnvVarIntegrationInfo, EnvVarResponse, EnvVarTemplateResponse, ErrorDashboardStatsQuery, ErrorDashboardStatsResponse, ErrorEventResponse, ErrorGroupResponse, ErrorGroupStatsResponse, ErrorResponse, ErrorRow, ErrorTimeSeriesDataResponse, ErrorTimeSeriesQuery, EventActivityBucket, EventBreakdown, EventBrowserStats, EventCount, EventCountryStats, EventDetailQuery, EventDetailResponse, EventEntriesQuery, EventEntriesResponse, EventEntryInfo, EventKind, EventMetricsPayload, EventReferrerStats, EventsCountQuery, EventsResponse, EventTimeline, EventTimelineQuery, EventType, EventTypeBreakdown, EventTypeBreakdownQuery, EventTypeResponse, EventTypesResponse, EventVisitorInfo, EventVisitorsQuery, EventVisitorsResponse, ExecBody, ExecData, ExecDetachedData, ExecDetachedErrors, ExecDetachedResponse, ExecDetachedResponse2, ExecDetachedResponses, ExecErrors, ExecResponse, ExecResponse2, ExecResponses, ExecuteDeploymentOperationData, ExecuteDeploymentOperationErrors, ExecuteDeploymentOperationResponse, ExecuteDeploymentOperationResponses, ExecuteImportData, ExecuteImportErrors, ExecuteImportRequest, ExecuteImportResponse, ExecuteImportResponse2, ExecuteImportResponses, ExecuteOperationRequest, ExpireRequest, ExpireResponse, ExplorerSupportResponse, ExtendTimeoutBody, ExtendTimeoutData, ExtendTimeoutErrors, ExtendTimeoutResponse, ExtendTimeoutResponses, ExternalImageResponse, ExternalServiceBackupResponse, ExternalServiceDetails, ExternalServiceEnablePgStatStatementsData, ExternalServiceEnablePgStatStatementsErrors, ExternalServiceEnablePgStatStatementsResponse, ExternalServiceEnablePgStatStatementsResponses, ExternalServiceInfo, ExternalServiceMetricsByDatabaseData, ExternalServiceMetricsByDatabaseErrors, ExternalServiceMetricsByDatabaseResponse, ExternalServiceMetricsByDatabaseResponses, ExternalServiceMetricsCreateAlertRuleData, ExternalServiceMetricsCreateAlertRuleErrors, ExternalServiceMetricsCreateAlertRuleResponse, ExternalServiceMetricsCreateAlertRuleResponses, ExternalServiceMetricsDeleteAlertRuleData, ExternalServiceMetricsDeleteAlertRuleErrors, ExternalServiceMetricsDeleteAlertRuleResponse, ExternalServiceMetricsDeleteAlertRuleResponses, ExternalServiceMetricsGetAlertRulesData, ExternalServiceMetricsGetAlertRulesErrors, ExternalServiceMetricsGetAlertRulesResponse, ExternalServiceMetricsGetAlertRulesResponses, ExternalServiceMetricsGetLatestData, ExternalServiceMetricsGetLatestErrors, ExternalServiceMetricsGetLatestResponse, ExternalServiceMetricsGetLatestResponses, ExternalServiceMetricsGetRangeData, ExternalServiceMetricsGetRangeErrors, ExternalServiceMetricsGetRangeResponse, ExternalServiceMetricsGetRangeResponses, ExternalServiceMetricsStatusData, ExternalServiceMetricsStatusErrors, ExternalServiceMetricsStatusResponse, ExternalServiceMetricsStatusResponses, ExternalServiceMetricsToggleData, ExternalServiceMetricsToggleErrors, ExternalServiceMetricsToggleResponses, ExternalServiceMetricsUpdateAlertRuleData, ExternalServiceMetricsUpdateAlertRuleErrors, ExternalServiceMetricsUpdateAlertRuleResponse, ExternalServiceMetricsUpdateAlertRuleResponses, ExternalServiceResetPgStatStatementsData, ExternalServiceResetPgStatStatementsErrors, ExternalServiceResetPgStatStatementsResponse, ExternalServiceResetPgStatStatementsResponses, ExternalServiceSummary, FieldResponse, FinalizeOrderData, FinalizeOrderErrors, FinalizeOrderResponse, FinalizeOrderResponses, FinalizeProjectReleaseData, FinalizeProjectReleaseErrors, FinalizeProjectReleaseResponse, FinalizeProjectReleaseResponses, FindConversationData, FindConversationErrors, FindConversationResponse, FindConversationResponses, FiringSeriesEntry, FlagEnvironmentResponse, FlagListResponse, FlagResponse, FlagSnapshot, FlagSnapshotResponse, FlagValueType, ForecastAlgorithm, ForecastParams, FullError, FullEvent, FullRequest, FunnelMetricsResponse, FunnelResponse, GatewayStatus, GenAiEvent, GenAiSpanDetail, GenAiTraceDetailResponse, GenAiTraceSummariesResponse, GenAiTraceSummary, GeneralStatsQuery, GeneralStatsResponse, GenerateDockerfileRequest, GenerateDockerfileResponse, GenerateJoinTokenData, GenerateJoinTokenErrors, GenerateJoinTokenResponse, GenerateJoinTokenResponse2, GenerateJoinTokenResponses, GeneratePresetDockerfileData, GeneratePresetDockerfileErrors, GeneratePresetDockerfileResponse, GeneratePresetDockerfileResponses, GeoLocationResponse, GeoRestrictionsConfig, GetAccessInfoData, GetAccessInfoErrors, GetAccessInfoResponse, GetAccessInfoResponses, GetActiveVisitorsData, GetActiveVisitorsErrors, GetActiveVisitorsResponse, GetActiveVisitorsResponses, GetActivityGraphData, GetActivityGraphErrors, GetActivityGraphResponse, GetActivityGraphResponses, GetAdminGateData, GetAdminGateErrors, GetAdminGateResponse, GetAdminGateResponses, GetAgentData, GetAgentErrors, GetAgentResponse, GetAgentResponses, GetAggregatedBucketsData, GetAggregatedBucketsErrors, GetAggregatedBucketsResponse, GetAggregatedBucketsResponses, GetAiAgentBreakdownData, GetAiAgentBreakdownError, GetAiAgentBreakdownErrors, GetAiAgentBreakdownResponse, GetAiAgentBreakdownResponses, GetAiAgentPagesData, GetAiAgentPagesError, GetAiAgentPagesErrors, GetAiAgentPagesResponse, GetAiAgentPagesResponses, GetAiAgentTimelineData, GetAiAgentTimelineError, GetAiAgentTimelineErrors, GetAiAgentTimelineResponse, GetAiAgentTimelineResponses, GetAiPageBreakdownData, GetAiPageBreakdownError, GetAiPageBreakdownErrors, GetAiPageBreakdownResponse, GetAiPageBreakdownResponses, GetAiStatusBreakdownData, GetAiStatusBreakdownError, GetAiStatusBreakdownErrors, GetAiStatusBreakdownResponse, GetAiStatusBreakdownResponses, GetAlertData, GetAlertError, GetAlertErrors, GetAlertResponse, GetAlertResponses, GetAlertRuleData, GetAlertRuleErrors, GetAlertRuleResponse, GetAlertRuleResponses, GetAllRepositoriesByNameData, GetAllRepositoriesByNameErrors, GetAllRepositoriesByNameResponse, GetAllRepositoriesByNameResponses, GetAnalyticsActiveVisitorsData, GetAnalyticsActiveVisitorsErrors, GetAnalyticsActiveVisitorsResponse, GetAnalyticsActiveVisitorsResponses, GetAnalyticsEventsCountData, GetAnalyticsEventsCountErrors, GetAnalyticsEventsCountResponse, GetAnalyticsEventsCountResponses, GetAnalyticsSessionEventsData, GetAnalyticsSessionEventsErrors, GetAnalyticsSessionEventsResponse, GetAnalyticsSessionEventsResponses, GetAnalyticsVisitorSessionsData, GetAnalyticsVisitorSessionsErrors, GetAnalyticsVisitorSessionsResponse, GetAnalyticsVisitorSessionsResponses, GetApiKeyData, GetApiKeyErrors, GetApiKeyPermissionsData, GetApiKeyPermissionsErrors, GetApiKeyPermissionsResponse, GetApiKeyPermissionsResponses, GetApiKeyResponse, GetApiKeyResponses, GetAuditLogData, GetAuditLogErrors, GetAuditLogResponse, GetAuditLogResponses, GetBackupData, GetBackupError, GetBackupErrors, GetBackupResponse, GetBackupResponses, GetBackupScheduleData, GetBackupScheduleErrors, GetBackupScheduleResponse, GetBackupScheduleResponses, GetBranchesByRepositoryIdData, GetBranchesByRepositoryIdErrors, GetBranchesByRepositoryIdResponse, GetBranchesByRepositoryIdResponses, GetBucketedIncidentsData, GetBucketedIncidentsErrors, GetBucketedIncidentsResponse, GetBucketedIncidentsResponses, GetBucketedStatusData, GetBucketedStatusErrors, GetBucketedStatusResponse, GetBucketedStatusResponses, GetChallengeTokenData, GetChallengeTokenErrors, GetChallengeTokenResponse, GetChallengeTokenResponses, GetChatReadinessData, GetChatReadinessErrors, GetChatReadinessResponse, GetChatReadinessResponses, GetCliStatusData, GetCliStatusErrors, GetCliStatusResponses, GetClusterHealthData, GetClusterHealthErrors, GetClusterHealthResponse, GetClusterHealthResponses, GetClusterMemberData, GetClusterMemberErrors, GetClusterMemberResponse, GetClusterMemberResponses, GetCmdData, GetCmdErrors, GetCmdResponse, GetCmdResponses, GetContainerDetailData, GetContainerDetailErrors, GetContainerDetailResponse, GetContainerDetailResponses, GetContainerEnvironmentVariableData, GetContainerEnvironmentVariableErrors, GetContainerEnvironmentVariableResponse, GetContainerEnvironmentVariableResponses, GetContainerInfoData, GetContainerInfoErrors, GetContainerInfoResponse, GetContainerInfoResponses, GetContainerLogsByIdData, GetContainerLogsByIdErrors, GetContainerLogsData, GetContainerLogsErrors, GetContainerMetricsData, GetContainerMetricsErrors, GetContainerMetricsResponse, GetContainerMetricsResponses, GetConversationData, GetConversationDetailData, GetConversationDetailError, GetConversationDetailErrors, GetConversationDetailResponse, GetConversationDetailResponses, GetConversationErrors, GetConversationResponse, GetConversationResponses, GetConversationsData, GetConversationsError, GetConversationsErrors, GetConversationsResponse, GetConversationsResponses, GetCronByIdData, GetCronByIdErrors, GetCronByIdResponse, GetCronByIdResponses, GetCronExecutionsData, GetCronExecutionsErrors, GetCronExecutionsResponse, GetCronExecutionsResponses, GetCrossProjectTraceSiblingsData, GetCrossProjectTraceSiblingsError, GetCrossProjectTraceSiblingsErrors, GetCrossProjectTraceSiblingsResponse, GetCrossProjectTraceSiblingsResponses, GetCurrentMonitorStatusData, GetCurrentMonitorStatusErrors, GetCurrentMonitorStatusResponse, GetCurrentMonitorStatusResponses, GetCurrentUserData, GetCurrentUserErrors, GetCurrentUserResponse, GetCurrentUserResponses, GetCustomDomainData, GetCustomDomainErrors, GetCustomDomainResponse, GetCustomDomainResponses, GetDashboardData, GetDashboardError, GetDashboardErrors, GetDashboardProjectsAnalyticsData, GetDashboardProjectsAnalyticsErrors, GetDashboardProjectsAnalyticsResponse, GetDashboardProjectsAnalyticsResponses, GetDashboardResponse, GetDashboardResponses, GetDeliveryData, GetDeliveryErrors, GetDeliveryResponse, GetDeliveryResponses, GetDeploymentContainerLogContentData, GetDeploymentContainerLogContentErrors, GetDeploymentContainerLogContentResponse, GetDeploymentContainerLogContentResponses, GetDeploymentData, GetDeploymentErrors, GetDeploymentJobLogsData, GetDeploymentJobLogsErrors, GetDeploymentJobLogsResponse, GetDeploymentJobLogsResponses, GetDeploymentJobsData, GetDeploymentJobsErrors, GetDeploymentJobsResponse, GetDeploymentJobsResponses, GetDeploymentOperationsData, GetDeploymentOperationsErrors, GetDeploymentOperationsResponse, GetDeploymentOperationsResponses, GetDeploymentOperationStatusData, GetDeploymentOperationStatusErrors, GetDeploymentOperationStatusResponse, GetDeploymentOperationStatusResponses, GetDeploymentResponse, GetDeploymentResponses, GetDeploymentsParams, GetDeploymentTokenData, GetDeploymentTokenErrors, GetDeploymentTokenResponse, GetDeploymentTokenResponses, GetDiskStatusData, GetDiskStatusErrors, GetDiskStatusResponse, GetDiskStatusResponses, GetDnsChangesData, GetDnsChangesErrors, GetDnsChangesResponse, GetDnsChangesResponses, GetDnsProviderData, GetDnsProviderErrors, GetDnsProviderResponse, GetDnsProviderResponses, GetDomainByHostData, GetDomainByHostErrors, GetDomainByHostResponse, GetDomainByHostResponses, GetDomainByIdData, GetDomainByIdErrors, GetDomainByIdResponse, GetDomainByIdResponses, GetDomainByNameData, GetDomainByNameErrors, GetDomainByNameResponse, GetDomainByNameResponses, GetDomainData, GetDomainDnsRecordsData, GetDomainDnsRecordsErrors, GetDomainDnsRecordsResponse, GetDomainDnsRecordsResponses, GetDomainErrors, GetDomainOrderData, GetDomainOrderErrors, GetDomainOrderResponse, GetDomainOrderResponses, GetDomainResponse, GetDomainResponses, GetEmailData, GetEmailErrors, GetEmailEventsData, GetEmailEventsErrors, GetEmailEventsResponse, GetEmailEventsResponses, GetEmailLinksData, GetEmailLinksErrors, GetEmailLinksResponse, GetEmailLinksResponses, GetEmailProviderData, GetEmailProviderErrors, GetEmailProviderResponse, GetEmailProviderResponses, GetEmailResponse, GetEmailResponses, GetEmailStatsData, GetEmailStatsErrors, GetEmailStatsResponse, GetEmailStatsResponses, GetEmailTrackingData, GetEmailTrackingErrors, GetEmailTrackingResponse, GetEmailTrackingResponses, GetEmailTrackingStatusData, GetEmailTrackingStatusErrors, GetEmailTrackingStatusResponse, GetEmailTrackingStatusResponses, GetEntityInfoData, GetEntityInfoErrors, GetEntityInfoResponse, GetEntityInfoResponses, GetEnvironmentCronsData, GetEnvironmentCronsErrors, GetEnvironmentCronsResponse, GetEnvironmentCronsResponses, GetEnvironmentData, GetEnvironmentDomainsData, GetEnvironmentDomainsErrors, GetEnvironmentDomainsResponse, GetEnvironmentDomainsResponses, GetEnvironmentErrors, GetEnvironmentResponse, GetEnvironmentResponses, GetEnvironmentsData, GetEnvironmentsErrors, GetEnvironmentsResponse, GetEnvironmentsResponses, GetEnvironmentVariablesData, GetEnvironmentVariablesErrors, GetEnvironmentVariablesQuery, GetEnvironmentVariablesResponse, GetEnvironmentVariablesResponses, GetEnvironmentVariableValueData, GetEnvironmentVariableValueErrors, GetEnvironmentVariableValueResponse, GetEnvironmentVariableValueResponses, GetErrorDashboardStatsData, GetErrorDashboardStatsErrors, GetErrorDashboardStatsResponse, GetErrorDashboardStatsResponses, GetErrorEventData, GetErrorEventErrors, GetErrorEventResponse, GetErrorEventResponses, GetErrorGroupData, GetErrorGroupErrors, GetErrorGroupResponse, GetErrorGroupResponses, GetErrorStatsData, GetErrorStatsErrors, GetErrorStatsResponse, GetErrorStatsResponses, GetErrorTimeSeriesData, GetErrorTimeSeriesErrors, GetErrorTimeSeriesResponse, GetErrorTimeSeriesResponses, GetEventDetailData, GetEventDetailErrors, GetEventDetailResponse, GetEventDetailResponses, GetEventEntriesData, GetEventEntriesErrors, GetEventEntriesResponse, GetEventEntriesResponses, GetEventsCountData, GetEventsCountErrors, GetEventsCountResponse, GetEventsCountResponses, GetEventsTimelineData, GetEventsTimelineErrors, GetEventsTimelineResponse, GetEventsTimelineResponses, GetEventTypeBreakdownData, GetEventTypeBreakdownErrors, GetEventTypeBreakdownResponse, GetEventTypeBreakdownResponses, GetEventVisitorsData, GetEventVisitorsErrors, GetEventVisitorsResponse, GetEventVisitorsResponses, GetExternalImageData, GetExternalImageErrors, GetExternalImageResponse, GetExternalImageResponses, GetFileData, GetFileErrors, GetFileResponse, GetFileResponses, GetFlagData, GetFlagErrors, GetFlagResponse, GetFlagResponses, GetFlagSnapshotData, GetFlagSnapshotErrors, GetFlagSnapshotResponse, GetFlagSnapshotResponses, GetFunnelMetricsData, GetFunnelMetricsErrors, GetFunnelMetricsQuery, GetFunnelMetricsResponse, GetFunnelMetricsResponses, GetGenaiTraceData, GetGenaiTraceError, GetGenaiTraceErrors, GetGenaiTraceResponse, GetGenaiTraceResponses, GetGeneralStatsData, GetGeneralStatsErrors, GetGeneralStatsResponse, GetGeneralStatsResponses, GetGitProviderData, GetGitProviderErrors, GetGitProviderResponse, GetGitProviderResponses, GetGlobalEventsData, GetGlobalEventsErrors, GetGlobalEventsResponse, GetGlobalEventsResponses, GetGlobalEventStatsData, GetGlobalEventStatsErrors, GetGlobalEventStatsResponse, GetGlobalEventStatsResponses, GetGlobalMcpData, GetGlobalMcpErrors, GetGlobalMcpResponse, GetGlobalMcpResponses, GetGlobalSandboxStatusData, GetGlobalSandboxStatusErrors, GetGlobalSandboxStatusResponse, GetGlobalSandboxStatusResponses, GetGlobalSkillData, GetGlobalSkillErrors, GetGlobalSkillResponse, GetGlobalSkillResponses, GetGroupedPageMetricsData, GetGroupedPageMetricsError, GetGroupedPageMetricsErrors, GetGroupedPageMetricsResponse, GetGroupedPageMetricsResponses, GetHealthData, GetHealthError, GetHealthErrors, GetHealthResponse, GetHealthResponses, GetHourlyVisitsData, GetHourlyVisitsErrors, GetHourlyVisitsResponse, GetHourlyVisitsResponses, GetHttpChallengeDebugData, GetHttpChallengeDebugErrors, GetHttpChallengeDebugResponse, GetHttpChallengeDebugResponses, GetImportStatusData, GetImportStatusErrors, GetImportStatusResponse, GetImportStatusResponses, GetIncidentData, GetIncidentErrors, GetIncidentResponse, GetIncidentResponses, GetIncidentUpdatesData, GetIncidentUpdatesErrors, GetIncidentUpdatesResponse, GetIncidentUpdatesResponses, GetIpAccessControlData, GetIpAccessControlError, GetIpAccessControlErrors, GetIpAccessControlResponse, GetIpAccessControlResponses, GetIpGeolocationData, GetIpGeolocationError, GetIpGeolocationErrors, GetIpGeolocationResponse, GetIpGeolocationResponses, GetJoinTokenStatusData, GetJoinTokenStatusErrors, GetJoinTokenStatusResponse, GetJoinTokenStatusResponses, GetLastDeploymentData, GetLastDeploymentErrors, GetLastDeploymentResponse, GetLastDeploymentResponses, GetLatestScanData, GetLatestScanError, GetLatestScanErrors, GetLatestScanResponse, GetLatestScanResponses, GetLatestScansPerEnvironmentData, GetLatestScansPerEnvironmentError, GetLatestScansPerEnvironmentErrors, GetLatestScansPerEnvironmentResponse, GetLatestScansPerEnvironmentResponses, GetLiveVisitorsListData, GetLiveVisitorsListErrors, GetLiveVisitorsListResponse, GetLiveVisitorsListResponses, GetLogContextData, GetLogContextError, GetLogContextErrors, GetLogContextResponse, GetLogContextResponses, GetMcpData, GetMcpErrors, GetMcpResponse, GetMcpResponses, GetMetricsOverTimeData, GetMetricsOverTimeError, GetMetricsOverTimeErrors, GetMetricsOverTimeResponse, GetMetricsOverTimeResponses, GetMonitorData, GetMonitorErrors, GetMonitorResponse, GetMonitorResponses, GetNotificationProviderData, GetNotificationProviderErrors, GetNotificationProviderResponse, GetNotificationProviderResponses, GetOnDemandCertStatusData, GetOnDemandCertStatusErrors, GetOnDemandCertStatusResponse, GetOnDemandCertStatusResponses, GetOrCreateDsnData, GetOrCreateDsnErrors, GetOrCreateDsnRequest, GetOrCreateDsnResponse, GetOrCreateDsnResponses, GetPageFlowData, GetPageFlowErrors, GetPageFlowResponse, GetPageFlowResponses, GetPageHourlySessionsData, GetPageHourlySessionsErrors, GetPageHourlySessionsResponse, GetPageHourlySessionsResponses, GetPagePathDetailData, GetPagePathDetailErrors, GetPagePathDetailResponse, GetPagePathDetailResponses, GetPagePathsData, GetPagePathsErrors, GetPagePathsResponse, GetPagePathsResponses, GetPagePathsSparklinesData, GetPagePathsSparklinesErrors, GetPagePathsSparklinesResponse, GetPagePathsSparklinesResponses, GetPagePathVisitorsData, GetPagePathVisitorsErrors, GetPagePathVisitorsResponse, GetPagePathVisitorsResponses, GetPendingActionData, GetPendingActionErrors, GetPendingActionResponse, GetPendingActionResponses, GetPerformanceMetricsData, GetPerformanceMetricsError, GetPerformanceMetricsErrors, GetPerformanceMetricsResponse, GetPerformanceMetricsResponses, GetPgUpgradeData, GetPgUpgradeErrors, GetPgUpgradeLogsData, GetPgUpgradeLogsErrors, GetPgUpgradeLogsResponse, GetPgUpgradeLogsResponses, GetPgUpgradeResponse, GetPgUpgradeResponses, GetPipelineStatsData, GetPipelineStatsError, GetPipelineStatsErrors, GetPipelineStatsResponse, GetPipelineStatsResponses, GetPlatformInfoData, GetPlatformInfoErrors, GetPlatformInfoResponse, GetPlatformInfoResponses, GetPostgresWalHealthData, GetPostgresWalHealthErrors, GetPostgresWalHealthResponse, GetPostgresWalHealthResponses, GetPreferencesData, GetPreferencesErrors, GetPreferencesResponse, GetPreferencesResponses, GetPreviewGatewayLogsData, GetPreviewGatewayLogsResponse, GetPreviewGatewayLogsResponses, GetPreviewGatewaySettingsData, GetPreviewGatewaySettingsResponse, GetPreviewGatewaySettingsResponses, GetPreviewGatewayStatusData, GetPreviewGatewayStatusResponse, GetPreviewGatewayStatusResponses, GetPricingData, GetPricingError, GetPricingErrors, GetPricingResponse, GetPricingResponses, GetPrivateIpData, GetPrivateIpErrors, GetPrivateIpResponses, GetProjectAlarmsSummaryData, GetProjectAlarmsSummaryErrors, GetProjectAlarmsSummaryResponse, GetProjectAlarmsSummaryResponses, GetProjectBySlugData, GetProjectBySlugErrors, GetProjectBySlugResponse, GetProjectBySlugResponses, GetProjectData, GetProjectDeploymentsData, GetProjectDeploymentsErrors, GetProjectDeploymentsResponse, GetProjectDeploymentsResponses, GetProjectErrors, GetProjectResponse, GetProjectResponses, GetProjectsData, GetProjectSecretsQuery, GetProjectsErrors, GetProjectServiceEnvironmentVariablesData, GetProjectServiceEnvironmentVariablesErrors, GetProjectServiceEnvironmentVariablesResponse, GetProjectServiceEnvironmentVariablesResponses, GetProjectSessionReplaysData, GetProjectSessionReplaysError, GetProjectSessionReplaysErrors, GetProjectSessionReplaysQuery, GetProjectSessionReplaysResponse, GetProjectSessionReplaysResponse2, GetProjectSessionReplaysResponses, GetProjectsHealthData, GetProjectsHealthError, GetProjectsHealthErrors, GetProjectsHealthResponse, GetProjectsHealthResponses, GetProjectsMonitorHealthData, GetProjectsMonitorHealthErrors, GetProjectsMonitorHealthResponse, GetProjectsMonitorHealthResponses, GetProjectsResponse, GetProjectsResponses, GetProjectStatisticsData, GetProjectStatisticsErrors, GetProjectStatisticsResponse, GetProjectStatisticsResponses, GetProjectTemplateData, GetProjectTemplateErrors, GetProjectTemplateResponse, GetProjectTemplateResponses, GetPropertyBreakdownData, GetPropertyBreakdownErrors, GetPropertyBreakdownResponse, GetPropertyBreakdownResponses, GetPropertyTimelineData, GetPropertyTimelineErrors, GetPropertyTimelineResponse, GetPropertyTimelineResponses, GetProviderConnectionsData, GetProviderConnectionsErrors, GetProviderConnectionsResponse, GetProviderConnectionsResponses, GetProviderMetadataData, GetProviderMetadataErrors, GetProviderMetadataResponse, GetProviderMetadataResponses, GetProvidersMetadataData, GetProvidersMetadataErrors, GetProvidersMetadataResponse, GetProvidersMetadataResponses, GetProxyLogByIdData, GetProxyLogByIdError, GetProxyLogByIdErrors, GetProxyLogByIdResponse, GetProxyLogByIdResponses, GetProxyLogByRequestIdData, GetProxyLogByRequestIdError, GetProxyLogByRequestIdErrors, GetProxyLogByRequestIdResponse, GetProxyLogByRequestIdResponses, GetProxyLogsData, GetProxyLogsError, GetProxyLogsErrors, GetProxyLogsResponse, GetProxyLogsResponses, GetPublicBranchesData, GetPublicBranchesErrors, GetPublicBranchesResponse, GetPublicBranchesResponses, GetPublicIpData, GetPublicIpErrors, GetPublicIpResponses, GetPublicRepositoryData, GetPublicRepositoryErrors, GetPublicRepositoryResponse, GetPublicRepositoryResponses, GetQuotaData, GetQuotaError, GetQuotaErrors, GetQuotaResponse, GetQuotaResponses, GetRecentActivityData, GetRecentActivityErrors, GetRecentActivityResponse, GetRecentActivityResponses, GetRemoteExternalImageData, GetRemoteExternalImageErrors, GetRemoteExternalImageResponse, GetRemoteExternalImageResponses, GetRepositoryBranchesData, GetRepositoryBranchesErrors, GetRepositoryBranchesResponse, GetRepositoryBranchesResponses, GetRepositoryByIdData, GetRepositoryByIdErrors, GetRepositoryByIdResponse, GetRepositoryByIdResponses, GetRepositoryByNameData, GetRepositoryByNameErrors, GetRepositoryByNameResponse, GetRepositoryByNameResponses, GetRepositoryPresetByNameData, GetRepositoryPresetByNameErrors, GetRepositoryPresetByNameResponse, GetRepositoryPresetByNameResponses, GetRepositoryPresetLiveData, GetRepositoryPresetLiveErrors, GetRepositoryPresetLiveResponse, GetRepositoryPresetLiveResponses, GetRepositoryTagsData, GetRepositoryTagsErrors, GetRepositoryTagsResponse, GetRepositoryTagsResponses, GetRequest, GetResolvedEnvironmentVariablesData, GetResolvedEnvironmentVariablesErrors, GetResolvedEnvironmentVariablesResponse, GetResolvedEnvironmentVariablesResponses, GetResolvedEnvironmentVariableValueData, GetResolvedEnvironmentVariableValueErrors, GetResolvedEnvironmentVariableValueResponse, GetResolvedEnvironmentVariableValueResponses, GetResponse, GetRestoreCapabilitiesData, GetRestoreCapabilitiesError, GetRestoreCapabilitiesErrors, GetRestoreCapabilitiesResponse, GetRestoreCapabilitiesResponses, GetRestoreRunData, GetRestoreRunError, GetRestoreRunErrors, GetRestoreRunResponse, GetRestoreRunResponses, GetRouteData, GetRouteErrors, GetRouteResponse, GetRouteResponses, GetRunData, GetRunErrors, GetRunResponse, GetRunResponses, GetRunWithLogsData, GetRunWithLogsErrors, GetRunWithLogsResponse, GetRunWithLogsResponses, GetS3CredentialsData, GetS3CredentialsErrors, GetS3CredentialsResponse, GetS3CredentialsResponses, GetS3SourceData, GetS3SourceError, GetS3SourceErrors, GetS3SourceResponse, GetS3SourceResponses, GetSandboxData, GetSandboxErrors, GetSandboxResponse, GetSandboxResponses, GetSandboxStatusData, GetSandboxStatusErrors, GetSandboxStatusResponse, GetSandboxStatusResponses, GetScanByDeploymentData, GetScanByDeploymentError, GetScanByDeploymentErrors, GetScanByDeploymentResponse, GetScanByDeploymentResponses, GetScanData, GetScanError, GetScanErrors, GetScanResponse, GetScanResponses, GetScanVulnerabilitiesData, GetScanVulnerabilitiesError, GetScanVulnerabilitiesErrors, GetScanVulnerabilitiesResponse, GetScanVulnerabilitiesResponses, GetServiceBySlugData, GetServiceBySlugErrors, GetServiceBySlugResponse, GetServiceBySlugResponses, GetServiceData, GetServiceEnvironmentVariableData, GetServiceEnvironmentVariableErrors, GetServiceEnvironmentVariableResponse, GetServiceEnvironmentVariableResponses, GetServiceEnvironmentVariablesData, GetServiceEnvironmentVariablesErrors, GetServiceEnvironmentVariablesResponse, GetServiceEnvironmentVariablesResponses, GetServiceErrors, GetServiceHealthStatusData, GetServiceHealthStatusErrors, GetServiceHealthStatusResponse, GetServiceHealthStatusResponses, GetServicePreviewEnvironmentVariableNamesData, GetServicePreviewEnvironmentVariableNamesErrors, GetServicePreviewEnvironmentVariableNamesResponse, GetServicePreviewEnvironmentVariableNamesResponses, GetServicePreviewEnvironmentVariablesMaskedData, GetServicePreviewEnvironmentVariablesMaskedErrors, GetServicePreviewEnvironmentVariablesMaskedResponse, GetServicePreviewEnvironmentVariablesMaskedResponses, GetServiceResponse, GetServiceResponses, GetServiceRuntimeData, GetServiceRuntimeErrors, GetServiceRuntimeResponse, GetServiceRuntimeResponses, GetServiceStatsData, GetServiceStatsErrors, GetServiceStatsResponse, GetServiceStatsResponses, GetServiceTypeParametersData, GetServiceTypeParametersErrors, GetServiceTypeParametersResponses, GetServiceTypesData, GetServiceTypesErrors, GetServiceTypesResponse, GetServiceTypesResponses, GetSessionDetailsData, GetSessionDetailsErrors, GetSessionDetailsResponse, GetSessionDetailsResponses, GetSessionEventsData, GetSessionEventsErrors, GetSessionEventsResponse, GetSessionEventsResponses, GetSessionLogsData, GetSessionLogsErrors, GetSessionLogsResponse, GetSessionLogsResponses, GetSessionReplayData, GetSessionReplayError, GetSessionReplayErrors, GetSessionReplayEventsData, GetSessionReplayEventsError, GetSessionReplayEventsErrors, GetSessionReplayEventsResponse, GetSessionReplayEventsResponses, GetSessionReplayResponse, GetSessionReplayResponse2, GetSessionReplayResponses, GetSettingsData, GetSettingsErrors, GetSettingsResponse, GetSettingsResponses, GetSkillData, GetSkillErrors, GetSkillResponse, GetSkillResponses, GetSlowQueriesData, GetSlowQueriesErrors, GetSlowQueriesResponse, GetSlowQueriesResponses, GetStaticBundleData, GetStaticBundleErrors, GetStaticBundleResponse, GetStaticBundleResponses, GetStatusOverviewData, GetStatusOverviewErrors, GetStatusOverviewResponse, GetStatusOverviewResponses, GetTagsByRepositoryIdData, GetTagsByRepositoryIdErrors, GetTagsByRepositoryIdResponse, GetTagsByRepositoryIdResponses, GetTeamData, GetTeamErrors, GetTeamResponse, GetTeamResponses, GetTimeBucketStatsData, GetTimeBucketStatsError, GetTimeBucketStatsErrors, GetTimeBucketStatsResponse, GetTimeBucketStatsResponses, GetTodayStatsData, GetTodayStatsError, GetTodayStatsErrors, GetTodayStatsResponse, GetTodayStatsResponses, GetTraceData, GetTraceError, GetTraceErrors, GetTraceResponse, GetTraceResponses, GetUnifiedTraceData, GetUnifiedTraceError, GetUnifiedTraceErrors, GetUnifiedTraceResponse, GetUnifiedTraceResponses, GetUniqueCountsData, GetUniqueCountsErrors, GetUniqueCountsResponse, GetUniqueCountsResponses, GetUniqueEventsData, GetUniqueEventsErrors, GetUniqueEventsQuery, GetUniqueEventsResponse, GetUniqueEventsResponses, GetUpdateStatusData, GetUpdateStatusErrors, GetUpdateStatusResponse, GetUpdateStatusResponses, GetUptimeHistoryData, GetUptimeHistoryErrors, GetUptimeHistoryResponse, GetUptimeHistoryResponses, GetUsageByProviderData, GetUsageByProviderError, GetUsageByProviderErrors, GetUsageByProviderResponse, GetUsageByProviderResponses, GetUsageRecentData, GetUsageRecentError, GetUsageRecentErrors, GetUsageRecentResponse, GetUsageRecentResponses, GetUsageSummaryData, GetUsageSummaryError, GetUsageSummaryErrors, GetUsageSummaryResponse, GetUsageSummaryResponses, GetUsageTimeseriesData, GetUsageTimeseriesError, GetUsageTimeseriesErrors, GetUsageTimeseriesResponse, GetUsageTimeseriesResponses, GetUsageTopModelsData, GetUsageTopModelsError, GetUsageTopModelsErrors, GetUsageTopModelsResponse, GetUsageTopModelsResponses, GetVisitorByGuidData, GetVisitorByGuidErrors, GetVisitorByGuidResponse, GetVisitorByGuidResponses, GetVisitorByIdData, GetVisitorByIdErrors, GetVisitorByIdResponse, GetVisitorByIdResponses, GetVisitorDetailsData, GetVisitorDetailsErrors, GetVisitorDetailsResponse, GetVisitorDetailsResponses, GetVisitorFacetsData, GetVisitorFacetsErrors, GetVisitorFacetsResponse, GetVisitorFacetsResponses, GetVisitorInfoData, GetVisitorInfoErrors, GetVisitorInfoResponse, GetVisitorInfoResponses, GetVisitorJourneyData, GetVisitorJourneyErrors, GetVisitorJourneyResponse, GetVisitorJourneyResponses, GetVisitorsData, GetVisitorsErrors, GetVisitorSessionsData, GetVisitorSessionsError, GetVisitorSessionsErrors, GetVisitorSessionsQuery, GetVisitorSessionsResponse, GetVisitorSessionsResponse2, GetVisitorSessionsResponses, GetVisitorsResponse, GetVisitorsResponses, GetVisitorStatsData, GetVisitorStatsErrors, GetVisitorStatsResponse, GetVisitorStatsResponses, GetWebhookData, GetWebhookErrors, GetWebhookResponse, GetWebhookResponses, GitPushEvent, GitRefResponse, GitSourcePlan, GlobalConversationResponse, GlobalEventStatsResponse, GlobalMrrResponse, GlobalRecentEventResponse, GlobalRevenueSummaryResponse, GrantProjectAccessData, GrantProjectAccessErrors, GrantProjectAccessResponse, GrantProjectAccessResponses, GroupedPageMetric, GroupedPageMetricsQuery, GroupedPageMetricsResponse, HandleGitProviderOauthCallbackData, HandleGitProviderOauthCallbackErrors, HasAnalyticsEventsData, HasAnalyticsEventsErrors, HasAnalyticsEventsResponse, HasAnalyticsEventsResponse2, HasAnalyticsEventsResponses, HasErrorGroupsData, HasErrorGroupsErrors, HasErrorGroupsResponse, HasErrorGroupsResponse2, HasErrorGroupsResponses, HasEventsQuery, HasEventsResponse, HasMetricsQuery, HasMetricsResponse, HasPerformanceMetricsData, HasPerformanceMetricsError, HasPerformanceMetricsErrors, HasPerformanceMetricsResponse, HasPerformanceMetricsResponses, HealthCheckConfiguration, HealthCheckEntryResponse, HealthResponse, HealthStatus, HealthSummary, HeartbeatApiRequest, HeartbeatResponse, HierarchyLevel, HistogramSummary, HostnameChange, HostnamePreviewResponse, HourlyPageSessions, HourlyVisitsQuery, HttpChallengeDebugResponse, ImportCredentials, ImportExecutionStatus, ImportExternalServiceData, ImportExternalServiceErrors, ImportExternalServiceRequest, ImportExternalServiceResponse, ImportExternalServiceResponses, ImportOutcomeResponse, ImportPlan, ImportRowErrorResponse, ImportSelector, ImportSource, ImportSourceCapabilities, ImportSourceInfo, ImportStatusResponse, IncidentBucket, IncidentBucketedResponse, IncidentResponse, IncidentUpdateResponse, IncrRequest, IncrResponse, IngestLogsByPathData, IngestLogsByPathError, IngestLogsByPathErrors, IngestLogsByPathResponses, IngestLogsData, IngestLogsError, IngestLogsErrors, IngestLogsResponses, IngestMetricsByPathData, IngestMetricsByPathError, IngestMetricsByPathErrors, IngestMetricsByPathResponses, IngestMetricsData, IngestMetricsError, IngestMetricsErrors, IngestMetricsResponses, IngestSentryEnvelopeData, IngestSentryEnvelopeErrors, IngestSentryEnvelopeResponses, IngestSentryEventData, IngestSentryEventErrors, IngestSentryEventResponse, IngestSentryEventResponses, IngestTracesByPathData, IngestTracesByPathError, IngestTracesByPathErrors, IngestTracesByPathResponses, IngestTracesData, IngestTracesError, IngestTracesErrors, IngestTracesResponses, InitAuthResponse, InitSessionReplayData, InitSessionReplayError, InitSessionReplayErrors, InitSessionReplayResponse, InitSessionReplayResponses, Insight, InsightSeverity, InsightsResponse, InsightStatus, InspectDropArchiveData, InspectDropArchiveErrors, InspectDropArchiveResponse, InspectDropArchiveResponses, IntegrationResponse, IpAccessControlQuery, IpAccessControlResponse, JobLogsData, JobLogsErrors, JobLogsResponses, JobStatusData, JobStatusErrors, JobStatusResponse, JobStatusResponse2, JobStatusResponses, JobSummaryResponse, JoinTokenStatusResponse, JourneyEvent, JourneySession, KeysRequest, KeysResponse, KillJobBody, KillJobData, KillJobErrors, KillJobResponse, KillJobResponses, KnownAiAgentsResponse, KvDelData, KvDelErrors, KvDelResponse, KvDelResponses, KvDisableData, KvDisableErrors, KvDisableResponse, KvDisableResponses, KvEnableData, KvEnableErrors, KvEnableResponse, KvEnableResponses, KvExpireData, KvExpireErrors, KvExpireResponse, KvExpireResponses, KvGetData, KvGetErrors, KvGetResponse, KvGetResponses, KvIncrData, KvIncrErrors, KvIncrResponse, KvIncrResponses, KvKeysData, KvKeysErrors, KvKeysResponse, KvKeysResponses, KvSetData, KvSetErrors, KvSetResponse, KvSetResponses, KvStatusData, KvStatusErrors, KvStatusResponse, KvStatusResponse2, KvStatusResponses, KvTtlData, KvTtlErrors, KvTtlResponse, KvTtlResponses, KvUpdateData, KvUpdateErrors, KvUpdateResponse, KvUpdateResponses, LatestRunForSourceData, LatestRunForSourceErrors, LatestRunForSourceResponse, LatestRunForSourceResponses, LemonSqueezyConfig, LetsEncryptSettings, LineContext, LinkCustomDomainToCertificateData, LinkCustomDomainToCertificateErrors, LinkCustomDomainToCertificateResponse, LinkCustomDomainToCertificateResponses, LinkServiceRequest, LinkServiceToProjectData, LinkServiceToProjectErrors, LinkServiceToProjectResponse, LinkServiceToProjectResponses, ListAgentRunsData, ListAgentRunsErrors, ListAgentRunsResponse, ListAgentRunsResponses, ListAgentsData, ListAgentsErrors, ListAgentsResponse, ListAgentsResponse2, ListAgentsResponses, ListAiProvidersData, ListAiProvidersErrors, ListAiProvidersResponse, ListAiProvidersResponses, ListAlertRulesData, ListAlertRulesErrors, ListAlertRulesResponse, ListAlertRulesResponses, ListAlertsData, ListAlertsError, ListAlertsErrors, ListAlertsResponse, ListAlertsResponses, ListAllConversationsData, ListAllConversationsErrors, ListAllConversationsResponse, ListAllConversationsResponses, ListAllRunsData, ListAllRunsErrors, ListAllRunsResponse, ListAllRunsResponses, ListApiKeysData, ListApiKeysErrors, ListApiKeysQuery, ListApiKeysResponse, ListApiKeysResponses, ListAuditLogsData, ListAuditLogsErrors, ListAuditLogsQuery, ListAuditLogsResponse, ListAuditLogsResponses, ListAvailableContainersData, ListAvailableContainersErrors, ListAvailableContainersResponse, ListAvailableContainersResponses, ListBackupAlertsData, ListBackupAlertsError, ListBackupAlertsErrors, ListBackupAlertsResponse, ListBackupAlertsResponses, ListBackupChildrenData, ListBackupChildrenError, ListBackupChildrenErrors, ListBackupChildrenResponse, ListBackupChildrenResponses, ListBackupSchedulesData, ListBackupSchedulesError, ListBackupSchedulesErrors, ListBackupSchedulesResponse, ListBackupSchedulesResponses, ListBackupsForScheduleData, ListBackupsForScheduleErrors, ListBackupsForScheduleResponse, ListBackupsForScheduleResponses, ListBlobsQuery, ListBlobsResponse, ListCommitsByRepositoryIdData, ListCommitsByRepositoryIdErrors, ListCommitsByRepositoryIdResponse, ListCommitsByRepositoryIdResponses, ListConnectionsData, ListConnectionsErrors, ListConnectionsResponse, ListConnectionsResponses, ListContainersAtPathData, ListContainersAtPathErrors, ListContainersAtPathResponse, ListContainersAtPathResponses, ListContainersData, ListContainersErrors, ListContainersResponse, ListContainersResponses, ListConversationsData, ListConversationsErrors, ListConversationsResponse, ListConversationsResponses, ListCustomDomainsForProjectData, ListCustomDomainsForProjectErrors, ListCustomDomainsForProjectResponse, ListCustomDomainsForProjectResponses, ListCustomDomainsResponse, ListDashboardsData, ListDashboardsError, ListDashboardsErrors, ListDashboardsResponse, ListDashboardsResponses, ListDeliveriesData, ListDeliveriesErrors, ListDeliveriesResponse, ListDeliveriesResponses, ListDeploymentContainerLogsData, ListDeploymentContainerLogsErrors, ListDeploymentContainerLogsResponse, ListDeploymentContainerLogsResponses, ListDeploymentTokensData, ListDeploymentTokensErrors, ListDeploymentTokensQuery, ListDeploymentTokensResponse, ListDeploymentTokensResponses, ListDnsProvidersData, ListDnsProvidersErrors, ListDnsProvidersResponse, ListDnsProvidersResponses, ListDomainsData, ListDomainsErrors, ListDomainsResponse, ListDomainsResponse2, ListDomainsResponses, ListDsnsData, ListDsnsErrors, ListDsnsResponse, ListDsnsResponses, ListEmailDomainsData, ListEmailDomainsErrors, ListEmailDomainsResponse, ListEmailDomainsResponses, ListEmailProvidersData, ListEmailProvidersErrors, ListEmailProvidersResponse, ListEmailProvidersResponses, ListEmailsData, ListEmailsErrors, ListEmailsResponse, ListEmailsResponses, ListEnrollmentTokensData, ListEnrollmentTokensErrors, ListEnrollmentTokensResponse, ListEnrollmentTokensResponses, ListEntitiesData, ListEntitiesErrors, ListEntitiesQuery, ListEntitiesResponse, ListEntitiesResponses, ListErrorEventsData, ListErrorEventsErrors, ListErrorEventsQuery, ListErrorEventsResponse, ListErrorEventsResponses, ListErrorGroupsData, ListErrorGroupsErrors, ListErrorGroupsQuery, ListErrorGroupsResponse, ListErrorGroupsResponses, ListEventsData, ListEventsResponse, ListEventsResponses, ListEventTypesData, ListEventTypesResponse, ListEventTypesResponses, ListExternalImagesData, ListExternalImagesErrors, ListExternalImagesResponse, ListExternalImagesResponses, ListExternalPluginsData, ListExternalPluginsErrors, ListExternalPluginsResponse, ListExternalPluginsResponses, ListExternalServiceBackupsData, ListExternalServiceBackupsError, ListExternalServiceBackupsErrors, ListExternalServiceBackupsResponse, ListExternalServiceBackupsResponses, ListFlagsData, ListFlagsErrors, ListFlagsResponse, ListFlagsResponses, ListFunnelsData, ListFunnelsErrors, ListFunnelsResponse, ListFunnelsResponses, ListGitProvidersData, ListGitProvidersErrors, ListGitProvidersResponse, ListGitProvidersResponses, ListGlobalMcpsData, ListGlobalMcpsErrors, ListGlobalMcpsResponse, ListGlobalMcpsResponses, ListGlobalSkillsData, ListGlobalSkillsErrors, ListGlobalSkillsResponse, ListGlobalSkillsResponses, ListIncidentsData, ListIncidentsErrors, ListIncidentsResponses, ListInsightsData, ListInsightsError, ListInsightsErrors, ListInsightsResponse, ListInsightsResponses, ListIpAccessControlData, ListIpAccessControlError, ListIpAccessControlErrors, ListIpAccessControlResponse, ListIpAccessControlResponses, ListJobsData, ListJobsErrors, ListJobsResponse, ListJobsResponse2, ListJobsResponses, ListKnownAiAgentsData, ListKnownAiAgentsError, ListKnownAiAgentsErrors, ListKnownAiAgentsResponse, ListKnownAiAgentsResponses, ListManagedDomainsData, ListManagedDomainsErrors, ListManagedDomainsResponse, ListManagedDomainsResponses, ListMcpsData, ListMcpsErrors, ListMcpsResponse, ListMcpsResponse2, ListMcpsResponses, ListMetricLabelKeysData, ListMetricLabelKeysError, ListMetricLabelKeysErrors, ListMetricLabelKeysResponse, ListMetricLabelKeysResponses, ListMetricLabelValuesData, ListMetricLabelValuesError, ListMetricLabelValuesErrors, ListMetricLabelValuesResponse, ListMetricLabelValuesResponses, ListMetricNamesData, ListMetricNamesError, ListMetricNamesErrors, ListMetricNamesResponse, ListMetricNamesResponses, ListModelsData, ListModelsError, ListModelsErrors, ListModelsResponse, ListModelsResponses, ListMonitorsData, ListMonitorsErrors, ListMonitorsResponse, ListMonitorsResponses, ListNotificationProvidersData, ListNotificationProvidersErrors, ListNotificationProvidersResponse, ListNotificationProvidersResponses, ListOidcProvidersData, ListOidcProvidersResponse, ListOidcProvidersResponses, ListOidcProviderUsersData, ListOidcProviderUsersErrors, ListOidcProviderUsersResponse, ListOidcProviderUsersResponses, ListOidcRoleMappingsData, ListOidcRoleMappingsResponse, ListOidcRoleMappingsResponses, ListOnDemandCertsData, ListOnDemandCertsErrors, ListOnDemandCertsResponse, ListOnDemandCertsResponse2, ListOnDemandCertsResponses, ListOrdersData, ListOrdersErrors, ListOrdersResponse, ListOrdersResponse2, ListOrdersResponses, ListPeersData, ListPeersErrors, ListPeersResponse, ListPeersResponses, ListPendingActionsData, ListPendingActionsErrors, ListPendingActionsResponse, ListPendingActionsResponses, ListPgUpgradesData, ListPgUpgradesErrors, ListPgUpgradesResponse, ListPgUpgradesResponses, ListPresetsData, ListPresetsErrors, ListPresetsResponse, ListPresetsResponse2, ListPresetsResponses, ListProjectAccessData, ListProjectAccessErrors, ListProjectAccessResponse, ListProjectAccessResponses, ListProjectAlarmsData, ListProjectAlarmsErrors, ListProjectAlarmsResponse, ListProjectAlarmsResponses, ListProjectScansData, ListProjectScansError, ListProjectScansErrors, ListProjectScansResponse, ListProjectScansResponses, ListProjectSecretsData, ListProjectSecretsErrors, ListProjectSecretsResponse, ListProjectSecretsResponses, ListProjectServicesData, ListProjectServicesErrors, ListProjectServicesResponse, ListProjectServicesResponses, ListProjectTemplatesData, ListProjectTemplatesErrors, ListProjectTemplatesResponse, ListProjectTemplatesResponses, ListProjectTemplateTagsData, ListProjectTemplateTagsErrors, ListProjectTemplateTagsResponse, ListProjectTemplateTagsResponses, ListProviderKeysData, ListProviderKeysError, ListProviderKeysErrors, ListProviderKeysResponse, ListProviderKeysResponses, ListProviderZonesData, ListProviderZonesErrors, ListProviderZonesResponse, ListProviderZonesResponses, ListPublicProvidersData, ListPublicProvidersResponse, ListPublicProvidersResponses, ListReleaseFilesData, ListReleaseFilesErrors, ListReleaseFilesResponse, ListReleaseFilesResponses, ListReleasesData, ListReleasesErrors, ListReleasesResponse, ListReleasesResponses, ListRemoteExternalImagesData, ListRemoteExternalImagesErrors, ListRemoteExternalImagesResponse, ListRemoteExternalImagesResponses, ListRepositoriesByConnectionData, ListRepositoriesByConnectionErrors, ListRepositoriesByConnectionResponse, ListRepositoriesByConnectionResponses, ListRepositoriesByProviderData, ListRepositoriesByProviderErrors, ListRepositoriesByProviderResponse, ListRepositoriesByProviderResponses, ListRestoreRunsForServiceData, ListRestoreRunsForServiceResponse, ListRestoreRunsForServiceResponses, ListRootContainersData, ListRootContainersErrors, ListRootContainersResponse, ListRootContainersResponses, ListRoutesData, ListRoutesErrors, ListRoutesResponse, ListRoutesResponses, ListRunsResponse, ListS3SourcesData, ListS3SourcesError, ListS3SourcesErrors, ListS3SourcesResponse, ListS3SourcesResponses, ListSandboxesData, ListSandboxesResponse, ListSandboxesResponse2, ListSandboxesResponses, ListScansQuery, ListScheduleRunJobsData, ListScheduleRunJobsError, ListScheduleRunJobsErrors, ListScheduleRunJobsResponse, ListScheduleRunJobsResponses, ListScheduleRunsData, ListScheduleRunsError, ListScheduleRunsErrors, ListScheduleRunsResponse, ListScheduleRunsResponses, ListScheduleServicesData, ListScheduleServicesError, ListScheduleServicesErrors, ListScheduleServicesResponse, ListScheduleServicesResponses, ListSecretsData, ListSecretsErrors, ListSecretsResponse, ListSecretsResponse2, ListSecretsResponses, ListServiceHealthStatusesData, ListServiceHealthStatusesErrors, ListServiceHealthStatusesResponse, ListServiceHealthStatusesResponses, ListServiceProjectsData, ListServiceProjectsErrors, ListServiceProjectsResponse, ListServiceProjectsResponses, ListServiceSchedulesData, ListServiceSchedulesError, ListServiceSchedulesErrors, ListServiceSchedulesResponse, ListServiceSchedulesResponses, ListServicesData, ListServicesErrors, ListServicesResponse, ListServicesResponses, ListSkillsData, ListSkillsErrors, ListSkillsResponse, ListSkillsResponse2, ListSkillsResponses, ListSourceBackupsData, ListSourceBackupsError, ListSourceBackupsErrors, ListSourceBackupsResponse, ListSourceBackupsResponses, ListSourceFilesData, ListSourceFilesErrors, ListSourceFilesResponse, ListSourceFilesResponses, ListSourceMapsData, ListSourceMapsErrors, ListSourceMapsResponse, ListSourceMapsResponses, ListSourcesData, ListSourcesErrors, ListSourcesResponse, ListSourcesResponses, ListStaticBundlesData, ListStaticBundlesErrors, ListStaticBundlesResponse, ListStaticBundlesResponses, ListSyncedRepositoriesData, ListSyncedRepositoriesErrors, ListSyncedRepositoriesResponse, ListSyncedRepositoriesResponses, ListTagsResponse, ListTeamMembersData, ListTeamMembersErrors, ListTeamMembersResponse, ListTeamMembersResponses, ListTeamProjectsData, ListTeamProjectsErrors, ListTeamProjectsResponse, ListTeamProjectsResponses, ListTeamsData, ListTeamsErrors, ListTeamsResponse, ListTeamsResponses, ListTemplatesQuery, ListTemplatesResponse, ListUsersData, ListUsersErrors, ListUsersResponse, ListUsersResponses, ListVulnerabilitiesQuery, ListWebhooksData, ListWebhooksErrors, ListWebhooksResponse, ListWebhooksResponses, LiveVisitorInfo, LiveVisitorsListResponse, LocationCount, LocationGranularity, LocationInfo, LoginData, LoginErrors, LoginRequest, LoginResponse, LoginResponses, LogLevel, LogoutData, LogoutErrors, LogoutResponses, LogRecord, LogSearchLine, LogSeverity, LogSource, LogsQuery, LogsResponse, LogStream, LookupDnsARecordsData, LookupDnsARecordsError, LookupDnsARecordsErrors, LookupDnsARecordsResponse, LookupDnsARecordsResponses, ManagedDomainResponse, ManualAction, ManualActionTiming, McpDefinitionResponse, MessageContent, MessagePart, MessageResponse, MeteredMode, MetricAggregation, MetricBucket, MetricDataPoint, MetricsOverTimeResponse, MetricsQuery, MetricsRangeQuery, MetricsStatusResponse, MetricsStoreKind, MetricsSummaryResponse, MetricType, MfaRequiredResponse, MfaSetupResponse, MfaVerificationRequest, MigrationStep, MigrationSummary, MintEnrollmentTokenData, MintEnrollmentTokenErrors, MintEnrollmentTokenRequest, MintEnrollmentTokenResponse, MintEnrollmentTokenResponse2, MintEnrollmentTokenResponses, MiscResult, MkdirBody, MkdirData, MkdirErrors, MkdirResponse, MkdirResponses, ModelInfo, ModelListResponse, ModelPricing, ModelUsage, MonitoringSettings, MonitoringSettingsMasked, MonitorResponse, MonitorStatus, MrrBucketResponse, MultiNodeSettings, MultiNodeSettingsMasked, MxResult, NavEntry, NavSection, NetworkConfiguration, NetworkMode, NixpacksPresetConfig, NixpacksProvider, NodeContainerListResponse, NodeContainerResponse, NodeCostInfo, NodeHeartbeatData, NodeHeartbeatErrors, NodeHeartbeatResponse, NodeHeartbeatResponses, NodeInfoResponse, NodeListResponse, NodeMetricsGetRangeData, NodeMetricsGetRangeErrors, NodeMetricsGetRangeResponse, NodeMetricsGetRangeResponses, NotificationPreferencesResponse, NotificationProviderResponse, ObservabilityCompressionSettings, ObservabilityEvent, ObservabilityFullEventData, ObservabilityFullEventError, ObservabilityFullEventErrors, ObservabilityFullEventResponse, ObservabilityFullEventResponses, ObservabilityListEventsData, ObservabilityListEventsError, ObservabilityListEventsErrors, ObservabilityListEventsResponse, ObservabilityListEventsResponses, ObservabilityRetentionSettings, OidcCallbackData, OidcProviderResponse, OidcProvidersListResponse, OidcProviderSummary, OidcProviderUserResponse, OidcRoleMappingResponse, OidcTestConnectionResponse, OnDemandCertAttemptResponse, OnDemandCertRow, OnDemandTlsSettings, OpenAiError, OpenAiErrorResponse, OperatingSystemCount, OperationResultResponse, OperationResultsResponse, OtelDashboardResponse, OtelDashboardsResponse, OtelMetricAlertRuleResponse, OtelMetricAlertsResponse, OtelMetricLabelKeysResponse, OtelMetricLabelValuesResponse, OtelMetricNamesResponse, OtelMetricsResponse, OutlierAlgorithm, OutlierParams, OverprovisioningAssessment, OverprovisioningVerdict, PageActivityBucket, PageCountryStats, PageFlowEntry, PageFlowQuery, PageFlowResponse, PageHourlySessionsQuery, PageHourlySessionsResponse, PagePathDetailQuery, PagePathDetailResponse, PagePathInfo, PagePathSparkline, PagePathSparklinePoint, PagePathsQuery, PagePathsResponse, PagePathsSparklineQuery, PagePathsSparklineResponse, PagePathVisitorsQuery, PagePathVisitorsResponse, PageReferrerStats, PagesComparisonResponse, PageSessionComparison, PageSessionStats, PageSessionStatsQuery, PageTransition, PageVisit, PageVisitorSession, PaginatedEmailsResponse, PaginatedEntitiesResponse, PaginatedErrorEventsResponse, PaginatedErrorGroupsResponse, PaginatedEventsResponse, PaginatedExternalImagesResponse, PaginatedProjectList, PaginatedStaticBundlesResponse, Pagination, PaginationMeta, PaginationParams, PasswordProtectionConfig, PatchAdminGateData, PatchAdminGateErrors, PatchAdminGateResponse, PatchAdminGateResponses, PatchPreviewGatewaySettingsData, PatchPreviewGatewaySettingsResponse, PatchPreviewGatewaySettingsResponses, PatchSettingsRequest, PathVisitors, PathVisitorsAnalyticsQuery, PathVisitorsResponse, PauseDeploymentData, PauseDeploymentErrors, PauseDeploymentResponse, PauseDeploymentResponses, PauseSandboxData, PauseSandboxErrors, PauseSandboxResponse, PauseSandboxResponses, PeerEntry, PeerListResponse, PendingActionResponse, PerformanceMetricsQuery, PerformanceMetricsResponse, PermissionInfo, PgUpgradeLogResponse, PgUpgradeResponse, PipelineStats, PipelineStatsResponse, PlanComplexity, PlanMetadata, PlanRestoreData, PlanRestoreError, PlanRestoreErrors, PlanRestoreResponse, PlanRestoreResponses, PlanSourceBackup, PlanTarget, PlatformInfo, PluginManifest, PortMapping, PostDnsAckData, PostDnsAckErrors, PostDnsAckResponse, PostDnsAckResponses, PostgresWalHealth, PresetConfigSchema, PresetInfo, PresetResponse, PreviewAlertData, PreviewAlertError, PreviewAlertErrors, PreviewAlertResponse, PreviewAlertResponses, PreviewFunnelMetricsData, PreviewFunnelMetricsErrors, PreviewFunnelMetricsResponse, PreviewFunnelMetricsResponses, PreviewGatewaySettings, PreviewGatewaySettingsMasked, PreviewGatewaySettingsResponse, PreviewHostnameModeData, PreviewHostnameModeErrors, PreviewHostnameModeResponse, PreviewHostnameModeResponses, PreviewShareLinkBody, PreviewShareLinkResponse, PricingResponse, ProblemDetails, ProjectAccessResponse, ProjectConfiguration, ProjectDashboardAnalytics, ProjectDsnResponse, ProjectHealthSummary, ProjectInfo, ProjectMonitorHealth, ProjectPresetResponse, ProjectQuery, ProjectRef, ProjectResponse, ProjectSecretEnvironmentInfo, ProjectSecretResponse, ProjectServiceInfo, ProjectsHealthResponse, ProjectsMonitorHealthResponse, ProjectStatisticsResponse, ProjectStatsBreakdown, ProjectType, ProjectUsageInfoResponse, PromoteClusterMemberData, PromoteClusterMemberErrors, PromoteClusterMemberResponses, PromoteDeploymentData, PromoteDeploymentErrors, PromoteDeploymentRequest, PromoteDeploymentResponse, PromoteDeploymentResponses, PropertyBreakdownItem, PropertyBreakdownQuery, PropertyBreakdownResponse, PropertyColumn, PropertyTimelineItem, PropertyTimelineQuery, PropertyTimelineResponse, Protocol, ProviderCatalogDto, ProviderCatalogResponse, ProviderConfig, ProviderConfigMasked, ProviderDeletionCheckResponse, ProviderDescriptor, ProviderKeyResponse, ProviderMetadata, ProviderResponse, ProviderUsage, ProvisionDomainData, ProvisionDomainErrors, ProvisionDomainResponse, ProvisionDomainResponses, ProvisionResponse, ProxyLogResponse, ProxyLogsPaginatedResponse, PublicHostnameStrategy, PublicPresetResponse, PublicRepositoryInfo, PurgeLogsRequest, PurgeProjectLogsData, PurgeProjectLogsError, PurgeProjectLogsErrors, PurgeProjectLogsResponses, PushedExternalImageResponse, PushExternalImageData, PushExternalImageErrors, PushExternalImageResponse, PushExternalImageResponses, PushImageRequest, QueryDataData, QueryDataErrors, QueryDataRequest, QueryDataResponse, QueryDataResponse2, QueryDataResponses, QueryGenaiTracesData, QueryGenaiTracesError, QueryGenaiTracesErrors, QueryGenaiTracesResponse, QueryGenaiTracesResponses, QueryLogsData, QueryLogsError, QueryLogsErrors, QueryLogsResponse, QueryLogsResponses, QueryMetricsData, QueryMetricsError, QueryMetricsErrors, QueryMetricsResponse, QueryMetricsResponses, QueryTracesData, QueryTracesError, QueryTracesErrors, QueryTracesResponse, QueryTracesResponses, QueryTraceSummariesData, QueryTraceSummariesError, QueryTraceSummariesErrors, QueryTraceSummariesResponse, QueryTraceSummariesResponses, QuotaResponse, RateLimitConfig, RateLimitSettings, ReachabilityStatus, ReadFileData, ReadFileErrors, ReadFileResponse, ReadFileResponse2, ReadFileResponses, ReAnalyzeData, ReAnalyzeErrors, ReAnalyzeResponses, RecentActivityQuery, RecentActivityResponse, RecentEventResponse, RecentQueryParams, RecordConsoleEventData, RecordConsoleEventErrors, RecordConsoleEventResponses, RecordEventMetricsData, RecordEventMetricsErrors, RecordEventMetricsResponse, RecordEventMetricsResponses, RecordExposureRequest, RecordExposureResponse, RecordFlagExposureData, RecordFlagExposureErrors, RecordFlagExposureResponse, RecordFlagExposureResponses, RecordListResponse, RecordSpeedMetricsData, RecordSpeedMetricsError, RecordSpeedMetricsErrors, RecordSpeedMetricsResponse, RecordSpeedMetricsResponses, RecoveryTarget, ReferrerCount, ReferrersAnalyticsQuery, RefreshRouteTableData, RefreshRouteTableErrors, RefreshRouteTableResponse, RefreshRouteTableResponses, RegenerateDsnData, RegenerateDsnErrors, RegenerateDsnRequest, RegenerateDsnResponse, RegenerateDsnResponses, RegisterExternalImageData, RegisterExternalImageErrors, RegisterExternalImageResponse, RegisterExternalImageResponses, RegisterImageRequest, RegisterNodeApiRequest, RegisterNodeData, RegisterNodeErrors, RegisterNodeResponse, RegisterNodeResponse2, RegisterNodeResponses, RegisterRequest, ReinstallGitlabWebhookData, ReinstallGitlabWebhookErrors, ReinstallGitlabWebhookResponse, ReinstallGitlabWebhookResponses, ReinstallWebhookResponse, RejectPendingActionData, RejectPendingActionErrors, RejectPendingActionResponse, RejectPendingActionResponses, ReleaseListResponse, ReloadPluginsData, ReloadPluginsErrors, ReloadPluginsResponse, ReloadPluginsResponses, ReloadResponse, RemoteDeploymentResponse, RemoveClusterMemberData, RemoveClusterMemberErrors, RemoveClusterMemberResponse, RemoveClusterMemberResponses, RemoveManagedDomainData, RemoveManagedDomainErrors, RemoveManagedDomainResponse, RemoveManagedDomainResponses, RemoveNodeResponse, RemoveRoleData, RemoveRoleErrors, RemoveRoleResponse, RemoveRoleResponses, RemoveTeamMemberData, RemoveTeamMemberErrors, RemoveTeamMemberResponse, RemoveTeamMemberResponses, RenameConversationData, RenameConversationErrors, RenameConversationRequest, RenameConversationResponse, RenameConversationResponses, RenewDomainData, RenewDomainErrors, RenewDomainResponse, RenewDomainResponses, RepositoryListQuery, RepositoryListResponse, RepositoryPresetResponse, RepositoryResponse, RepositorySyncStartedResponse, RequestPasswordResetData, RequestPasswordResetErrors, RequestPasswordResetResponse, RequestPasswordResetResponses, RequestRow, ResetPasswordData, ResetPasswordErrors, ResetPasswordRequest, ResetPasswordResponse, ResetPasswordResponses, ResetPgStatStatementsRequest, ResetPgStatStatementsResponse, ResizeSandboxBody, ResizeSandboxData, ResizeSandboxErrors, ResizeSandboxResponse, ResizeSandboxResponses, ResolveAlarmData, ResolveAlarmErrors, ResolveAlarmResponses, ResolvedEnvVarResponse, ResolvedEnvVarSource, ResourceCounts, ResourceFootprint, ResourceInfo, ResourceLimitApplyResult, ResourceLimits, ResourceLimitsResponse, ResourceLimitsUpdateResponse, ResourcesBody, RestartContainerData, RestartContainerErrors, RestartContainerResponse, RestartContainerResponses, RestartPreviewGatewayData, RestartPreviewGatewayResponse, RestartPreviewGatewayResponses, RestartSandboxData, RestartSandboxErrors, RestartSandboxResponse, RestartSandboxResponses, RestoreCapabilities, RestoreCapabilitiesResponse, RestoreFlagData, RestoreFlagErrors, RestoreFlagResponse, RestoreFlagResponses, RestorePlan, RestoreRequestMode, RestoreRunView, RestoreUserData, RestoreUserErrors, RestoreUserResponse, RestoreUserResponses, ResumeDeploymentData, ResumeDeploymentErrors, ResumeDeploymentResponse, ResumeDeploymentResponses, ResumeSandboxData, ResumeSandboxErrors, ResumeSandboxResponse, ResumeSandboxResponses, RetentionCleanupFailure, RetentionCleanupReport, RetryClusterData, RetryClusterErrors, RetryClusterRequest, RetryClusterResponse, RetryClusterResponses, RetryDeliveryData, RetryDeliveryErrors, RetryDeliveryResponse, RetryDeliveryResponses, RetryPgUpgradeData, RetryPgUpgradeErrors, RetryPgUpgradeResponse, RetryPgUpgradeResponses, RetryRunData, RetryRunErrors, RetryRunResponse, RetryRunResponses, RevealGlobalMcpConfigData, RevealGlobalMcpConfigErrors, RevealGlobalMcpConfigResponse, RevealGlobalMcpConfigResponses, RevealMcpConfigData, RevealMcpConfigErrors, RevealMcpConfigResponse, RevealMcpConfigResponses, RevealNotificationProviderConfigData, RevealNotificationProviderConfigErrors, RevealNotificationProviderConfigResponse, RevealNotificationProviderConfigResponses, RevealServiceParameterData, RevealServiceParameterErrors, RevealServiceParameterResponse, RevealServiceParameterResponses, RevenueCreateIntegrationData, RevenueCreateIntegrationErrors, RevenueCreateIntegrationResponse, RevenueCreateIntegrationResponses, RevenueDeleteIntegrationData, RevenueDeleteIntegrationResponse, RevenueDeleteIntegrationResponses, RevenueGlobalEventsData, RevenueGlobalEventsResponse, RevenueGlobalEventsResponses, RevenueImportInvoicesCsvData, RevenueImportInvoicesCsvErrors, RevenueImportInvoicesCsvResponse, RevenueImportInvoicesCsvResponses, RevenueImportSubscriptionsCsvData, RevenueImportSubscriptionsCsvErrors, RevenueImportSubscriptionsCsvResponse, RevenueImportSubscriptionsCsvResponses, RevenueListIntegrationsData, RevenueListIntegrationsResponse, RevenueListIntegrationsResponses, RevenueListProvidersData, RevenueListProvidersResponse, RevenueListProvidersResponses, RevenueMetricsCustomersData, RevenueMetricsCustomersResponse, RevenueMetricsCustomersResponses, RevenueMetricsGlobalMrrData, RevenueMetricsGlobalMrrResponse, RevenueMetricsGlobalMrrResponses, RevenueMetricsGlobalSummaryData, RevenueMetricsGlobalSummaryResponse, RevenueMetricsGlobalSummaryResponses, RevenueMetricsMrrData, RevenueMetricsMrrResponse, RevenueMetricsMrrResponses, RevenueMetricsSummaryData, RevenueMetricsSummaryResponse, RevenueMetricsSummaryResponses, RevenueRecentEventsData, RevenueRecentEventsResponse, RevenueRecentEventsResponses, RevenueRotateTokenData, RevenueRotateTokenResponse, RevenueRotateTokenResponses, RevenueRow, RevenueUpdateConfigData, RevenueUpdateConfigErrors, RevenueUpdateConfigResponse, RevenueUpdateConfigResponses, RevenueUpdateSecretData, RevenueUpdateSecretErrors, RevenueUpdateSecretResponse, RevenueUpdateSecretResponses, RevokeDsnData, RevokeDsnErrors, RevokeDsnResponse, RevokeDsnResponses, RevokeEnrollmentTokenData, RevokeEnrollmentTokenErrors, RevokeEnrollmentTokenResponse, RevokeEnrollmentTokenResponses, RevokeJoinTokenData, RevokeJoinTokenErrors, RevokeJoinTokenResponse, RevokeJoinTokenResponses, RevokeProjectAccessData, RevokeProjectAccessErrors, RevokeProjectAccessResponse, RevokeProjectAccessResponses, RiskLevel, RoleInfo, RollbackPgUpgradeData, RollbackPgUpgradeErrors, RollbackPgUpgradeResponse, RollbackPgUpgradeResponses, RollbackToDeploymentData, RollbackToDeploymentErrors, RollbackToDeploymentResponse, RollbackToDeploymentResponses, RootfsCacheEntry, RootfsGcData, RootfsGcReport, RootfsGcResponses, RootfsReport, RootfsReportData, RootfsReportResponses, RootfsVmEntry, RotateApiKeyData, RotateApiKeyErrors, RotateApiKeyResponse, RotateApiKeyResponses, RotateDeploymentTokenData, RotateDeploymentTokenErrors, RotateDeploymentTokenResponse, RotateDeploymentTokenResponses, RouteRefreshResponse, RouteResponse, RouteRole, RouteUser, RouteUserWithRoles, RunBackupForSourceData, RunBackupForSourceError, RunBackupForSourceErrors, RunBackupForSourceResponse, RunBackupForSourceResponses, RunBackupRequest, RunConnectionHealthCheckData, RunConnectionHealthCheckErrors, RunConnectionHealthCheckResponse, RunConnectionHealthCheckResponses, RunExternalServiceBackupData, RunExternalServiceBackupError, RunExternalServiceBackupErrors, RunExternalServiceBackupRequest, RunExternalServiceBackupResponse, RunExternalServiceBackupResponses, RunScheduleNowData, RunScheduleNowError, RunScheduleNowErrors, RunScheduleNowResponse, RunScheduleNowResponses, S3ConnectionTestResponse, S3CredentialsResponse, S3SourceResponse, S3SourceResponseWritable, SandboxCreatePreviewLinkData, SandboxCreatePreviewLinkErrors, SandboxCreatePreviewLinkResponse, SandboxCreatePreviewLinkResponses, SandboxDomainResponse, SandboxEvent, SandboxEventsResponse, SandboxInner, SandboxResponse, SandboxRoute, SandboxStatusResponse, SaveAgentTokenData, SaveAgentTokenErrors, SaveAgentTokenRequest, SaveAgentTokenResponse, SaveAgentTokenResponse2, SaveAgentTokenResponses, SaveAiProviderCredentialData, SaveAiProviderCredentialErrors, SaveAiProviderCredentialResponse, SaveAiProviderCredentialResponses, SaveCredentialRequest, SaveCredentialResponse, ScalewayCredentialsRequest, ScanResponse, ScheduleRunEntry, ScheduleRunJobEntry, ScheduleRunListResponse, ScheduleRunResponse, ScheduleRunSummary, ScheduleRunSummaryList, ScreenshotSettings, SearchLogsData, SearchLogsError, SearchLogsErrors, SearchLogsRequest, SearchLogsResponse, SearchLogsResponse2, SearchLogsResponses, SearchMode, Seasonality, SecretResponse, SecurityConfig, SecurityHeadersConfig, SecurityHeadersSettings, SendEmailData, SendEmailErrors, SendEmailRequestBody, SendEmailResponse, SendEmailResponseBody, SendEmailResponses, SendMessageRequest, SensitiveConfigValueResponse, SensitiveMcpConfigValueResponse, SensitiveValueResponse, SentryChunkUploadResponse, SentryCreateReleaseRequest, SentryEventRequest, SentryEventResponse, SentryReleaseFileResponse, SentryReleaseProjectRef, SentryReleaseResponse, SeriesStateEntry, ServiceAccessInfo, ServiceAction, ServiceAlertRuleResponse, ServiceBackupEntryResponse, ServiceBackupListResponse, ServiceCreateAlertRuleRequest, ServiceHealthResponse, ServiceHealthStatusBatchResponse, ServiceHealthStatusEntryResponse, ServiceMemberInfo, ServiceParameter, ServicePlan, ServiceResourceLimits, ServiceRuntimeReport, ServiceStatsReport, ServiceTypeInfo, ServiceTypeRoute, ServiceUpdateAlertRuleRequest, SesCredentialsRequest, SessionDetails, SessionDetailsQuery, SessionEvent, SessionEventDto, SessionEventsQuery, SessionEventsResponse, SessionLogsQuery, SessionLogsResponse, SessionReplayEventsRequest, SessionReplayInfoDto, SessionReplayInitRequest, SessionReplayInitResponse, SessionReplayWithEventsDto, SessionReplayWithVisitorDto, SessionRequestLog, SessionSummary, SetDefaultS3SourceData, SetDefaultS3SourceError, SetDefaultS3SourceErrors, SetDefaultS3SourceResponse, SetDefaultS3SourceResponses, SetFlagEnvironmentData, SetFlagEnvironmentErrors, SetFlagEnvironmentRequest, SetFlagEnvironmentResponse, SetFlagEnvironmentResponses, SetPreviewPasswordBody, SetPreviewPasswordData, SetPreviewPasswordErrors, SetPreviewPasswordResponse, SetPreviewPasswordResponse2, SetPreviewPasswordResponses, SetRequest, SetResponse, SettingsUpdateResponse, SetupDnsChallengeData, SetupDnsChallengeErrors, SetupDnsChallengeRequest, SetupDnsChallengeResponse, SetupDnsChallengeResponse2, SetupDnsChallengeResponses, SetupDnsData, SetupDnsErrors, SetupDnsRequest, SetupDnsResponse, SetupDnsResponse2, SetupDnsResponses, SetupEmailTrackingData, SetupEmailTrackingErrors, SetupEmailTrackingResponse, SetupEmailTrackingResponses, SetupMfaData, SetupMfaErrors, SetupMfaResponse, SetupMfaResponses, SiblingRef, SkillDefinitionResponse, SlackConfig, SleepEnvironmentData, SleepEnvironmentErrors, SleepEnvironmentResponse, SleepEnvironmentResponses, SlowQueriesResponse, SlowQueryRow, SmartFilter, SmokeTestAgentData, SmokeTestAgentErrors, SmokeTestAgentResponse, SmokeTestAgentResponses, SmokeTestResponse, SmtpCredentialsRequest, SmtpEncryptionRoute, SmtpResult, SourceArchiveUpload, SourceBackupEntry, SourceBackupIndexResponse, SourceBody, SourceFileListResponse, SourceFileResponse, SourceMapListResponse, SourceMapResponse, SourceSandboxData, SourceSandboxErrors, SourceSandboxResponse, SourceSandboxResponses, SourceType, SpanEvent, SpanKind, SpanRecord, SpanRow, SpanStatusCode, SpeedMetricsPayload, SpeedSegmentFilters, StaleSlot, StartAnalysisData, StartAnalysisErrors, StartAnalysisRequest, StartAnalysisResponse, StartAnalysisResponses, StartContainerData, StartContainerErrors, StartContainerResponse, StartContainerResponses, StartFixData, StartFixErrors, StartFixResponses, StartGitProviderOauthData, StartGitProviderOauthErrors, StartOidcLoginBySlugData, StartOidcLoginBySlugErrors, StartPgUpgradeData, StartPgUpgradeErrors, StartPgUpgradeRequest, StartPgUpgradeResponse, StartPgUpgradeResponses, StartRestoreData, StartRestoreError, StartRestoreErrors, StartRestoreRequest, StartRestoreResponse, StartRestoreResponses, StartServiceData, StartServiceErrors, StartServiceResponse, StartServiceResponses, StaticBundleResponse, StaticParams, StaticPresetConfig, StatPathData, StatPathErrors, StatPathResponse, StatPathResponses, StatResponse, StatsFilters, StatusBucket, StatusBucketedResponse, StatusCodeCount, StatusCodesQuery, StatusPageOverview, StepConversionResponse, StepResourceType, StepResult, StepUpResponse, StopContainerData, StopContainerErrors, StopContainerResponse, StopContainerResponses, StopSandboxData, StopSandboxErrors, StopSandboxResponse, StopSandboxResponses, StopSequence, StopServiceData, StopServiceErrors, StopServiceResponse, StopServiceResponses, StorageQuota, StreamContainerMetricsData, StreamContainerMetricsErrors, StreamContainerMetricsResponses, StreamEventsData, StreamEventsErrors, StreamEventsResponses, StreamRunEventsData, StreamRunEventsErrors, StreamRunEventsResponses, StripeConfig, SyncedRepositoryListQuery, SyncRepositoriesData, SyncRepositoriesErrors, SyncRepositoriesResponse, SyncRepositoriesResponses, SyntaxResult, TagInfo, TagListResponse, TailDeploymentJobLogsData, TailDeploymentJobLogsErrors, TailLogsData, TailLogsError, TailLogsErrors, TailLogsRequest, TailLogsResponses, TargetRecommendation, TeamListResponse, TeamMemberResponse, TeamResponse, TeamRole, TeardownDeploymentData, TeardownDeploymentErrors, TeardownDeploymentResponse, TeardownDeploymentResponses, TeardownEnvironmentData, TeardownEnvironmentErrors, TeardownEnvironmentResponse, TeardownEnvironmentResponses, TemplateResponse, TestEmailRequest, TestEmailResponse, TestNotificationProviderData, TestNotificationProviderErrors, TestNotificationProviderResponse, TestNotificationProviderResponses, TestOidcProviderData, TestOidcProviderResponse, TestOidcProviderResponses, TestProviderConnectionData, TestProviderConnectionErrors, TestProviderConnectionResponse, TestProviderConnectionResponses, TestProviderData, TestProviderErrors, TestProviderKeyByIdData, TestProviderKeyByIdError, TestProviderKeyByIdErrors, TestProviderKeyByIdResponse, TestProviderKeyByIdResponses, TestProviderKeyInlineData, TestProviderKeyInlineError, TestProviderKeyInlineErrors, TestProviderKeyInlineResponse, TestProviderKeyInlineResponses, TestProviderKeyRequest, TestProviderKeyResponse, TestProviderResponse, TestProviderResponse2, TestProviderResponses, TestS3ConnectionPreviewData, TestS3ConnectionPreviewError, TestS3ConnectionPreviewErrors, TestS3ConnectionPreviewResponse, TestS3ConnectionPreviewResponses, TestS3SourceConnectionData, TestS3SourceConnectionError, TestS3SourceConnectionErrors, TestS3SourceConnectionResponse, TestS3SourceConnectionResponses, TimeBucketStats, TimeBucketStatsResponse, TimeseriesBucket, TimeseriesQueryParams, TlsMode, TodayStatsResponse, ToggleDeploymentMetricsRequest, ToggleServiceMetricsRequest, TokenRenewalRequest, ToolCallEvent, ToolInfo, ToolResultEvent, TopModelsQueryParams, TraceProjectRef, TracesResponse, TraceSummariesResponse, TraceSummary, TrackClickData, TrackClickErrors, TrackedLinkResponse, TrackingEventResponse, TrackOpenData, TrackOpenErrors, TrackOpenResponses, TriggerAgentData, TriggerAgentErrors, TriggerAgentRequest, TriggerAgentResponse, TriggerAgentResponses, TriggerDigestResponse, TriggerPipelinePayload, TriggerPipelineResponse, TriggerProjectPipelineData, TriggerProjectPipelineErrors, TriggerProjectPipelineResponse, TriggerProjectPipelineResponses, TriggerScanData, TriggerScanError, TriggerScanErrors, TriggerScanRequest, TriggerScanResponse, TriggerScanResponse2, TriggerScanResponses, TriggerServiceHealthCheckData, TriggerServiceHealthCheckErrors, TriggerServiceHealthCheckResponse, TriggerServiceHealthCheckResponses, TriggerWeeklyDigestData, TriggerWeeklyDigestErrors, TriggerWeeklyDigestResponse, TriggerWeeklyDigestResponses, TtlRequest, TtlResponse, TxtRecord, UiManifest, UiRoute, UndrainNodeResponse, UnifiedTrace, UniqueCountsQuery, UniqueCountsResponse, UnlinkServiceFromProjectData, UnlinkServiceFromProjectErrors, UnlinkServiceFromProjectResponse, UnlinkServiceFromProjectResponses, UnsupportedFeature, UpdateAdminGateRequest, UpdateAgentData, UpdateAgentErrors, UpdateAgentResponse, UpdateAgentResponses, UpdateAiProviderData, UpdateAiProviderErrors, UpdateAiProviderRequest, UpdateAiProviderResponse, UpdateAiProviderResponse2, UpdateAiProviderResponses, UpdateAlertData, UpdateAlertError, UpdateAlertErrors, UpdateAlertResponse, UpdateAlertResponses, UpdateAlertRuleData, UpdateAlertRuleErrors, UpdateAlertRuleRequest, UpdateAlertRuleResponse, UpdateAlertRuleResponses, UpdateApiKeyData, UpdateApiKeyErrors, UpdateApiKeyRequest, UpdateApiKeyResponse, UpdateApiKeyResponses, UpdateAutomaticDeployData, UpdateAutomaticDeployErrors, UpdateAutomaticDeployRequest, UpdateAutomaticDeployResponse, UpdateAutomaticDeployResponses, UpdateBackupScheduleData, UpdateBackupScheduleError, UpdateBackupScheduleErrors, UpdateBackupScheduleRequest, UpdateBackupScheduleResponse, UpdateBackupScheduleResponses, UpdateBlobRequest, UpdateBlobResponse, UpdateCloudflareProviderData, UpdateCloudflareProviderErrors, UpdateCloudflareProviderRequest, UpdateCloudflareProviderResponse, UpdateCloudflareProviderResponses, UpdateConfigBody, UpdateConnectionTokenData, UpdateConnectionTokenErrors, UpdateConnectionTokenResponse, UpdateConnectionTokenResponses, UpdateCustomDomainData, UpdateCustomDomainErrors, UpdateCustomDomainRequest, UpdateCustomDomainResponse, UpdateCustomDomainResponses, UpdateDashboardData, UpdateDashboardError, UpdateDashboardErrors, UpdateDashboardRequest, UpdateDashboardResponse, UpdateDashboardResponses, UpdateDeploymentConfigRequest, UpdateDeploymentTokenData, UpdateDeploymentTokenErrors, UpdateDeploymentTokenRequest, UpdateDeploymentTokenResponse, UpdateDeploymentTokenResponses, UpdateDnsProviderRequest, UpdateEmailProviderData, UpdateEmailProviderErrors, UpdateEmailProviderRequest, UpdateEmailProviderResponse, UpdateEmailProviderResponses, UpdateEnvironmentSettingsData, UpdateEnvironmentSettingsErrors, UpdateEnvironmentSettingsRequest, UpdateEnvironmentSettingsResponse, UpdateEnvironmentSettingsResponses, UpdateEnvironmentSubdomainData, UpdateEnvironmentSubdomainErrors, UpdateEnvironmentSubdomainRequest, UpdateEnvironmentSubdomainResponse, UpdateEnvironmentSubdomainResponses, UpdateEnvironmentVariableData, UpdateEnvironmentVariableErrors, UpdateEnvironmentVariableRequest, UpdateEnvironmentVariableResponse, UpdateEnvironmentVariableResponses, UpdateErrorGroupData, UpdateErrorGroupErrors, UpdateErrorGroupRequest, UpdateErrorGroupResponses, UpdateExternalServiceRequest, UpdateFlagData, UpdateFlagErrors, UpdateFlagRequest, UpdateFlagResponse, UpdateFlagResponses, UpdateFunnelData, UpdateFunnelErrors, UpdateFunnelResponses, UpdateGitProviderCredentialsData, UpdateGitProviderCredentialsErrors, UpdateGitProviderCredentialsResponse, UpdateGitProviderCredentialsResponses, UpdateGitSettingsData, UpdateGitSettingsErrors, UpdateGitSettingsRequest, UpdateGitSettingsResponse, UpdateGitSettingsResponses, UpdateGlobalMcpData, UpdateGlobalMcpErrors, UpdateGlobalMcpResponse, UpdateGlobalMcpResponses, UpdateGlobalSkillData, UpdateGlobalSkillErrors, UpdateGlobalSkillResponse, UpdateGlobalSkillResponses, UpdateIncidentStatusData, UpdateIncidentStatusErrors, UpdateIncidentStatusRequest, UpdateIncidentStatusResponse, UpdateIncidentStatusResponses, UpdateIpAccessControlData, UpdateIpAccessControlError, UpdateIpAccessControlErrors, UpdateIpAccessControlRequest, UpdateIpAccessControlResponse, UpdateIpAccessControlResponses, UpdateKvRequest, UpdateKvResponse, UpdateManagedDomainApiRequest, UpdateManagedDomainData, UpdateManagedDomainErrors, UpdateManagedDomainResponse, UpdateManagedDomainResponses, UpdateMcpData, UpdateMcpErrors, UpdateMcpRequest, UpdateMcpResponse, UpdateMcpResponses, UpdateMemberRoleRequest, UpdateMetricAlertRequest, UpdateNotificationEmailProviderData, UpdateNotificationEmailProviderErrors, UpdateNotificationEmailProviderRequest, UpdateNotificationEmailProviderResponse, UpdateNotificationEmailProviderResponses, UpdateNotificationProviderData, UpdateNotificationProviderErrors, UpdateNotificationProviderResponse, UpdateNotificationProviderResponses, UpdateOidcProviderData, UpdateOidcProviderRequest, UpdateOidcProviderResponse, UpdateOidcProviderResponses, UpdatePreferencesData, UpdatePreferencesErrors, UpdatePreferencesRequest, UpdatePreferencesResponse, UpdatePreferencesResponses, UpdateProjectData, UpdateProjectDeploymentConfigData, UpdateProjectDeploymentConfigErrors, UpdateProjectDeploymentConfigResponse, UpdateProjectDeploymentConfigResponses, UpdateProjectErrors, UpdateProjectResponse, UpdateProjectResponses, UpdateProjectSecretData, UpdateProjectSecretErrors, UpdateProjectSecretRequest, UpdateProjectSecretResponse, UpdateProjectSecretResponses, UpdateProjectSettingsData, UpdateProjectSettingsErrors, UpdateProjectSettingsRequest, UpdateProjectSettingsResponse, UpdateProjectSettingsResponses, UpdateProviderCredentialsRequest, UpdateProviderData, UpdateProviderErrors, UpdateProviderKeyData, UpdateProviderKeyError, UpdateProviderKeyErrors, UpdateProviderKeyRequest, UpdateProviderKeyResponse, UpdateProviderKeyResponses, UpdateProviderRequest, UpdateProviderResponse, UpdateProviderResponses, UpdateRouteData, UpdateRouteErrors, UpdateRouteRequest, UpdateRouteResponse, UpdateRouteResponses, UpdateS3SourceData, UpdateS3SourceError, UpdateS3SourceErrors, UpdateS3SourceRequest, UpdateS3SourceResponse, UpdateS3SourceResponses, UpdateSecretBody, UpdateSelfData, UpdateSelfErrors, UpdateSelfRequest, UpdateSelfResponse, UpdateSelfResponses, UpdateServiceData, UpdateServiceErrors, UpdateServiceResourcesData, UpdateServiceResourcesErrors, UpdateServiceResourcesResponse, UpdateServiceResourcesResponses, UpdateServiceResponse, UpdateServiceResponses, UpdateSessionDurationData, UpdateSessionDurationError, UpdateSessionDurationErrors, UpdateSessionDurationRequest, UpdateSessionDurationResponse, UpdateSessionDurationResponse2, UpdateSessionDurationResponses, UpdateSettingsData, UpdateSettingsErrors, UpdateSettingsResponse, UpdateSettingsResponses, UpdateSkillData, UpdateSkillErrors, UpdateSkillRequest, UpdateSkillResponse, UpdateSkillResponses, UpdateSlackProviderData, UpdateSlackProviderErrors, UpdateSlackProviderRequest, UpdateSlackProviderResponse, UpdateSlackProviderResponses, UpdateSpeedMetricsData, UpdateSpeedMetricsError, UpdateSpeedMetricsErrors, UpdateSpeedMetricsPayload, UpdateSpeedMetricsResponse, UpdateSpeedMetricsResponses, UpdateStatusResponse, UpdateTeamData, UpdateTeamErrors, UpdateTeamMemberRoleData, UpdateTeamMemberRoleErrors, UpdateTeamMemberRoleResponse, UpdateTeamMemberRoleResponses, UpdateTeamRequest, UpdateTeamResponse, UpdateTeamResponses, UpdateTokenRequest, UpdateTokenResponse, UpdateUserData, UpdateUserErrors, UpdateUserRequest, UpdateUserResponse, UpdateUserResponses, UpdateWebhookData, UpdateWebhookErrors, UpdateWebhookProviderData, UpdateWebhookProviderErrors, UpdateWebhookProviderRequest, UpdateWebhookProviderResponse, UpdateWebhookProviderResponses, UpdateWebhookRequestBody, UpdateWebhookResponse, UpdateWebhookResponses, UpgradeExternalServiceRequest, UpgradePreviewGatewayData, UpgradePreviewGatewayResponse, UpgradePreviewGatewayResponses, UpgradeRequest, UpgradeServiceData, UpgradeServiceErrors, UpgradeServiceResponse, UpgradeServiceResponses, UploadGlobalSkillData, UploadGlobalSkillErrors, UploadGlobalSkillResponse, UploadGlobalSkillResponses, UploadReleaseFileData, UploadReleaseFileErrors, UploadReleaseFileResponse, UploadReleaseFileResponses, UploadSkillData, UploadSkillErrors, UploadSkillResponse, UploadSkillResponses, UploadSourceFileData, UploadSourceFileErrors, UploadSourceFileResponse, UploadSourceFileResponses, UploadSourceMapData, UploadSourceMapErrors, UploadSourceMapResponse, UploadSourceMapResponses, UploadStaticBundleData, UploadStaticBundleErrors, UploadStaticBundleResponse, UploadStaticBundleResponses, UpsertAgentRequest, UpsertSecretData, UpsertSecretErrors, UpsertSecretRequest, UpsertSecretResponse, UpsertSecretResponses, UptimeDataPoint, UptimeHistoryResponse, UsageFilter, UsageInfo, UsageLogEntry, UsageLogPage, UsageQueryParams, UsageSource, UsageSummary, UserResponse, ValidateConnectionData, ValidateConnectionErrors, ValidateConnectionResponse, ValidateConnectionResponses, ValidateEmailData, ValidateEmailErrors, ValidateEmailRequest, ValidateEmailResponse, ValidateEmailResponse2, ValidateEmailResponses, ValidationLevel, ValidationReport, ValidationResponse, ValidationResult, ValidationStatus, ValidationSummary, VerifyAndEnableMfaData, VerifyAndEnableMfaErrors, VerifyAndEnableMfaResponse, VerifyAndEnableMfaResponses, VerifyDomainData, VerifyDomainErrors, VerifyDomainResponse, VerifyDomainResponses, VerifyEmailData, VerifyEmailErrors, VerifyEmailResponse, VerifyEmailResponses, VerifyManagedDomainData, VerifyManagedDomainErrors, VerifyManagedDomainResponse, VerifyManagedDomainResponses, VerifyMfaChallengeData, VerifyMfaChallengeErrors, VerifyMfaChallengeResponse, VerifyMfaChallengeResponses, VerifyMfaRequest, VerifyStepUpData, VerifyStepUpErrors, VerifyStepUpRequest, VerifyStepUpResponse, VerifyStepUpResponses, ViewItem, ViewsOverTime, ViewsOverTimeQuery, VisitorDetails, VisitorFacets, VisitorFacetsQuery, VisitorFacetValue, VisitorInfo, VisitorJourneyQuery, VisitorJourneyResponse, VisitorLocationsQuery, VisitorRecord, VisitorSegmentFilters, VisitorSessionsQuery, VisitorSessionsResponse, VisitorsListQuery, VisitorsResponse, VisitorStats, VisitorWithGeolocation, VolumeMount, VolumeType, VulnerabilityResponse, WakeEnvironmentData, WakeEnvironmentErrors, WakeEnvironmentResponse, WakeEnvironmentResponses, WalWarning, WalWarningSeverity, WebhookConfig, WebhookDeliveryResponse, WebhookResponse, WebhookTriggerData, WebhookTriggerErrors, WebhookTriggerRequest, WebhookTriggerResponse, WebhookTriggerResponse2, WebhookTriggerResponses, WorkflowDryRunData, WorkflowDryRunErrors, WorkflowDryRunRequest, WorkflowDryRunResponse, WorkflowDryRunResponses, WorkloadDescriptor, WorkloadId, WorkloadStatus, WorkloadType, WriteFileBody, WriteFileData, WriteFileErrors, WriteFileResponse, WriteFileResponses, WriteFilesBody, WriteFilesData, WriteFilesErrors, WriteFilesResponse, WriteFilesResponse2, WriteFilesResponses, ZoneListResponse } from './types.gen'; +export { acknowledgeAlarm, activateAiProvider, activateApiKey, activateConnection, activateProvider, addClusterMember, addContext, addEnvironmentDomain, addEvents, addManagedDomain, addSessionReplayEvents, addTeamMember, adminDrainNode, adminDrainStatus, adminGetNode, adminListNodeContainers, adminListNodes, adminRemoveNode, adminUndrainNode, applyHostnameMode, archiveConversation, archiveFlag, assignRole, attachScheduleServices, blobCopy, blobDelete, blobDisable, blobDownload, blobEnable, blobHead, blobList, blobPut, blobStatus, blobUpdate, cancel, cancelBackup, cancelDeployment, cancelDomainOrder, cancelPgUpgrade, cancelRun, cancelScheduleRun, changePasswordSelf, changeProjectSource, chatCompletions, checkAnalyticsHasEvents, checkCommitExists, checkDomainStatus, checkExplorerSupport, checkIpBlocked, checkProviderDeletionSafety, chunkUploadOptions, cleanupExpiredBackups, clearPreviewPassword, cliDeviceApprove, cliDeviceDeny, cliDeviceLookup, cliDevicePoll, cliDeviceStart, cliLogout, cmd, cmdKill, cmdLogs, confirmPendingAction, containerMetricsGetHistory, createAgent, createAlert, createAlertRule, createApiKey, createBackupSchedule, createBitbucketProvider, createCloudflareProvider, createConversation, createCustomDomain, createDashboard, createDeploymentToken, createDnsProvider, createDomain, createDsn, createEmailDomain, createEmailProvider, createEnvironment, createEnvironmentVariable, createFlag, createFunnel, createGenericProvider, createGiteaPatProvider, createGithubPatProvider, createGitlabOauthProvider, createGitlabPatProvider, createGitProvider, createGlobalMcp, createGlobalSkill, createIncident, createIpAccessControl, createMcp, createMonitor, createNotificationEmailProvider, createNotificationProvider, createOidcProvider, createOidcRoleMapping, createOrRecreateOrder, createPlan, createPr, createProject, createProjectFromTemplate, createProjectRelease, createProjectSecret, createProviderKey, createRelease, createRoute, createS3Source, createSandbox, createService, createSkill, createSlackProvider, createTeam, createUser, createWebhook, createWebhookProvider, deactivateApiKey, deactivateConnection, deactivateProvider, deleteAgent, deleteAlert, deleteAlertRule, deleteApiKey, deleteBackup, deleteBackupSchedule, deleteConnection, deleteCustomDomain, deleteDashboard, deleteDeploymentToken, deleteDnsProvider, deleteDomain, deleteEmailDomain, deleteEmailProvider, deleteEnvironment, deleteEnvironmentDomain, deleteEnvironmentVariable, deleteExternalImage, deleteFunnel, deleteGitProvider, deleteGlobalMcp, deleteGlobalSkill, deleteIpAccessControl, deleteMcp, deleteMonitor, deleteNotificationProvider, deleteOidcProvider, deleteOidcRoleMapping, deletePreferences, deleteProject, deleteProjectSecret, deleteProviderKey, deleteProviderSafely, deleteReleaseSourceFiles, deleteReleaseSourceMaps, deleteRoute, deleteS3Source, deleteScan, deleteSecret, deleteService, deleteSessionReplay, deleteSkill, deleteSourceMap, deleteStaticBundle, deleteTeam, deleteUser, deleteWebhook, deployFromImage, deployFromImageUpload, deployFromStatic, deployFromUploadedSource, deploymentMetricsGetLatest, deploymentMetricsGetRange, deploymentMetricsToggle, destroySandbox, detachScheduleService, detectPublicPresets, disableBackupSchedule, disableMfa, disconnectCloud, discoverWorkloads, domain, downloadGlobalSkillArchive, downloadObject, downloadSkillArchive, emailStatus, embeddings, enableBackupSchedule, enrichVisitor, enrollCloud, exec, execDetached, executeDeploymentOperation, executeImport, extendTimeout, externalServiceEnablePgStatStatements, externalServiceMetricsByDatabase, externalServiceMetricsCreateAlertRule, externalServiceMetricsDeleteAlertRule, externalServiceMetricsGetAlertRules, externalServiceMetricsGetLatest, externalServiceMetricsGetRange, externalServiceMetricsStatus, externalServiceMetricsToggle, externalServiceMetricsUpdateAlertRule, externalServiceResetPgStatStatements, finalizeOrder, finalizeProjectRelease, findConversation, generateJoinToken, generatePresetDockerfile, getAccessInfo, getActiveVisitors, getActivityGraph, getAdminGate, getAgent, getAggregatedBuckets, getAiAgentBreakdown, getAiAgentPages, getAiAgentTimeline, getAiPageBreakdown, getAiStatusBreakdown, getAlert, getAlertRule, getAllRepositoriesByName, getAnalyticsActiveVisitors, getAnalyticsEventsCount, getAnalyticsSessionEvents, getAnalyticsVisitorSessions, getApiKey, getApiKeyPermissions, getAuditLog, getBackup, getBackupSchedule, getBranchesByRepositoryId, getBucketedIncidents, getBucketedStatus, getChallengeToken, getChatReadiness, getCliStatus, getCloudCapability, getCloudStatus, getClusterHealth, getClusterMember, getCmd, getContainerDetail, getContainerEnvironmentVariable, getContainerInfo, getContainerLogs, getContainerLogsById, getContainerMetrics, getConversation, getConversationDetail, getConversations, getCronById, getCronExecutions, getCrossProjectTraceSiblings, getCurrentMonitorStatus, getCurrentUser, getCustomDomain, getDashboard, getDashboardProjectsAnalytics, getDelivery, getDeployment, getDeploymentContainerLogContent, getDeploymentJobLogs, getDeploymentJobs, getDeploymentOperations, getDeploymentOperationStatus, getDeploymentToken, getDiskStatus, getDnsChanges, getDnsProvider, getDomain, getDomainByHost, getDomainById, getDomainByName, getDomainDnsRecords, getDomainOrder, getEmail, getEmailEvents, getEmailLinks, getEmailProvider, getEmailStats, getEmailTracking, getEmailTrackingStatus, getEntityInfo, getEnvironment, getEnvironmentCrons, getEnvironmentDomains, getEnvironments, getEnvironmentVariables, getEnvironmentVariableValue, getErrorDashboardStats, getErrorEvent, getErrorGroup, getErrorStats, getErrorTimeSeries, getEventDetail, getEventEntries, getEventsCount, getEventsTimeline, getEventTypeBreakdown, getEventVisitors, getExternalImage, getFile, getFlag, getFlagSnapshot, getFunnelMetrics, getGenaiTrace, getGeneralStats, getGitProvider, getGlobalEvents, getGlobalEventStats, getGlobalMcp, getGlobalSandboxStatus, getGlobalSkill, getGroupedPageMetrics, getHealth, getHourlyVisits, getHttpChallengeDebug, getImportStatus, getIncident, getIncidentUpdates, getIpAccessControl, getIpGeolocation, getJoinTokenStatus, getLastDeployment, getLatestScan, getLatestScansPerEnvironment, getLiveVisitorsList, getLogContext, getMcp, getMetricsOverTime, getMonitor, getNotificationProvider, getOnDemandCertStatus, getOrCreateDsn, getPageFlow, getPageHourlySessions, getPagePathDetail, getPagePaths, getPagePathsSparklines, getPagePathVisitors, getPendingAction, getPerformanceMetrics, getPgUpgrade, getPgUpgradeLogs, getPipelineStats, getPlatformInfo, getPostgresWalHealth, getPreferences, getPreviewGatewayLogs, getPreviewGatewaySettings, getPreviewGatewayStatus, getPricing, getPrivateIp, getProject, getProjectAlarmsSummary, getProjectBySlug, getProjectDeployments, getProjects, getProjectServiceEnvironmentVariables, getProjectSessionReplays, getProjectsHealth, getProjectsMonitorHealth, getProjectStatistics, getProjectTemplate, getPropertyBreakdown, getPropertyTimeline, getProviderConnections, getProviderMetadata, getProvidersMetadata, getProxyLogById, getProxyLogByRequestId, getProxyLogs, getPublicBranches, getPublicIp, getPublicRepository, getQuota, getRecentActivity, getRemoteExternalImage, getRepositoryBranches, getRepositoryById, getRepositoryByName, getRepositoryPresetByName, getRepositoryPresetLive, getRepositoryTags, getResolvedEnvironmentVariables, getResolvedEnvironmentVariableValue, getRestoreCapabilities, getRestoreRun, getRoute, getRun, getRunWithLogs, getS3Credentials, getS3Source, getSandbox, getSandboxStatus, getScan, getScanByDeployment, getScanVulnerabilities, getService, getServiceBySlug, getServiceEnvironmentVariable, getServiceEnvironmentVariables, getServiceHealthStatus, getServicePreviewEnvironmentVariableNames, getServicePreviewEnvironmentVariablesMasked, getServiceRuntime, getServiceStats, getServiceTypeParameters, getServiceTypes, getSessionDetails, getSessionEvents, getSessionLogs, getSessionReplay, getSessionReplayEvents, getSettings, getSkill, getSlowQueries, getStaticBundle, getStatusOverview, getTagsByRepositoryId, getTeam, getTimeBucketStats, getTodayStats, getTrace, getUnifiedTrace, getUniqueCounts, getUniqueEvents, getUpdateStatus, getUptimeHistory, getUsageByProvider, getUsageRecent, getUsageSummary, getUsageTimeseries, getUsageTopModels, getVisitorByGuid, getVisitorById, getVisitorDetails, getVisitorFacets, getVisitorInfo, getVisitorJourney, getVisitors, getVisitorSessions, getVisitorStats, getWebhook, grantProjectAccess, handleGitProviderOauthCallback, hasAnalyticsEvents, hasErrorGroups, hasPerformanceMetrics, importExternalService, ingestLogs, ingestLogsByPath, ingestMetrics, ingestMetricsByPath, ingestSentryEnvelope, ingestSentryEvent, ingestTraces, ingestTracesByPath, initSessionReplay, inspectDropArchive, jobLogs, jobStatus, killJob, kvDel, kvDisable, kvEnable, kvExpire, kvGet, kvIncr, kvKeys, kvSet, kvStatus, kvTtl, kvUpdate, latestRunForSource, linkCustomDomainToCertificate, linkServiceToProject, listAgentRuns, listAgents, listAiProviders, listAlertRules, listAlerts, listAllConversations, listAllRuns, listApiKeys, listAuditLogs, listAvailableContainers, listBackupAlerts, listBackupChildren, listBackupSchedules, listBackupsForSchedule, listCommitsByRepositoryId, listConnections, listContainers, listContainersAtPath, listConversations, listCustomDomainsForProject, listDashboards, listDeliveries, listDeploymentContainerLogs, listDeploymentTokens, listDnsProviders, listDomains, listDsns, listEmailDomains, listEmailProviders, listEmails, listEnrollmentTokens, listEntities, listErrorEvents, listErrorGroups, listEvents, listEventTypes, listExternalImages, listExternalPlugins, listExternalServiceBackups, listFlags, listFunnels, listGitProviders, listGlobalMcps, listGlobalSkills, listIncidents, listInsights, listIpAccessControl, listJobs, listKnownAiAgents, listManagedDomains, listMcps, listMetricLabelKeys, listMetricLabelValues, listMetricNames, listModels, listMonitors, listNotificationProviders, listOidcProviders, listOidcProviderUsers, listOidcRoleMappings, listOnDemandCerts, listOrders, listPeers, listPendingActions, listPgUpgrades, listPresets, listProjectAccess, listProjectAlarms, listProjectScans, listProjectSecrets, listProjectServices, listProjectTemplates, listProjectTemplateTags, listProviderKeys, listProviderZones, listPublicProviders, listReleaseFiles, listReleases, listRemoteExternalImages, listRepositoriesByConnection, listRepositoriesByProvider, listRestoreRunsForService, listRootContainers, listRoutes, listS3Sources, listSandboxes, listScheduleRunJobs, listScheduleRuns, listScheduleServices, listSecrets, listServiceHealthStatuses, listServiceProjects, listServices, listServiceSchedules, listSkills, listSourceBackups, listSourceFiles, listSourceMaps, listSources, listStaticBundles, listSyncedRepositories, listTeamMembers, listTeamProjects, listTeams, listUsers, listWebhooks, login, logout, lookupDnsARecords, mintEnrollmentToken, mkdir, nodeHeartbeat, nodeMetricsGetRange, observabilityFullEvent, observabilityListEvents, oidcCallback, type Options, patchAdminGate, patchPreviewGatewaySettings, pauseDeployment, pauseSandbox, planRestore, postDnsAck, previewAlert, previewFunnelMetrics, previewHostnameMode, promoteClusterMember, promoteDeployment, provisionDomain, purgeProjectLogs, pushExternalImage, queryData, queryGenaiTraces, queryLogs, queryMetrics, queryTraces, queryTraceSummaries, readFile, reAnalyze, recordConsoleEvent, recordEventMetrics, recordFlagExposure, recordSpeedMetrics, refreshRouteTable, regenerateDsn, registerExternalImage, registerNode, reinstallGitlabWebhook, rejectPendingAction, reloadPlugins, removeClusterMember, removeManagedDomain, removeRole, removeTeamMember, renameConversation, renewDomain, requestPasswordReset, resetPassword, resizeSandbox, resolveAlarm, restartContainer, restartPreviewGateway, restartSandbox, restoreFlag, restoreUser, resumeDeployment, resumeSandbox, retryCluster, retryDelivery, retryPgUpgrade, retryRun, revealGlobalMcpConfig, revealMcpConfig, revealNotificationProviderConfig, revealServiceParameter, revenueCreateIntegration, revenueDeleteIntegration, revenueGlobalEvents, revenueImportInvoicesCsv, revenueImportSubscriptionsCsv, revenueListIntegrations, revenueListProviders, revenueMetricsCustomers, revenueMetricsGlobalMrr, revenueMetricsGlobalSummary, revenueMetricsMrr, revenueMetricsSummary, revenueRecentEvents, revenueRotateToken, revenueUpdateConfig, revenueUpdateSecret, revokeDsn, revokeEnrollmentToken, revokeJoinToken, revokeProjectAccess, rollbackPgUpgrade, rollbackToDeployment, rootfsGc, rootfsReport, rotateApiKey, rotateDeploymentToken, runBackupForSource, runConnectionHealthCheck, runExternalServiceBackup, runScheduleNow, sandboxCreatePreviewLink, saveAgentToken, saveAiProviderCredential, searchLogs, sendEmail, setDefaultS3Source, setFlagEnvironment, setPreviewPassword, setupDns, setupDnsChallenge, setupEmailTracking, setupMfa, sleepEnvironment, smokeTestAgent, sourceSandbox, startAnalysis, startContainer, startFix, startGitProviderOauth, startOidcLoginBySlug, startPgUpgrade, startRestore, startService, statPath, stopContainer, stopSandbox, stopService, streamContainerMetrics, streamEvents, streamRunEvents, syncRepositories, tailDeploymentJobLogs, tailLogs, teardownDeployment, teardownEnvironment, testNotificationProvider, testOidcProvider, testProvider, testProviderConnection, testProviderKeyById, testProviderKeyInline, testS3ConnectionPreview, testS3SourceConnection, trackClick, trackOpen, triggerAgent, triggerProjectPipeline, triggerScan, triggerServiceHealthCheck, triggerWeeklyDigest, unlinkServiceFromProject, updateAgent, updateAiProvider, updateAlert, updateAlertRule, updateApiKey, updateAutomaticDeploy, updateBackupSchedule, updateCloudflareProvider, updateConnectionToken, updateCustomDomain, updateDashboard, updateDeploymentToken, updateEmailProvider, updateEnvironmentSettings, updateEnvironmentSubdomain, updateEnvironmentVariable, updateErrorGroup, updateFlag, updateFunnel, updateGitProviderCredentials, updateGitSettings, updateGlobalMcp, updateGlobalSkill, updateIncidentStatus, updateIpAccessControl, updateManagedDomain, updateMcp, updateNotificationEmailProvider, updateNotificationProvider, updateOidcProvider, updatePreferences, updateProject, updateProjectDeploymentConfig, updateProjectSecret, updateProjectSettings, updateProvider, updateProviderKey, updateRoute, updateS3Source, updateSelf, updateService, updateServiceResources, updateSessionDuration, updateSettings, updateSkill, updateSlackProvider, updateSpeedMetrics, updateTeam, updateTeamMemberRole, updateUser, updateWebhook, updateWebhookProvider, upgradePreviewGateway, upgradeService, uploadGlobalSkill, uploadReleaseFile, uploadSkill, uploadSourceFile, uploadSourceMap, uploadStaticBundle, upsertSecret, validateConnection, validateEmail, verifyAndEnableMfa, verifyDomain, verifyEmail, verifyManagedDomain, verifyMfaChallenge, verifyStepUp, wakeEnvironment, webhookTrigger, workflowDryRun, writeFile, writeFiles } from './sdk.gen'; +export type { AcknowledgeAlarmData, AcknowledgeAlarmErrors, AcknowledgeAlarmResponses, AcmeOrderResponse, ActivateAiProviderData, ActivateAiProviderErrors, ActivateAiProviderResponse, ActivateAiProviderResponses, ActivateApiKeyData, ActivateApiKeyErrors, ActivateApiKeyResponse, ActivateApiKeyResponses, ActivateConnectionData, ActivateConnectionErrors, ActivateConnectionResponses, ActivateProviderData, ActivateProviderErrors, ActivateProviderResponse, ActivateProviderResponses, ActiveVisitor, ActiveVisitorsQuery, ActiveVisitorsResponse, ActivityDay, ActivityEvent, ActivityGraphQuery, ActivityGraphResponse, AddClusterMemberData, AddClusterMemberErrors, AddClusterMemberRequest, AddClusterMemberResponse, AddClusterMemberResponses, AddContextData, AddContextErrors, AddContextRequest, AddContextResponses, AddEnvironmentDomainData, AddEnvironmentDomainErrors, AddEnvironmentDomainRequest, AddEnvironmentDomainResponse, AddEnvironmentDomainResponses, AddEventsData, AddEventsError, AddEventsErrors, AddEventsRequest, AddEventsResponse, AddEventsResponse2, AddEventsResponses, AddManagedDomainApiRequest, AddManagedDomainData, AddManagedDomainErrors, AddManagedDomainResponse, AddManagedDomainResponses, AddSessionReplayEventsData, AddSessionReplayEventsError, AddSessionReplayEventsErrors, AddSessionReplayEventsResponse, AddSessionReplayEventsResponses, AddTeamMemberData, AddTeamMemberErrors, AddTeamMemberResponse, AddTeamMemberResponses, AdminDrainNodeData, AdminDrainNodeErrors, AdminDrainNodeResponse, AdminDrainNodeResponses, AdminDrainStatusData, AdminDrainStatusErrors, AdminDrainStatusResponse, AdminDrainStatusResponses, AdminGateResponse, AdminGateSource, AdminGetNodeData, AdminGetNodeErrors, AdminGetNodeResponse, AdminGetNodeResponses, AdminListNodeContainersData, AdminListNodeContainersErrors, AdminListNodeContainersResponse, AdminListNodeContainersResponses, AdminListNodesData, AdminListNodesErrors, AdminListNodesResponse, AdminListNodesResponses, AdminRemoveNodeData, AdminRemoveNodeErrors, AdminRemoveNodeResponse, AdminRemoveNodeResponses, AdminUndrainNodeData, AdminUndrainNodeErrors, AdminUndrainNodeResponse, AdminUndrainNodeResponses, AgentConfigResponse, AgentRunLogResponse, AgentRunResponse, AgentRunWithLogsResponse, AgentSandboxSettings, AgentSandboxSettingsMasked, AggregatedBucketItem, AggregatedBucketsQuery, AggregatedBucketsResponse, AggregationLevel, AggregationTemporality, AiAgentBreakdownResponse, AiAgentBreakdownRow, AiAgentDescriptor, AiAgentPageRow, AiAgentPagesResponse, AiAgentTimelineResponse, AiAgentTimelineRow, AiChatLimitsSettings, AiConfigSettings, AiPageBreakdownResponse, AiPageBreakdownRow, AiStatusBreakdownResponse, AiStatusBreakdownRow, AlarmListResponse, AlarmResponse, AlarmSummaryResponse, AlertRuleResponse, AllocEntry, AnalyticsSessionEventsResponse, AnnotatedSpan, AnomalyAlgorithm, AnomalyParams, AnomalyPreviewPointResponse, AnomalyPreviewRequest, AnomalyPreviewResponse, ApiKeyListResponse, ApiKeyResponse, ApplyHostnameModeData, ApplyHostnameModeErrors, ApplyHostnameModeRequest, ApplyHostnameModeResponse, ApplyHostnameModeResponses, AppSettings, AppSettingsResponse, ArchiveConversationData, ArchiveConversationErrors, ArchiveConversationResponse, ArchiveConversationResponses, ArchiveFlagData, ArchiveFlagErrors, ArchiveFlagResponse, ArchiveFlagResponse2, ArchiveFlagResponses, ArchiveMode, AssignRoleData, AssignRoleErrors, AssignRoleRequest, AssignRoleResponses, AttachScheduleServicesData, AttachScheduleServicesError, AttachScheduleServicesErrors, AttachScheduleServicesRequest, AttachScheduleServicesResponse, AttachScheduleServicesResponse2, AttachScheduleServicesResponses, AuditLogIpInfo, AuditLogResponse, AuditLogUserInfo, AuthFlavorDto, AuthResponse, AuthStatusResponse, AuthTokenResponse, AutofixerRunResponse, AutofixerRunWithLogsResponse, AutofixRunConfig, AutoWatchParams, AvailableContainerInfo, AvailablePermissions, BackupAlertListResponse, BackupAlertResponse, BackupResponse, BackupScheduleResponse, BitbucketAuthInput, BlobCopyData, BlobCopyError, BlobCopyErrors, BlobCopyResponse, BlobCopyResponses, BlobDeleteData, BlobDeleteError, BlobDeleteErrors, BlobDeleteResponse, BlobDeleteResponses, BlobDisableData, BlobDisableErrors, BlobDisableResponse, BlobDisableResponses, BlobDownloadData, BlobDownloadError, BlobDownloadErrors, BlobDownloadResponses, BlobEnableData, BlobEnableErrors, BlobEnableResponse, BlobEnableResponses, BlobHeadData, BlobHeadError, BlobHeadErrors, BlobHeadResponses, BlobListData, BlobListError, BlobListErrors, BlobListResponse, BlobListResponses, BlobPutData, BlobPutError, BlobPutErrors, BlobPutResponse, BlobPutResponses, BlobResponse, BlobStatusData, BlobStatusErrors, BlobStatusResponse, BlobStatusResponse2, BlobStatusResponses, BlobUpdateData, BlobUpdateErrors, BlobUpdateResponse, BlobUpdateResponses, BranchInfo, BranchListResponse, BrowserCount, BrowsersQuery, BuildConfiguration, BuildLimitsSettings, CancelBackupData, CancelBackupError, CancelBackupErrors, CancelBackupResponse, CancelBackupResponse2, CancelBackupResponses, CancelData, CancelDeploymentData, CancelDeploymentErrors, CancelDeploymentResponse, CancelDeploymentResponses, CancelDomainOrderData, CancelDomainOrderErrors, CancelDomainOrderResponse, CancelDomainOrderResponses, CancelErrors, CancelPgUpgradeData, CancelPgUpgradeErrors, CancelPgUpgradeResponse, CancelPgUpgradeResponses, CancelResponses, CancelRunData, CancelRunErrors, CancelRunResponse, CancelRunResponses, CancelScheduleRunData, CancelScheduleRunError, CancelScheduleRunErrors, CancelScheduleRunResponse, CancelScheduleRunResponses, CertStatusResponse, ChallengeConfig, ChallengeError, ChallengeValidationStatus, ChangePasswordRequest, ChangePasswordSelfData, ChangePasswordSelfErrors, ChangePasswordSelfResponse, ChangePasswordSelfResponses, ChangeProjectSourceData, ChangeProjectSourceErrors, ChangeProjectSourceRequest, ChangeProjectSourceResponse, ChangeProjectSourceResponses, ChatCompletionChoice, ChatCompletionRequest, ChatCompletionResponse, ChatCompletionsData, ChatCompletionsError, ChatCompletionsErrors, ChatCompletionsResponse, ChatCompletionsResponses, ChatMessage, ChatReadinessResponse, CheckAnalyticsHasEventsData, CheckAnalyticsHasEventsErrors, CheckAnalyticsHasEventsResponse, CheckAnalyticsHasEventsResponses, CheckCommitExistsData, CheckCommitExistsErrors, CheckCommitExistsResponse, CheckCommitExistsResponses, CheckDomainStatusData, CheckDomainStatusErrors, CheckDomainStatusResponse, CheckDomainStatusResponses, CheckExplorerSupportData, CheckExplorerSupportErrors, CheckExplorerSupportResponse, CheckExplorerSupportResponses, CheckIpBlockedData, CheckIpBlockedError, CheckIpBlockedErrors, CheckIpBlockedResponses, CheckProviderDeletionSafetyData, CheckProviderDeletionSafetyErrors, CheckProviderDeletionSafetyResponse, CheckProviderDeletionSafetyResponses, ChildBackupEntryResponse, ChildBackupListResponse, ChunkUploadOptionsData, ChunkUploadOptionsResponse, ChunkUploadOptionsResponses, CleanupExpiredBackupsData, CleanupExpiredBackupsError, CleanupExpiredBackupsErrors, CleanupExpiredBackupsRequest, CleanupExpiredBackupsResponse, CleanupExpiredBackupsResponses, ClearPreviewPasswordData, ClearPreviewPasswordErrors, ClearPreviewPasswordResponse, ClearPreviewPasswordResponses, CliDeviceApproveData, CliDeviceApproveErrors, CliDeviceApproveRequest, CliDeviceApproveResponse, CliDeviceApproveResponse2, CliDeviceApproveResponses, CliDeviceDenyData, CliDeviceDenyErrors, CliDeviceDenyResponse, CliDeviceDenyResponses, CliDeviceLookupData, CliDeviceLookupErrors, CliDeviceLookupResponse, CliDeviceLookupResponse2, CliDeviceLookupResponses, CliDevicePollData, CliDevicePollErrors, CliDevicePollRequest, CliDevicePollResponse, CliDevicePollResponse2, CliDevicePollResponses, CliDeviceStartData, CliDeviceStartErrors, CliDeviceStartRequest, CliDeviceStartResponse, CliDeviceStartResponse2, CliDeviceStartResponses, ClientOptions, CliLoginRequest, CliLogoutData, CliLogoutErrors, CliLogoutResponse, CliLogoutResponses, CloudCapability, CloudflareConfig, CloudProvider, CloudSettings, CloudStatus, ClusterCapacity, ClusterDnsSettings, ClusterHealthReportResponse, ClusterMemberHealthResponse, ClusterMemberRequest, CmdBody, CmdData, CmdErrors, CmdInner, CmdKillBody, CmdKillData, CmdKillErrors, CmdKillResponse, CmdKillResponses, CmdLogsData, CmdLogsErrors, CmdLogsResponses, CmdResponse, CmdResponse2, CmdResponses, CommitExistsResponse, CommitInfo, CommitListResponse, Comparator, ComposePublicPort, ConfirmPendingActionData, ConfirmPendingActionErrors, ConfirmPendingActionResponse, ConfirmPendingActionResponses, ConnectionListQuery, ConnectionListResponse, ConnectionResponse, ConnectionTestResult, ConsoleEventPayload, ContainerActionResponse, ContainerDetailResponse, ContainerEnvironmentVariableValueResponse, ContainerInfoResponse, ContainerInventoryItem, ContainerListResponse, ContainerLogSettings, ContainerLogsQuery, ContainerMetricHistoryPoint, ContainerMetricsGetHistoryData, ContainerMetricsGetHistoryErrors, ContainerMetricsGetHistoryResponse, ContainerMetricsGetHistoryResponses, ContainerMetricsHistoryQuery, ContainerMetricsResponse, ContainerResponse, ContainerRuntimeInfo, ContainerStatsSample, ContentPart, ContextLine, ContextLogsRequest, ContextLogsResponse, ConversationDetailResponse, ConversationResponse, ConversationsQueryParams, ConversationSummary, CopyBlobRequest, CostAnalysis, CreateAgentData, CreateAgentErrors, CreateAgentResponse, CreateAgentResponses, CreateAlertData, CreateAlertError, CreateAlertErrors, CreateAlertResponse, CreateAlertResponses, CreateAlertRuleData, CreateAlertRuleErrors, CreateAlertRuleRequest, CreateAlertRuleResponse, CreateAlertRuleResponses, CreateApiKeyData, CreateApiKeyErrors, CreateApiKeyRequest, CreateApiKeyResponse, CreateApiKeyResponse2, CreateApiKeyResponses, CreateBackupScheduleData, CreateBackupScheduleError, CreateBackupScheduleErrors, CreateBackupScheduleRequest, CreateBackupScheduleResponse, CreateBackupScheduleResponses, CreateBitbucketProviderData, CreateBitbucketProviderErrors, CreateBitbucketProviderResponse, CreateBitbucketProviderResponses, CreateBitbucketRequest, CreateCloudflareProviderData, CreateCloudflareProviderErrors, CreateCloudflareProviderRequest, CreateCloudflareProviderResponse, CreateCloudflareProviderResponses, CreateConversationData, CreateConversationErrors, CreateConversationRequest, CreateConversationResponse, CreateConversationResponses, CreateCustomDomainData, CreateCustomDomainErrors, CreateCustomDomainResponse, CreateCustomDomainResponses, CreateDashboardData, CreateDashboardError, CreateDashboardErrors, CreateDashboardRequest, CreateDashboardResponse, CreateDashboardResponses, CreateDeploymentTokenData, CreateDeploymentTokenErrors, CreateDeploymentTokenRequest, CreateDeploymentTokenResponse, CreateDeploymentTokenResponse2, CreateDeploymentTokenResponses, CreateDnsProviderData, CreateDnsProviderErrors, CreateDnsProviderRequest, CreateDnsProviderResponse, CreateDnsProviderResponses, CreateDomainData, CreateDomainErrors, CreateDomainRequest, CreateDomainResponse, CreateDomainResponses, CreatedResource, CreateDsnData, CreateDsnErrors, CreateDsnRequest, CreateDsnResponse, CreateDsnResponses, CreateEmailDomainData, CreateEmailDomainErrors, CreateEmailDomainRequest, CreateEmailDomainResponse, CreateEmailDomainResponses, CreateEmailProviderData, CreateEmailProviderErrors, CreateEmailProviderRequest, CreateEmailProviderResponse, CreateEmailProviderResponses, CreateEnvironmentData, CreateEnvironmentErrors, CreateEnvironmentRequest, CreateEnvironmentResponse, CreateEnvironmentResponses, CreateEnvironmentVariableData, CreateEnvironmentVariableErrors, CreateEnvironmentVariableRequest, CreateEnvironmentVariableResponse, CreateEnvironmentVariableResponses, CreateExternalServiceRequest, CreateFlagData, CreateFlagErrors, CreateFlagRequest, CreateFlagResponse, CreateFlagResponses, CreateFunnelData, CreateFunnelErrors, CreateFunnelRequest, CreateFunnelResponse, CreateFunnelResponse2, CreateFunnelResponses, CreateFunnelStep, CreateGenericProviderData, CreateGenericProviderErrors, CreateGenericProviderResponse, CreateGenericProviderResponses, CreateGenericRequest, CreateGiteaPatProviderData, CreateGiteaPatProviderErrors, CreateGiteaPatProviderResponse, CreateGiteaPatProviderResponses, CreateGiteaPatRequest, CreateGithubPatProviderData, CreateGithubPatProviderErrors, CreateGithubPatProviderResponse, CreateGithubPatProviderResponses, CreateGitHubPatRequest, CreateGitlabOauthProviderData, CreateGitlabOauthProviderErrors, CreateGitlabOauthProviderResponse, CreateGitlabOauthProviderResponses, CreateGitLabOAuthRequest, CreateGitlabPatProviderData, CreateGitlabPatProviderErrors, CreateGitlabPatProviderResponse, CreateGitlabPatProviderResponses, CreateGitLabPatRequest, CreateGitProviderData, CreateGitProviderErrors, CreateGitProviderResponse, CreateGitProviderResponses, CreateGlobalMcpData, CreateGlobalMcpErrors, CreateGlobalMcpResponse, CreateGlobalMcpResponses, CreateGlobalSkillData, CreateGlobalSkillErrors, CreateGlobalSkillResponse, CreateGlobalSkillResponses, CreateIncidentData, CreateIncidentErrors, CreateIncidentRequest, CreateIncidentResponse, CreateIncidentResponses, CreateIntegrationBody, CreateIpAccessControlData, CreateIpAccessControlError, CreateIpAccessControlErrors, CreateIpAccessControlRequest, CreateIpAccessControlResponse, CreateIpAccessControlResponses, CreateMcpData, CreateMcpErrors, CreateMcpRequest, CreateMcpResponse, CreateMcpResponses, CreateMetricAlertRequest, CreateMonitorData, CreateMonitorErrors, CreateMonitorRequest, CreateMonitorResponse, CreateMonitorResponses, CreateNotificationEmailProviderData, CreateNotificationEmailProviderErrors, CreateNotificationEmailProviderRequest, CreateNotificationEmailProviderResponse, CreateNotificationEmailProviderResponses, CreateNotificationProviderData, CreateNotificationProviderErrors, CreateNotificationProviderResponse, CreateNotificationProviderResponses, CreateOidcProviderData, CreateOidcProviderErrors, CreateOidcProviderRequest, CreateOidcProviderResponse, CreateOidcProviderResponses, CreateOidcRoleMappingData, CreateOidcRoleMappingRequest, CreateOidcRoleMappingResponse, CreateOidcRoleMappingResponses, CreateOrRecreateOrderData, CreateOrRecreateOrderErrors, CreateOrRecreateOrderResponse, CreateOrRecreateOrderResponses, CreatePlanData, CreatePlanErrors, CreatePlanRequest, CreatePlanResponse, CreatePlanResponse2, CreatePlanResponses, CreatePrData, CreatePrErrors, CreateProjectAccessRequest, CreateProjectData, CreateProjectErrors, CreateProjectFromTemplateData, CreateProjectFromTemplateErrors, CreateProjectFromTemplateRequest, CreateProjectFromTemplateResponse, CreateProjectFromTemplateResponse2, CreateProjectFromTemplateResponses, CreateProjectReleaseData, CreateProjectReleaseErrors, CreateProjectReleaseResponse, CreateProjectReleaseResponses, CreateProjectRequest, CreateProjectResponse, CreateProjectResponses, CreateProjectSecretData, CreateProjectSecretErrors, CreateProjectSecretRequest, CreateProjectSecretResponse, CreateProjectSecretResponses, CreateProviderKeyData, CreateProviderKeyError, CreateProviderKeyErrors, CreateProviderKeyRequest, CreateProviderKeyResponse, CreateProviderKeyResponses, CreateProviderRequest, CreatePrResponse, CreatePrResponse2, CreatePrResponses, CreateReleaseData, CreateReleaseErrors, CreateReleaseResponse, CreateReleaseResponses, CreateRouteData, CreateRouteErrors, CreateRouteRequest, CreateRouteResponse, CreateRouteResponses, CreateS3SourceData, CreateS3SourceError, CreateS3SourceErrors, CreateS3SourceRequest, CreateS3SourceResponse, CreateS3SourceResponses, CreateSandboxBody, CreateSandboxData, CreateSandboxErrors, CreateSandboxResponse, CreateSandboxResponses, CreateServiceData, CreateServiceErrors, CreateServiceResponse, CreateServiceResponses, CreateSkillData, CreateSkillErrors, CreateSkillRequest, CreateSkillResponse, CreateSkillResponses, CreateSlackProviderData, CreateSlackProviderErrors, CreateSlackProviderRequest, CreateSlackProviderResponse, CreateSlackProviderResponses, CreateTeamData, CreateTeamErrors, CreateTeamMemberRequest, CreateTeamRequest, CreateTeamResponse, CreateTeamResponses, CreateUserData, CreateUserErrors, CreateUserRequest, CreateUserResponse, CreateUserResponses, CreateWebhookData, CreateWebhookErrors, CreateWebhookProviderData, CreateWebhookProviderErrors, CreateWebhookProviderRequest, CreateWebhookProviderResponse, CreateWebhookProviderResponses, CreateWebhookRequestBody, CreateWebhookResponse, CreateWebhookResponses, CronExecutionInfo, CronInfo, CrossProjectSiblingRef, CrossProjectTraceResponse, CurrentStatusResponse, CustomDomainRequest, CustomDomainResponse, CustomerMovementResponse, DashboardLayout, DashboardProjectsAnalyticsQuery, DashboardProjectsAnalyticsResponse, DashboardSection, DashboardTile, DatabaseMetricsResponse, DatabaseMetricsRow, DataImplication, DataImplicationSeverity, DeactivateApiKeyData, DeactivateApiKeyErrors, DeactivateApiKeyResponse, DeactivateApiKeyResponses, DeactivateConnectionData, DeactivateConnectionErrors, DeactivateConnectionResponses, DeactivateProviderData, DeactivateProviderErrors, DeactivateProviderResponses, DeleteAgentData, DeleteAgentErrors, DeleteAgentResponse, DeleteAgentResponses, DeleteAlertData, DeleteAlertError, DeleteAlertErrors, DeleteAlertResponse, DeleteAlertResponses, DeleteAlertRuleData, DeleteAlertRuleErrors, DeleteAlertRuleResponse, DeleteAlertRuleResponses, DeleteApiKeyData, DeleteApiKeyErrors, DeleteApiKeyResponse, DeleteApiKeyResponses, DeleteBackupData, DeleteBackupError, DeleteBackupErrors, DeleteBackupResponse, DeleteBackupResponses, DeleteBackupScheduleData, DeleteBackupScheduleError, DeleteBackupScheduleErrors, DeleteBackupScheduleResponse, DeleteBackupScheduleResponses, DeleteBlobRequest, DeleteBlobResponse, DeleteConnectionData, DeleteConnectionErrors, DeleteConnectionResponse, DeleteConnectionResponses, DeleteCustomDomainData, DeleteCustomDomainErrors, DeleteCustomDomainResponse, DeleteCustomDomainResponses, DeleteDashboardData, DeleteDashboardError, DeleteDashboardErrors, DeleteDashboardResponse, DeleteDashboardResponses, DeleteDeploymentTokenData, DeleteDeploymentTokenErrors, DeleteDeploymentTokenResponse, DeleteDeploymentTokenResponses, DeleteDnsProviderData, DeleteDnsProviderErrors, DeleteDnsProviderResponse, DeleteDnsProviderResponses, DeleteDomainData, DeleteDomainErrors, DeleteDomainResponse, DeleteDomainResponses, DeleteEmailDomainData, DeleteEmailDomainErrors, DeleteEmailDomainResponse, DeleteEmailDomainResponses, DeleteEmailProviderData, DeleteEmailProviderErrors, DeleteEmailProviderResponse, DeleteEmailProviderResponses, DeleteEnvironmentData, DeleteEnvironmentDomainData, DeleteEnvironmentDomainErrors, DeleteEnvironmentDomainResponse, DeleteEnvironmentDomainResponses, DeleteEnvironmentErrors, DeleteEnvironmentResponse, DeleteEnvironmentResponses, DeleteEnvironmentVariableData, DeleteEnvironmentVariableErrors, DeleteEnvironmentVariableResponse, DeleteEnvironmentVariableResponses, DeleteExternalImageData, DeleteExternalImageErrors, DeleteExternalImageResponse, DeleteExternalImageResponses, DeleteFunnelData, DeleteFunnelErrors, DeleteFunnelResponses, DeleteGitProviderData, DeleteGitProviderErrors, DeleteGitProviderResponse, DeleteGitProviderResponses, DeleteGlobalMcpData, DeleteGlobalMcpErrors, DeleteGlobalMcpResponse, DeleteGlobalMcpResponses, DeleteGlobalSkillData, DeleteGlobalSkillErrors, DeleteGlobalSkillResponse, DeleteGlobalSkillResponses, DeleteIpAccessControlData, DeleteIpAccessControlError, DeleteIpAccessControlErrors, DeleteIpAccessControlResponse, DeleteIpAccessControlResponses, DeleteMcpData, DeleteMcpErrors, DeleteMcpResponse, DeleteMcpResponses, DeleteMonitorData, DeleteMonitorErrors, DeleteMonitorResponse, DeleteMonitorResponses, DeleteNotificationProviderData, DeleteNotificationProviderErrors, DeleteNotificationProviderResponse, DeleteNotificationProviderResponses, DeleteOidcProviderData, DeleteOidcProviderResponse, DeleteOidcProviderResponses, DeleteOidcRoleMappingData, DeleteOidcRoleMappingResponse, DeleteOidcRoleMappingResponses, DeletePreferencesData, DeletePreferencesErrors, DeletePreferencesResponse, DeletePreferencesResponses, DeleteProjectData, DeleteProjectErrors, DeleteProjectResponse, DeleteProjectResponses, DeleteProjectSecretData, DeleteProjectSecretErrors, DeleteProjectSecretResponse, DeleteProjectSecretResponses, DeleteProviderKeyData, DeleteProviderKeyError, DeleteProviderKeyErrors, DeleteProviderKeyResponse, DeleteProviderKeyResponses, DeleteProviderSafelyData, DeleteProviderSafelyErrors, DeleteProviderSafelyResponse, DeleteProviderSafelyResponses, DeleteReleaseSourceFilesData, DeleteReleaseSourceFilesErrors, DeleteReleaseSourceFilesResponse, DeleteReleaseSourceFilesResponses, DeleteReleaseSourceMapsData, DeleteReleaseSourceMapsErrors, DeleteReleaseSourceMapsResponse, DeleteReleaseSourceMapsResponses, DeleteResponse, DeleteRouteData, DeleteRouteErrors, DeleteRouteResponse, DeleteRouteResponses, DeleteS3SourceData, DeleteS3SourceError, DeleteS3SourceErrors, DeleteS3SourceResponse, DeleteS3SourceResponses, DeleteScanData, DeleteScanError, DeleteScanErrors, DeleteScanResponse, DeleteScanResponses, DeleteSecretData, DeleteSecretErrors, DeleteSecretResponse, DeleteSecretResponses, DeleteServiceData, DeleteServiceErrors, DeleteServiceResponse, DeleteServiceResponses, DeleteSessionReplayData, DeleteSessionReplayError, DeleteSessionReplayErrors, DeleteSessionReplayResponses, DeleteSkillData, DeleteSkillErrors, DeleteSkillResponse, DeleteSkillResponses, DeleteSourceMapData, DeleteSourceMapErrors, DeleteSourceMapResponse, DeleteSourceMapResponses, DeleteStaticBundleData, DeleteStaticBundleErrors, DeleteStaticBundleResponse, DeleteStaticBundleResponses, DeleteTeamData, DeleteTeamErrors, DeleteTeamResponse, DeleteTeamResponses, DeleteUserData, DeleteUserErrors, DeleteUserResponse, DeleteUserResponses, DeleteWebhookData, DeleteWebhookErrors, DeleteWebhookResponse, DeleteWebhookResponses, DelRequest, DelResponse, DeployFromImageData, DeployFromImageErrors, DeployFromImageRequest, DeployFromImageResponse, DeployFromImageResponses, DeployFromImageUploadData, DeployFromImageUploadErrors, DeployFromImageUploadQuery, DeployFromImageUploadResponse, DeployFromImageUploadResponses, DeployFromStaticData, DeployFromStaticErrors, DeployFromStaticRequest, DeployFromStaticResponse, DeployFromStaticResponses, DeployFromUploadedSourceData, DeployFromUploadedSourceErrors, DeployFromUploadedSourceResponse, DeployFromUploadedSourceResponses, DeploymentConfig, DeploymentConfigSnapshot, DeploymentConfiguration, DeploymentContainerLogContentResponse, DeploymentContainerLogResponse, DeploymentContainerLogsListResponse, DeploymentEnvironmentResponse, DeploymentJobResponse, DeploymentJobsResponse, DeploymentListResponse, DeploymentMetadata, DeploymentMetricsGetLatestData, DeploymentMetricsGetLatestErrors, DeploymentMetricsGetLatestResponse, DeploymentMetricsGetLatestResponses, DeploymentMetricsGetRangeData, DeploymentMetricsGetRangeErrors, DeploymentMetricsGetRangeResponse, DeploymentMetricsGetRangeResponses, DeploymentMetricsToggleData, DeploymentMetricsToggleErrors, DeploymentMetricsToggleResponses, DeploymentResponse, DeploymentStateResponse, DeploymentStrategy, DeploymentTokenListResponse, DeploymentTokenResponse, DestroySandboxData, DestroySandboxErrors, DestroySandboxResponse, DestroySandboxResponses, DetachScheduleServiceData, DetachScheduleServiceError, DetachScheduleServiceErrors, DetachScheduleServiceResponse, DetachScheduleServiceResponses, DetectionConfig, DetectPublicPresetsData, DetectPublicPresetsErrors, DetectPublicPresetsResponse, DetectPublicPresetsResponses, DeviceCount, DigestSections, Direction, DisableBackupScheduleData, DisableBackupScheduleErrors, DisableBackupScheduleResponse, DisableBackupScheduleResponses, DisableBlobResponse, DisableKvResponse, DisableMfaData, DisableMfaErrors, DisableMfaRequest, DisableMfaResponse, DisableMfaResponses, DisconnectCloudData, DisconnectCloudResponse, DisconnectCloudResponses, DiscoverRequest, DiscoverResponse, DiscoverWorkloadsData, DiscoverWorkloadsErrors, DiscoverWorkloadsResponse, DiscoverWorkloadsResponses, DiskInfo, DiskSpaceAlert, DiskSpaceAlertSettings, DiskSpaceCheckResult, DnsAckRequest, DnsAckResponse, DnsChallengeRecordResult, DnsChangesResponse, DnsCompletionResponse, DnsLookupError, DnsLookupRequest, DnsLookupResponse, DnsProviderCredentials, DnsProviderResponse, DnsProviderSettings, DnsProviderSettingsMasked, DnsProviderType, DnsRecord, DnsRecordChange, DnsRecordContent, DnsRecordResponse, DnsRecordSetupResult, DnsRecordStatusResponse, DnsZone, DockerComposePresetConfig, DockerfilePresetConfig, DockerfileVariant, DockerRegistrySettings, DockerRegistrySettingsMasked, DomainAction, DomainChallengeResponse, DomainData, DomainEnvironmentResponse, DomainError, DomainErrors, DomainPlan, DomainResponse, DomainResponse2, DomainResponses, DownloadGlobalSkillArchiveData, DownloadGlobalSkillArchiveErrors, DownloadGlobalSkillArchiveResponse, DownloadGlobalSkillArchiveResponses, DownloadObjectData, DownloadObjectErrors, DownloadObjectResponse, DownloadObjectResponses, DownloadSkillArchiveData, DownloadSkillArchiveErrors, DownloadSkillArchiveResponse, DownloadSkillArchiveResponses, DrainNodeResponse, DrainStatusResponse, DropArchiveUpload, DropInspectionResponse, DropOffPoint, DropPresetCandidate, EmailConfig, EmailDomainResponse, EmailDomainWithDnsResponse, EmailProviderResponse, EmailProviderTypeRoute, EmailRequest, EmailResponse, EmailStatsResponse, EmailStatusData, EmailStatusErrors, EmailStatusResponse, EmailStatusResponse2, EmailStatusResponses, EmailTrackingResponse, EmailTrackingSetupResponse, EmailTrackingStatusResponse, EmbeddingData, EmbeddingInput, EmbeddingRequest, EmbeddingResponse, EmbeddingsData, EmbeddingsError, EmbeddingsErrors, EmbeddingsResponse, EmbeddingsResponses, EmbeddingUsage, EnableBackupScheduleData, EnableBackupScheduleErrors, EnableBackupScheduleResponse, EnableBackupScheduleResponses, EnableBlobRequest, EnableBlobResponse, EnableKvRequest, EnableKvResponse, EnablePgStatStatementsResponse, EndpointDto, EnqueuedJob, EnrichVisitorData, EnrichVisitorErrors, EnrichVisitorRequest, EnrichVisitorResponse, EnrichVisitorResponse2, EnrichVisitorResponses, EnrollCloudData, EnrollCloudRequest, EnrollCloudResponse, EnrollCloudResponses, EnrollmentTokenInfo, EnrollmentTokenListResponse, EntityInfoResponse, EntityResponse, EnvironmentConfiguration, EnvironmentDomainResponse, EnvironmentInfo, EnvironmentResponse, EnvironmentVariable, EnvironmentVariableInfo, EnvironmentVariableResponse, EnvironmentVariableValueResponse, EnvVarInput, EnvVarIntegrationInfo, EnvVarResponse, EnvVarTemplateResponse, ErrorDashboardStatsQuery, ErrorDashboardStatsResponse, ErrorEventResponse, ErrorGroupResponse, ErrorGroupStatsResponse, ErrorResponse, ErrorRow, ErrorTimeSeriesDataResponse, ErrorTimeSeriesQuery, EventActivityBucket, EventBreakdown, EventBrowserStats, EventCount, EventCountryStats, EventDetailQuery, EventDetailResponse, EventEntriesQuery, EventEntriesResponse, EventEntryInfo, EventKind, EventMetricsPayload, EventReferrerStats, EventsCountQuery, EventsResponse, EventTimeline, EventTimelineQuery, EventType, EventTypeBreakdown, EventTypeBreakdownQuery, EventTypeResponse, EventTypesResponse, EventVisitorInfo, EventVisitorsQuery, EventVisitorsResponse, ExecBody, ExecData, ExecDetachedData, ExecDetachedErrors, ExecDetachedResponse, ExecDetachedResponse2, ExecDetachedResponses, ExecErrors, ExecResponse, ExecResponse2, ExecResponses, ExecuteDeploymentOperationData, ExecuteDeploymentOperationErrors, ExecuteDeploymentOperationResponse, ExecuteDeploymentOperationResponses, ExecuteImportData, ExecuteImportErrors, ExecuteImportRequest, ExecuteImportResponse, ExecuteImportResponse2, ExecuteImportResponses, ExecuteOperationRequest, ExpireRequest, ExpireResponse, ExplorerSupportResponse, ExtendTimeoutBody, ExtendTimeoutData, ExtendTimeoutErrors, ExtendTimeoutResponse, ExtendTimeoutResponses, ExternalImageResponse, ExternalServiceBackupResponse, ExternalServiceDetails, ExternalServiceEnablePgStatStatementsData, ExternalServiceEnablePgStatStatementsErrors, ExternalServiceEnablePgStatStatementsResponse, ExternalServiceEnablePgStatStatementsResponses, ExternalServiceInfo, ExternalServiceMetricsByDatabaseData, ExternalServiceMetricsByDatabaseErrors, ExternalServiceMetricsByDatabaseResponse, ExternalServiceMetricsByDatabaseResponses, ExternalServiceMetricsCreateAlertRuleData, ExternalServiceMetricsCreateAlertRuleErrors, ExternalServiceMetricsCreateAlertRuleResponse, ExternalServiceMetricsCreateAlertRuleResponses, ExternalServiceMetricsDeleteAlertRuleData, ExternalServiceMetricsDeleteAlertRuleErrors, ExternalServiceMetricsDeleteAlertRuleResponse, ExternalServiceMetricsDeleteAlertRuleResponses, ExternalServiceMetricsGetAlertRulesData, ExternalServiceMetricsGetAlertRulesErrors, ExternalServiceMetricsGetAlertRulesResponse, ExternalServiceMetricsGetAlertRulesResponses, ExternalServiceMetricsGetLatestData, ExternalServiceMetricsGetLatestErrors, ExternalServiceMetricsGetLatestResponse, ExternalServiceMetricsGetLatestResponses, ExternalServiceMetricsGetRangeData, ExternalServiceMetricsGetRangeErrors, ExternalServiceMetricsGetRangeResponse, ExternalServiceMetricsGetRangeResponses, ExternalServiceMetricsStatusData, ExternalServiceMetricsStatusErrors, ExternalServiceMetricsStatusResponse, ExternalServiceMetricsStatusResponses, ExternalServiceMetricsToggleData, ExternalServiceMetricsToggleErrors, ExternalServiceMetricsToggleResponses, ExternalServiceMetricsUpdateAlertRuleData, ExternalServiceMetricsUpdateAlertRuleErrors, ExternalServiceMetricsUpdateAlertRuleResponse, ExternalServiceMetricsUpdateAlertRuleResponses, ExternalServiceResetPgStatStatementsData, ExternalServiceResetPgStatStatementsErrors, ExternalServiceResetPgStatStatementsResponse, ExternalServiceResetPgStatStatementsResponses, ExternalServiceSummary, FieldResponse, FinalizeOrderData, FinalizeOrderErrors, FinalizeOrderResponse, FinalizeOrderResponses, FinalizeProjectReleaseData, FinalizeProjectReleaseErrors, FinalizeProjectReleaseResponse, FinalizeProjectReleaseResponses, FindConversationData, FindConversationErrors, FindConversationResponse, FindConversationResponses, FiringSeriesEntry, FlagEnvironmentResponse, FlagListResponse, FlagResponse, FlagSnapshot, FlagSnapshotResponse, FlagValueType, ForecastAlgorithm, ForecastParams, FullError, FullEvent, FullRequest, FunnelMetricsResponse, FunnelResponse, GatewayStatus, GenAiEvent, GenAiSpanDetail, GenAiTraceDetailResponse, GenAiTraceSummariesResponse, GenAiTraceSummary, GeneralStatsQuery, GeneralStatsResponse, GenerateDockerfileRequest, GenerateDockerfileResponse, GenerateJoinTokenData, GenerateJoinTokenErrors, GenerateJoinTokenResponse, GenerateJoinTokenResponse2, GenerateJoinTokenResponses, GeneratePresetDockerfileData, GeneratePresetDockerfileErrors, GeneratePresetDockerfileResponse, GeneratePresetDockerfileResponses, GeoLocationResponse, GeoRestrictionsConfig, GetAccessInfoData, GetAccessInfoErrors, GetAccessInfoResponse, GetAccessInfoResponses, GetActiveVisitorsData, GetActiveVisitorsErrors, GetActiveVisitorsResponse, GetActiveVisitorsResponses, GetActivityGraphData, GetActivityGraphErrors, GetActivityGraphResponse, GetActivityGraphResponses, GetAdminGateData, GetAdminGateErrors, GetAdminGateResponse, GetAdminGateResponses, GetAgentData, GetAgentErrors, GetAgentResponse, GetAgentResponses, GetAggregatedBucketsData, GetAggregatedBucketsErrors, GetAggregatedBucketsResponse, GetAggregatedBucketsResponses, GetAiAgentBreakdownData, GetAiAgentBreakdownError, GetAiAgentBreakdownErrors, GetAiAgentBreakdownResponse, GetAiAgentBreakdownResponses, GetAiAgentPagesData, GetAiAgentPagesError, GetAiAgentPagesErrors, GetAiAgentPagesResponse, GetAiAgentPagesResponses, GetAiAgentTimelineData, GetAiAgentTimelineError, GetAiAgentTimelineErrors, GetAiAgentTimelineResponse, GetAiAgentTimelineResponses, GetAiPageBreakdownData, GetAiPageBreakdownError, GetAiPageBreakdownErrors, GetAiPageBreakdownResponse, GetAiPageBreakdownResponses, GetAiStatusBreakdownData, GetAiStatusBreakdownError, GetAiStatusBreakdownErrors, GetAiStatusBreakdownResponse, GetAiStatusBreakdownResponses, GetAlertData, GetAlertError, GetAlertErrors, GetAlertResponse, GetAlertResponses, GetAlertRuleData, GetAlertRuleErrors, GetAlertRuleResponse, GetAlertRuleResponses, GetAllRepositoriesByNameData, GetAllRepositoriesByNameErrors, GetAllRepositoriesByNameResponse, GetAllRepositoriesByNameResponses, GetAnalyticsActiveVisitorsData, GetAnalyticsActiveVisitorsErrors, GetAnalyticsActiveVisitorsResponse, GetAnalyticsActiveVisitorsResponses, GetAnalyticsEventsCountData, GetAnalyticsEventsCountErrors, GetAnalyticsEventsCountResponse, GetAnalyticsEventsCountResponses, GetAnalyticsSessionEventsData, GetAnalyticsSessionEventsErrors, GetAnalyticsSessionEventsResponse, GetAnalyticsSessionEventsResponses, GetAnalyticsVisitorSessionsData, GetAnalyticsVisitorSessionsErrors, GetAnalyticsVisitorSessionsResponse, GetAnalyticsVisitorSessionsResponses, GetApiKeyData, GetApiKeyErrors, GetApiKeyPermissionsData, GetApiKeyPermissionsErrors, GetApiKeyPermissionsResponse, GetApiKeyPermissionsResponses, GetApiKeyResponse, GetApiKeyResponses, GetAuditLogData, GetAuditLogErrors, GetAuditLogResponse, GetAuditLogResponses, GetBackupData, GetBackupError, GetBackupErrors, GetBackupResponse, GetBackupResponses, GetBackupScheduleData, GetBackupScheduleErrors, GetBackupScheduleResponse, GetBackupScheduleResponses, GetBranchesByRepositoryIdData, GetBranchesByRepositoryIdErrors, GetBranchesByRepositoryIdResponse, GetBranchesByRepositoryIdResponses, GetBucketedIncidentsData, GetBucketedIncidentsErrors, GetBucketedIncidentsResponse, GetBucketedIncidentsResponses, GetBucketedStatusData, GetBucketedStatusErrors, GetBucketedStatusResponse, GetBucketedStatusResponses, GetChallengeTokenData, GetChallengeTokenErrors, GetChallengeTokenResponse, GetChallengeTokenResponses, GetChatReadinessData, GetChatReadinessErrors, GetChatReadinessResponse, GetChatReadinessResponses, GetCliStatusData, GetCliStatusErrors, GetCliStatusResponses, GetCloudCapabilityData, GetCloudCapabilityResponse, GetCloudCapabilityResponses, GetCloudStatusData, GetCloudStatusResponse, GetCloudStatusResponses, GetClusterHealthData, GetClusterHealthErrors, GetClusterHealthResponse, GetClusterHealthResponses, GetClusterMemberData, GetClusterMemberErrors, GetClusterMemberResponse, GetClusterMemberResponses, GetCmdData, GetCmdErrors, GetCmdResponse, GetCmdResponses, GetContainerDetailData, GetContainerDetailErrors, GetContainerDetailResponse, GetContainerDetailResponses, GetContainerEnvironmentVariableData, GetContainerEnvironmentVariableErrors, GetContainerEnvironmentVariableResponse, GetContainerEnvironmentVariableResponses, GetContainerInfoData, GetContainerInfoErrors, GetContainerInfoResponse, GetContainerInfoResponses, GetContainerLogsByIdData, GetContainerLogsByIdErrors, GetContainerLogsData, GetContainerLogsErrors, GetContainerMetricsData, GetContainerMetricsErrors, GetContainerMetricsResponse, GetContainerMetricsResponses, GetConversationData, GetConversationDetailData, GetConversationDetailError, GetConversationDetailErrors, GetConversationDetailResponse, GetConversationDetailResponses, GetConversationErrors, GetConversationResponse, GetConversationResponses, GetConversationsData, GetConversationsError, GetConversationsErrors, GetConversationsResponse, GetConversationsResponses, GetCronByIdData, GetCronByIdErrors, GetCronByIdResponse, GetCronByIdResponses, GetCronExecutionsData, GetCronExecutionsErrors, GetCronExecutionsResponse, GetCronExecutionsResponses, GetCrossProjectTraceSiblingsData, GetCrossProjectTraceSiblingsError, GetCrossProjectTraceSiblingsErrors, GetCrossProjectTraceSiblingsResponse, GetCrossProjectTraceSiblingsResponses, GetCurrentMonitorStatusData, GetCurrentMonitorStatusErrors, GetCurrentMonitorStatusResponse, GetCurrentMonitorStatusResponses, GetCurrentUserData, GetCurrentUserErrors, GetCurrentUserResponse, GetCurrentUserResponses, GetCustomDomainData, GetCustomDomainErrors, GetCustomDomainResponse, GetCustomDomainResponses, GetDashboardData, GetDashboardError, GetDashboardErrors, GetDashboardProjectsAnalyticsData, GetDashboardProjectsAnalyticsErrors, GetDashboardProjectsAnalyticsResponse, GetDashboardProjectsAnalyticsResponses, GetDashboardResponse, GetDashboardResponses, GetDeliveryData, GetDeliveryErrors, GetDeliveryResponse, GetDeliveryResponses, GetDeploymentContainerLogContentData, GetDeploymentContainerLogContentErrors, GetDeploymentContainerLogContentResponse, GetDeploymentContainerLogContentResponses, GetDeploymentData, GetDeploymentErrors, GetDeploymentJobLogsData, GetDeploymentJobLogsErrors, GetDeploymentJobLogsResponse, GetDeploymentJobLogsResponses, GetDeploymentJobsData, GetDeploymentJobsErrors, GetDeploymentJobsResponse, GetDeploymentJobsResponses, GetDeploymentOperationsData, GetDeploymentOperationsErrors, GetDeploymentOperationsResponse, GetDeploymentOperationsResponses, GetDeploymentOperationStatusData, GetDeploymentOperationStatusErrors, GetDeploymentOperationStatusResponse, GetDeploymentOperationStatusResponses, GetDeploymentResponse, GetDeploymentResponses, GetDeploymentsParams, GetDeploymentTokenData, GetDeploymentTokenErrors, GetDeploymentTokenResponse, GetDeploymentTokenResponses, GetDiskStatusData, GetDiskStatusErrors, GetDiskStatusResponse, GetDiskStatusResponses, GetDnsChangesData, GetDnsChangesErrors, GetDnsChangesResponse, GetDnsChangesResponses, GetDnsProviderData, GetDnsProviderErrors, GetDnsProviderResponse, GetDnsProviderResponses, GetDomainByHostData, GetDomainByHostErrors, GetDomainByHostResponse, GetDomainByHostResponses, GetDomainByIdData, GetDomainByIdErrors, GetDomainByIdResponse, GetDomainByIdResponses, GetDomainByNameData, GetDomainByNameErrors, GetDomainByNameResponse, GetDomainByNameResponses, GetDomainData, GetDomainDnsRecordsData, GetDomainDnsRecordsErrors, GetDomainDnsRecordsResponse, GetDomainDnsRecordsResponses, GetDomainErrors, GetDomainOrderData, GetDomainOrderErrors, GetDomainOrderResponse, GetDomainOrderResponses, GetDomainResponse, GetDomainResponses, GetEmailData, GetEmailErrors, GetEmailEventsData, GetEmailEventsErrors, GetEmailEventsResponse, GetEmailEventsResponses, GetEmailLinksData, GetEmailLinksErrors, GetEmailLinksResponse, GetEmailLinksResponses, GetEmailProviderData, GetEmailProviderErrors, GetEmailProviderResponse, GetEmailProviderResponses, GetEmailResponse, GetEmailResponses, GetEmailStatsData, GetEmailStatsErrors, GetEmailStatsResponse, GetEmailStatsResponses, GetEmailTrackingData, GetEmailTrackingErrors, GetEmailTrackingResponse, GetEmailTrackingResponses, GetEmailTrackingStatusData, GetEmailTrackingStatusErrors, GetEmailTrackingStatusResponse, GetEmailTrackingStatusResponses, GetEntityInfoData, GetEntityInfoErrors, GetEntityInfoResponse, GetEntityInfoResponses, GetEnvironmentCronsData, GetEnvironmentCronsErrors, GetEnvironmentCronsResponse, GetEnvironmentCronsResponses, GetEnvironmentData, GetEnvironmentDomainsData, GetEnvironmentDomainsErrors, GetEnvironmentDomainsResponse, GetEnvironmentDomainsResponses, GetEnvironmentErrors, GetEnvironmentResponse, GetEnvironmentResponses, GetEnvironmentsData, GetEnvironmentsErrors, GetEnvironmentsResponse, GetEnvironmentsResponses, GetEnvironmentVariablesData, GetEnvironmentVariablesErrors, GetEnvironmentVariablesQuery, GetEnvironmentVariablesResponse, GetEnvironmentVariablesResponses, GetEnvironmentVariableValueData, GetEnvironmentVariableValueErrors, GetEnvironmentVariableValueResponse, GetEnvironmentVariableValueResponses, GetErrorDashboardStatsData, GetErrorDashboardStatsErrors, GetErrorDashboardStatsResponse, GetErrorDashboardStatsResponses, GetErrorEventData, GetErrorEventErrors, GetErrorEventResponse, GetErrorEventResponses, GetErrorGroupData, GetErrorGroupErrors, GetErrorGroupResponse, GetErrorGroupResponses, GetErrorStatsData, GetErrorStatsErrors, GetErrorStatsResponse, GetErrorStatsResponses, GetErrorTimeSeriesData, GetErrorTimeSeriesErrors, GetErrorTimeSeriesResponse, GetErrorTimeSeriesResponses, GetEventDetailData, GetEventDetailErrors, GetEventDetailResponse, GetEventDetailResponses, GetEventEntriesData, GetEventEntriesErrors, GetEventEntriesResponse, GetEventEntriesResponses, GetEventsCountData, GetEventsCountErrors, GetEventsCountResponse, GetEventsCountResponses, GetEventsTimelineData, GetEventsTimelineErrors, GetEventsTimelineResponse, GetEventsTimelineResponses, GetEventTypeBreakdownData, GetEventTypeBreakdownErrors, GetEventTypeBreakdownResponse, GetEventTypeBreakdownResponses, GetEventVisitorsData, GetEventVisitorsErrors, GetEventVisitorsResponse, GetEventVisitorsResponses, GetExternalImageData, GetExternalImageErrors, GetExternalImageResponse, GetExternalImageResponses, GetFileData, GetFileErrors, GetFileResponse, GetFileResponses, GetFlagData, GetFlagErrors, GetFlagResponse, GetFlagResponses, GetFlagSnapshotData, GetFlagSnapshotErrors, GetFlagSnapshotResponse, GetFlagSnapshotResponses, GetFunnelMetricsData, GetFunnelMetricsErrors, GetFunnelMetricsQuery, GetFunnelMetricsResponse, GetFunnelMetricsResponses, GetGenaiTraceData, GetGenaiTraceError, GetGenaiTraceErrors, GetGenaiTraceResponse, GetGenaiTraceResponses, GetGeneralStatsData, GetGeneralStatsErrors, GetGeneralStatsResponse, GetGeneralStatsResponses, GetGitProviderData, GetGitProviderErrors, GetGitProviderResponse, GetGitProviderResponses, GetGlobalEventsData, GetGlobalEventsErrors, GetGlobalEventsResponse, GetGlobalEventsResponses, GetGlobalEventStatsData, GetGlobalEventStatsErrors, GetGlobalEventStatsResponse, GetGlobalEventStatsResponses, GetGlobalMcpData, GetGlobalMcpErrors, GetGlobalMcpResponse, GetGlobalMcpResponses, GetGlobalSandboxStatusData, GetGlobalSandboxStatusErrors, GetGlobalSandboxStatusResponse, GetGlobalSandboxStatusResponses, GetGlobalSkillData, GetGlobalSkillErrors, GetGlobalSkillResponse, GetGlobalSkillResponses, GetGroupedPageMetricsData, GetGroupedPageMetricsError, GetGroupedPageMetricsErrors, GetGroupedPageMetricsResponse, GetGroupedPageMetricsResponses, GetHealthData, GetHealthError, GetHealthErrors, GetHealthResponse, GetHealthResponses, GetHourlyVisitsData, GetHourlyVisitsErrors, GetHourlyVisitsResponse, GetHourlyVisitsResponses, GetHttpChallengeDebugData, GetHttpChallengeDebugErrors, GetHttpChallengeDebugResponse, GetHttpChallengeDebugResponses, GetImportStatusData, GetImportStatusErrors, GetImportStatusResponse, GetImportStatusResponses, GetIncidentData, GetIncidentErrors, GetIncidentResponse, GetIncidentResponses, GetIncidentUpdatesData, GetIncidentUpdatesErrors, GetIncidentUpdatesResponse, GetIncidentUpdatesResponses, GetIpAccessControlData, GetIpAccessControlError, GetIpAccessControlErrors, GetIpAccessControlResponse, GetIpAccessControlResponses, GetIpGeolocationData, GetIpGeolocationError, GetIpGeolocationErrors, GetIpGeolocationResponse, GetIpGeolocationResponses, GetJoinTokenStatusData, GetJoinTokenStatusErrors, GetJoinTokenStatusResponse, GetJoinTokenStatusResponses, GetLastDeploymentData, GetLastDeploymentErrors, GetLastDeploymentResponse, GetLastDeploymentResponses, GetLatestScanData, GetLatestScanError, GetLatestScanErrors, GetLatestScanResponse, GetLatestScanResponses, GetLatestScansPerEnvironmentData, GetLatestScansPerEnvironmentError, GetLatestScansPerEnvironmentErrors, GetLatestScansPerEnvironmentResponse, GetLatestScansPerEnvironmentResponses, GetLiveVisitorsListData, GetLiveVisitorsListErrors, GetLiveVisitorsListResponse, GetLiveVisitorsListResponses, GetLogContextData, GetLogContextError, GetLogContextErrors, GetLogContextResponse, GetLogContextResponses, GetMcpData, GetMcpErrors, GetMcpResponse, GetMcpResponses, GetMetricsOverTimeData, GetMetricsOverTimeError, GetMetricsOverTimeErrors, GetMetricsOverTimeResponse, GetMetricsOverTimeResponses, GetMonitorData, GetMonitorErrors, GetMonitorResponse, GetMonitorResponses, GetNotificationProviderData, GetNotificationProviderErrors, GetNotificationProviderResponse, GetNotificationProviderResponses, GetOnDemandCertStatusData, GetOnDemandCertStatusErrors, GetOnDemandCertStatusResponse, GetOnDemandCertStatusResponses, GetOrCreateDsnData, GetOrCreateDsnErrors, GetOrCreateDsnRequest, GetOrCreateDsnResponse, GetOrCreateDsnResponses, GetPageFlowData, GetPageFlowErrors, GetPageFlowResponse, GetPageFlowResponses, GetPageHourlySessionsData, GetPageHourlySessionsErrors, GetPageHourlySessionsResponse, GetPageHourlySessionsResponses, GetPagePathDetailData, GetPagePathDetailErrors, GetPagePathDetailResponse, GetPagePathDetailResponses, GetPagePathsData, GetPagePathsErrors, GetPagePathsResponse, GetPagePathsResponses, GetPagePathsSparklinesData, GetPagePathsSparklinesErrors, GetPagePathsSparklinesResponse, GetPagePathsSparklinesResponses, GetPagePathVisitorsData, GetPagePathVisitorsErrors, GetPagePathVisitorsResponse, GetPagePathVisitorsResponses, GetPendingActionData, GetPendingActionErrors, GetPendingActionResponse, GetPendingActionResponses, GetPerformanceMetricsData, GetPerformanceMetricsError, GetPerformanceMetricsErrors, GetPerformanceMetricsResponse, GetPerformanceMetricsResponses, GetPgUpgradeData, GetPgUpgradeErrors, GetPgUpgradeLogsData, GetPgUpgradeLogsErrors, GetPgUpgradeLogsResponse, GetPgUpgradeLogsResponses, GetPgUpgradeResponse, GetPgUpgradeResponses, GetPipelineStatsData, GetPipelineStatsError, GetPipelineStatsErrors, GetPipelineStatsResponse, GetPipelineStatsResponses, GetPlatformInfoData, GetPlatformInfoErrors, GetPlatformInfoResponse, GetPlatformInfoResponses, GetPostgresWalHealthData, GetPostgresWalHealthErrors, GetPostgresWalHealthResponse, GetPostgresWalHealthResponses, GetPreferencesData, GetPreferencesErrors, GetPreferencesResponse, GetPreferencesResponses, GetPreviewGatewayLogsData, GetPreviewGatewayLogsResponse, GetPreviewGatewayLogsResponses, GetPreviewGatewaySettingsData, GetPreviewGatewaySettingsResponse, GetPreviewGatewaySettingsResponses, GetPreviewGatewayStatusData, GetPreviewGatewayStatusResponse, GetPreviewGatewayStatusResponses, GetPricingData, GetPricingError, GetPricingErrors, GetPricingResponse, GetPricingResponses, GetPrivateIpData, GetPrivateIpErrors, GetPrivateIpResponses, GetProjectAlarmsSummaryData, GetProjectAlarmsSummaryErrors, GetProjectAlarmsSummaryResponse, GetProjectAlarmsSummaryResponses, GetProjectBySlugData, GetProjectBySlugErrors, GetProjectBySlugResponse, GetProjectBySlugResponses, GetProjectData, GetProjectDeploymentsData, GetProjectDeploymentsErrors, GetProjectDeploymentsResponse, GetProjectDeploymentsResponses, GetProjectErrors, GetProjectResponse, GetProjectResponses, GetProjectsData, GetProjectSecretsQuery, GetProjectsErrors, GetProjectServiceEnvironmentVariablesData, GetProjectServiceEnvironmentVariablesErrors, GetProjectServiceEnvironmentVariablesResponse, GetProjectServiceEnvironmentVariablesResponses, GetProjectSessionReplaysData, GetProjectSessionReplaysError, GetProjectSessionReplaysErrors, GetProjectSessionReplaysQuery, GetProjectSessionReplaysResponse, GetProjectSessionReplaysResponse2, GetProjectSessionReplaysResponses, GetProjectsHealthData, GetProjectsHealthError, GetProjectsHealthErrors, GetProjectsHealthResponse, GetProjectsHealthResponses, GetProjectsMonitorHealthData, GetProjectsMonitorHealthErrors, GetProjectsMonitorHealthResponse, GetProjectsMonitorHealthResponses, GetProjectsResponse, GetProjectsResponses, GetProjectStatisticsData, GetProjectStatisticsErrors, GetProjectStatisticsResponse, GetProjectStatisticsResponses, GetProjectTemplateData, GetProjectTemplateErrors, GetProjectTemplateResponse, GetProjectTemplateResponses, GetPropertyBreakdownData, GetPropertyBreakdownErrors, GetPropertyBreakdownResponse, GetPropertyBreakdownResponses, GetPropertyTimelineData, GetPropertyTimelineErrors, GetPropertyTimelineResponse, GetPropertyTimelineResponses, GetProviderConnectionsData, GetProviderConnectionsErrors, GetProviderConnectionsResponse, GetProviderConnectionsResponses, GetProviderMetadataData, GetProviderMetadataErrors, GetProviderMetadataResponse, GetProviderMetadataResponses, GetProvidersMetadataData, GetProvidersMetadataErrors, GetProvidersMetadataResponse, GetProvidersMetadataResponses, GetProxyLogByIdData, GetProxyLogByIdError, GetProxyLogByIdErrors, GetProxyLogByIdResponse, GetProxyLogByIdResponses, GetProxyLogByRequestIdData, GetProxyLogByRequestIdError, GetProxyLogByRequestIdErrors, GetProxyLogByRequestIdResponse, GetProxyLogByRequestIdResponses, GetProxyLogsData, GetProxyLogsError, GetProxyLogsErrors, GetProxyLogsResponse, GetProxyLogsResponses, GetPublicBranchesData, GetPublicBranchesErrors, GetPublicBranchesResponse, GetPublicBranchesResponses, GetPublicIpData, GetPublicIpErrors, GetPublicIpResponses, GetPublicRepositoryData, GetPublicRepositoryErrors, GetPublicRepositoryResponse, GetPublicRepositoryResponses, GetQuotaData, GetQuotaError, GetQuotaErrors, GetQuotaResponse, GetQuotaResponses, GetRecentActivityData, GetRecentActivityErrors, GetRecentActivityResponse, GetRecentActivityResponses, GetRemoteExternalImageData, GetRemoteExternalImageErrors, GetRemoteExternalImageResponse, GetRemoteExternalImageResponses, GetRepositoryBranchesData, GetRepositoryBranchesErrors, GetRepositoryBranchesResponse, GetRepositoryBranchesResponses, GetRepositoryByIdData, GetRepositoryByIdErrors, GetRepositoryByIdResponse, GetRepositoryByIdResponses, GetRepositoryByNameData, GetRepositoryByNameErrors, GetRepositoryByNameResponse, GetRepositoryByNameResponses, GetRepositoryPresetByNameData, GetRepositoryPresetByNameErrors, GetRepositoryPresetByNameResponse, GetRepositoryPresetByNameResponses, GetRepositoryPresetLiveData, GetRepositoryPresetLiveErrors, GetRepositoryPresetLiveResponse, GetRepositoryPresetLiveResponses, GetRepositoryTagsData, GetRepositoryTagsErrors, GetRepositoryTagsResponse, GetRepositoryTagsResponses, GetRequest, GetResolvedEnvironmentVariablesData, GetResolvedEnvironmentVariablesErrors, GetResolvedEnvironmentVariablesResponse, GetResolvedEnvironmentVariablesResponses, GetResolvedEnvironmentVariableValueData, GetResolvedEnvironmentVariableValueErrors, GetResolvedEnvironmentVariableValueResponse, GetResolvedEnvironmentVariableValueResponses, GetResponse, GetRestoreCapabilitiesData, GetRestoreCapabilitiesError, GetRestoreCapabilitiesErrors, GetRestoreCapabilitiesResponse, GetRestoreCapabilitiesResponses, GetRestoreRunData, GetRestoreRunError, GetRestoreRunErrors, GetRestoreRunResponse, GetRestoreRunResponses, GetRouteData, GetRouteErrors, GetRouteResponse, GetRouteResponses, GetRunData, GetRunErrors, GetRunResponse, GetRunResponses, GetRunWithLogsData, GetRunWithLogsErrors, GetRunWithLogsResponse, GetRunWithLogsResponses, GetS3CredentialsData, GetS3CredentialsErrors, GetS3CredentialsResponse, GetS3CredentialsResponses, GetS3SourceData, GetS3SourceError, GetS3SourceErrors, GetS3SourceResponse, GetS3SourceResponses, GetSandboxData, GetSandboxErrors, GetSandboxResponse, GetSandboxResponses, GetSandboxStatusData, GetSandboxStatusErrors, GetSandboxStatusResponse, GetSandboxStatusResponses, GetScanByDeploymentData, GetScanByDeploymentError, GetScanByDeploymentErrors, GetScanByDeploymentResponse, GetScanByDeploymentResponses, GetScanData, GetScanError, GetScanErrors, GetScanResponse, GetScanResponses, GetScanVulnerabilitiesData, GetScanVulnerabilitiesError, GetScanVulnerabilitiesErrors, GetScanVulnerabilitiesResponse, GetScanVulnerabilitiesResponses, GetServiceBySlugData, GetServiceBySlugErrors, GetServiceBySlugResponse, GetServiceBySlugResponses, GetServiceData, GetServiceEnvironmentVariableData, GetServiceEnvironmentVariableErrors, GetServiceEnvironmentVariableResponse, GetServiceEnvironmentVariableResponses, GetServiceEnvironmentVariablesData, GetServiceEnvironmentVariablesErrors, GetServiceEnvironmentVariablesResponse, GetServiceEnvironmentVariablesResponses, GetServiceErrors, GetServiceHealthStatusData, GetServiceHealthStatusErrors, GetServiceHealthStatusResponse, GetServiceHealthStatusResponses, GetServicePreviewEnvironmentVariableNamesData, GetServicePreviewEnvironmentVariableNamesErrors, GetServicePreviewEnvironmentVariableNamesResponse, GetServicePreviewEnvironmentVariableNamesResponses, GetServicePreviewEnvironmentVariablesMaskedData, GetServicePreviewEnvironmentVariablesMaskedErrors, GetServicePreviewEnvironmentVariablesMaskedResponse, GetServicePreviewEnvironmentVariablesMaskedResponses, GetServiceResponse, GetServiceResponses, GetServiceRuntimeData, GetServiceRuntimeErrors, GetServiceRuntimeResponse, GetServiceRuntimeResponses, GetServiceStatsData, GetServiceStatsErrors, GetServiceStatsResponse, GetServiceStatsResponses, GetServiceTypeParametersData, GetServiceTypeParametersErrors, GetServiceTypeParametersResponses, GetServiceTypesData, GetServiceTypesErrors, GetServiceTypesResponse, GetServiceTypesResponses, GetSessionDetailsData, GetSessionDetailsErrors, GetSessionDetailsResponse, GetSessionDetailsResponses, GetSessionEventsData, GetSessionEventsErrors, GetSessionEventsResponse, GetSessionEventsResponses, GetSessionLogsData, GetSessionLogsErrors, GetSessionLogsResponse, GetSessionLogsResponses, GetSessionReplayData, GetSessionReplayError, GetSessionReplayErrors, GetSessionReplayEventsData, GetSessionReplayEventsError, GetSessionReplayEventsErrors, GetSessionReplayEventsResponse, GetSessionReplayEventsResponses, GetSessionReplayResponse, GetSessionReplayResponse2, GetSessionReplayResponses, GetSettingsData, GetSettingsErrors, GetSettingsResponse, GetSettingsResponses, GetSkillData, GetSkillErrors, GetSkillResponse, GetSkillResponses, GetSlowQueriesData, GetSlowQueriesErrors, GetSlowQueriesResponse, GetSlowQueriesResponses, GetStaticBundleData, GetStaticBundleErrors, GetStaticBundleResponse, GetStaticBundleResponses, GetStatusOverviewData, GetStatusOverviewErrors, GetStatusOverviewResponse, GetStatusOverviewResponses, GetTagsByRepositoryIdData, GetTagsByRepositoryIdErrors, GetTagsByRepositoryIdResponse, GetTagsByRepositoryIdResponses, GetTeamData, GetTeamErrors, GetTeamResponse, GetTeamResponses, GetTimeBucketStatsData, GetTimeBucketStatsError, GetTimeBucketStatsErrors, GetTimeBucketStatsResponse, GetTimeBucketStatsResponses, GetTodayStatsData, GetTodayStatsError, GetTodayStatsErrors, GetTodayStatsResponse, GetTodayStatsResponses, GetTraceData, GetTraceError, GetTraceErrors, GetTraceResponse, GetTraceResponses, GetUnifiedTraceData, GetUnifiedTraceError, GetUnifiedTraceErrors, GetUnifiedTraceResponse, GetUnifiedTraceResponses, GetUniqueCountsData, GetUniqueCountsErrors, GetUniqueCountsResponse, GetUniqueCountsResponses, GetUniqueEventsData, GetUniqueEventsErrors, GetUniqueEventsQuery, GetUniqueEventsResponse, GetUniqueEventsResponses, GetUpdateStatusData, GetUpdateStatusErrors, GetUpdateStatusResponse, GetUpdateStatusResponses, GetUptimeHistoryData, GetUptimeHistoryErrors, GetUptimeHistoryResponse, GetUptimeHistoryResponses, GetUsageByProviderData, GetUsageByProviderError, GetUsageByProviderErrors, GetUsageByProviderResponse, GetUsageByProviderResponses, GetUsageRecentData, GetUsageRecentError, GetUsageRecentErrors, GetUsageRecentResponse, GetUsageRecentResponses, GetUsageSummaryData, GetUsageSummaryError, GetUsageSummaryErrors, GetUsageSummaryResponse, GetUsageSummaryResponses, GetUsageTimeseriesData, GetUsageTimeseriesError, GetUsageTimeseriesErrors, GetUsageTimeseriesResponse, GetUsageTimeseriesResponses, GetUsageTopModelsData, GetUsageTopModelsError, GetUsageTopModelsErrors, GetUsageTopModelsResponse, GetUsageTopModelsResponses, GetVisitorByGuidData, GetVisitorByGuidErrors, GetVisitorByGuidResponse, GetVisitorByGuidResponses, GetVisitorByIdData, GetVisitorByIdErrors, GetVisitorByIdResponse, GetVisitorByIdResponses, GetVisitorDetailsData, GetVisitorDetailsErrors, GetVisitorDetailsResponse, GetVisitorDetailsResponses, GetVisitorFacetsData, GetVisitorFacetsErrors, GetVisitorFacetsResponse, GetVisitorFacetsResponses, GetVisitorInfoData, GetVisitorInfoErrors, GetVisitorInfoResponse, GetVisitorInfoResponses, GetVisitorJourneyData, GetVisitorJourneyErrors, GetVisitorJourneyResponse, GetVisitorJourneyResponses, GetVisitorsData, GetVisitorsErrors, GetVisitorSessionsData, GetVisitorSessionsError, GetVisitorSessionsErrors, GetVisitorSessionsQuery, GetVisitorSessionsResponse, GetVisitorSessionsResponse2, GetVisitorSessionsResponses, GetVisitorsResponse, GetVisitorsResponses, GetVisitorStatsData, GetVisitorStatsErrors, GetVisitorStatsResponse, GetVisitorStatsResponses, GetWebhookData, GetWebhookErrors, GetWebhookResponse, GetWebhookResponses, GitPushEvent, GitRefResponse, GitSourcePlan, GlobalConversationResponse, GlobalEventStatsResponse, GlobalMrrResponse, GlobalRecentEventResponse, GlobalRevenueSummaryResponse, GrantProjectAccessData, GrantProjectAccessErrors, GrantProjectAccessResponse, GrantProjectAccessResponses, GroupedPageMetric, GroupedPageMetricsQuery, GroupedPageMetricsResponse, HandleGitProviderOauthCallbackData, HandleGitProviderOauthCallbackErrors, HasAnalyticsEventsData, HasAnalyticsEventsErrors, HasAnalyticsEventsResponse, HasAnalyticsEventsResponse2, HasAnalyticsEventsResponses, HasErrorGroupsData, HasErrorGroupsErrors, HasErrorGroupsResponse, HasErrorGroupsResponse2, HasErrorGroupsResponses, HasEventsQuery, HasEventsResponse, HasMetricsQuery, HasMetricsResponse, HasPerformanceMetricsData, HasPerformanceMetricsError, HasPerformanceMetricsErrors, HasPerformanceMetricsResponse, HasPerformanceMetricsResponses, HealthCheckConfiguration, HealthCheckEntryResponse, HealthResponse, HealthStatus, HealthSummary, HeartbeatApiRequest, HeartbeatResponse, HierarchyLevel, HistogramSummary, HostnameChange, HostnamePreviewResponse, HourlyPageSessions, HourlyVisitsQuery, HttpChallengeDebugResponse, ImportCredentials, ImportExecutionStatus, ImportExternalServiceData, ImportExternalServiceErrors, ImportExternalServiceRequest, ImportExternalServiceResponse, ImportExternalServiceResponses, ImportOutcomeResponse, ImportPlan, ImportRowErrorResponse, ImportSelector, ImportSource, ImportSourceCapabilities, ImportSourceInfo, ImportStatusResponse, IncidentBucket, IncidentBucketedResponse, IncidentResponse, IncidentUpdateResponse, IncrRequest, IncrResponse, IngestLogsByPathData, IngestLogsByPathError, IngestLogsByPathErrors, IngestLogsByPathResponses, IngestLogsData, IngestLogsError, IngestLogsErrors, IngestLogsResponses, IngestMetricsByPathData, IngestMetricsByPathError, IngestMetricsByPathErrors, IngestMetricsByPathResponses, IngestMetricsData, IngestMetricsError, IngestMetricsErrors, IngestMetricsResponses, IngestSentryEnvelopeData, IngestSentryEnvelopeErrors, IngestSentryEnvelopeResponses, IngestSentryEventData, IngestSentryEventErrors, IngestSentryEventResponse, IngestSentryEventResponses, IngestTracesByPathData, IngestTracesByPathError, IngestTracesByPathErrors, IngestTracesByPathResponses, IngestTracesData, IngestTracesError, IngestTracesErrors, IngestTracesResponses, InitAuthResponse, InitSessionReplayData, InitSessionReplayError, InitSessionReplayErrors, InitSessionReplayResponse, InitSessionReplayResponses, Insight, InsightSeverity, InsightsResponse, InsightStatus, InspectDropArchiveData, InspectDropArchiveErrors, InspectDropArchiveResponse, InspectDropArchiveResponses, IntegrationResponse, IpAccessControlQuery, IpAccessControlResponse, JobLogsData, JobLogsErrors, JobLogsResponses, JobStatusData, JobStatusErrors, JobStatusResponse, JobStatusResponse2, JobStatusResponses, JobSummaryResponse, JoinTokenStatusResponse, JourneyEvent, JourneySession, KeysRequest, KeysResponse, KillJobBody, KillJobData, KillJobErrors, KillJobResponse, KillJobResponses, KnownAiAgentsResponse, KvDelData, KvDelErrors, KvDelResponse, KvDelResponses, KvDisableData, KvDisableErrors, KvDisableResponse, KvDisableResponses, KvEnableData, KvEnableErrors, KvEnableResponse, KvEnableResponses, KvExpireData, KvExpireErrors, KvExpireResponse, KvExpireResponses, KvGetData, KvGetErrors, KvGetResponse, KvGetResponses, KvIncrData, KvIncrErrors, KvIncrResponse, KvIncrResponses, KvKeysData, KvKeysErrors, KvKeysResponse, KvKeysResponses, KvSetData, KvSetErrors, KvSetResponse, KvSetResponses, KvStatusData, KvStatusErrors, KvStatusResponse, KvStatusResponse2, KvStatusResponses, KvTtlData, KvTtlErrors, KvTtlResponse, KvTtlResponses, KvUpdateData, KvUpdateErrors, KvUpdateResponse, KvUpdateResponses, LatestRunForSourceData, LatestRunForSourceErrors, LatestRunForSourceResponse, LatestRunForSourceResponses, LemonSqueezyConfig, LetsEncryptSettings, LineContext, LinkCustomDomainToCertificateData, LinkCustomDomainToCertificateErrors, LinkCustomDomainToCertificateResponse, LinkCustomDomainToCertificateResponses, LinkServiceRequest, LinkServiceToProjectData, LinkServiceToProjectErrors, LinkServiceToProjectResponse, LinkServiceToProjectResponses, ListAgentRunsData, ListAgentRunsErrors, ListAgentRunsResponse, ListAgentRunsResponses, ListAgentsData, ListAgentsErrors, ListAgentsResponse, ListAgentsResponse2, ListAgentsResponses, ListAiProvidersData, ListAiProvidersErrors, ListAiProvidersResponse, ListAiProvidersResponses, ListAlertRulesData, ListAlertRulesErrors, ListAlertRulesResponse, ListAlertRulesResponses, ListAlertsData, ListAlertsError, ListAlertsErrors, ListAlertsResponse, ListAlertsResponses, ListAllConversationsData, ListAllConversationsErrors, ListAllConversationsResponse, ListAllConversationsResponses, ListAllRunsData, ListAllRunsErrors, ListAllRunsResponse, ListAllRunsResponses, ListApiKeysData, ListApiKeysErrors, ListApiKeysQuery, ListApiKeysResponse, ListApiKeysResponses, ListAuditLogsData, ListAuditLogsErrors, ListAuditLogsQuery, ListAuditLogsResponse, ListAuditLogsResponses, ListAvailableContainersData, ListAvailableContainersErrors, ListAvailableContainersResponse, ListAvailableContainersResponses, ListBackupAlertsData, ListBackupAlertsError, ListBackupAlertsErrors, ListBackupAlertsResponse, ListBackupAlertsResponses, ListBackupChildrenData, ListBackupChildrenError, ListBackupChildrenErrors, ListBackupChildrenResponse, ListBackupChildrenResponses, ListBackupSchedulesData, ListBackupSchedulesError, ListBackupSchedulesErrors, ListBackupSchedulesResponse, ListBackupSchedulesResponses, ListBackupsForScheduleData, ListBackupsForScheduleErrors, ListBackupsForScheduleResponse, ListBackupsForScheduleResponses, ListBlobsQuery, ListBlobsResponse, ListCommitsByRepositoryIdData, ListCommitsByRepositoryIdErrors, ListCommitsByRepositoryIdResponse, ListCommitsByRepositoryIdResponses, ListConnectionsData, ListConnectionsErrors, ListConnectionsResponse, ListConnectionsResponses, ListContainersAtPathData, ListContainersAtPathErrors, ListContainersAtPathResponse, ListContainersAtPathResponses, ListContainersData, ListContainersErrors, ListContainersResponse, ListContainersResponses, ListConversationsData, ListConversationsErrors, ListConversationsResponse, ListConversationsResponses, ListCustomDomainsForProjectData, ListCustomDomainsForProjectErrors, ListCustomDomainsForProjectResponse, ListCustomDomainsForProjectResponses, ListCustomDomainsResponse, ListDashboardsData, ListDashboardsError, ListDashboardsErrors, ListDashboardsResponse, ListDashboardsResponses, ListDeliveriesData, ListDeliveriesErrors, ListDeliveriesResponse, ListDeliveriesResponses, ListDeploymentContainerLogsData, ListDeploymentContainerLogsErrors, ListDeploymentContainerLogsResponse, ListDeploymentContainerLogsResponses, ListDeploymentTokensData, ListDeploymentTokensErrors, ListDeploymentTokensQuery, ListDeploymentTokensResponse, ListDeploymentTokensResponses, ListDnsProvidersData, ListDnsProvidersErrors, ListDnsProvidersResponse, ListDnsProvidersResponses, ListDomainsData, ListDomainsErrors, ListDomainsResponse, ListDomainsResponse2, ListDomainsResponses, ListDsnsData, ListDsnsErrors, ListDsnsResponse, ListDsnsResponses, ListEmailDomainsData, ListEmailDomainsErrors, ListEmailDomainsResponse, ListEmailDomainsResponses, ListEmailProvidersData, ListEmailProvidersErrors, ListEmailProvidersResponse, ListEmailProvidersResponses, ListEmailsData, ListEmailsErrors, ListEmailsResponse, ListEmailsResponses, ListEnrollmentTokensData, ListEnrollmentTokensErrors, ListEnrollmentTokensResponse, ListEnrollmentTokensResponses, ListEntitiesData, ListEntitiesErrors, ListEntitiesQuery, ListEntitiesResponse, ListEntitiesResponses, ListErrorEventsData, ListErrorEventsErrors, ListErrorEventsQuery, ListErrorEventsResponse, ListErrorEventsResponses, ListErrorGroupsData, ListErrorGroupsErrors, ListErrorGroupsQuery, ListErrorGroupsResponse, ListErrorGroupsResponses, ListEventsData, ListEventsResponse, ListEventsResponses, ListEventTypesData, ListEventTypesResponse, ListEventTypesResponses, ListExternalImagesData, ListExternalImagesErrors, ListExternalImagesResponse, ListExternalImagesResponses, ListExternalPluginsData, ListExternalPluginsErrors, ListExternalPluginsResponse, ListExternalPluginsResponses, ListExternalServiceBackupsData, ListExternalServiceBackupsError, ListExternalServiceBackupsErrors, ListExternalServiceBackupsResponse, ListExternalServiceBackupsResponses, ListFlagsData, ListFlagsErrors, ListFlagsResponse, ListFlagsResponses, ListFunnelsData, ListFunnelsErrors, ListFunnelsResponse, ListFunnelsResponses, ListGitProvidersData, ListGitProvidersErrors, ListGitProvidersResponse, ListGitProvidersResponses, ListGlobalMcpsData, ListGlobalMcpsErrors, ListGlobalMcpsResponse, ListGlobalMcpsResponses, ListGlobalSkillsData, ListGlobalSkillsErrors, ListGlobalSkillsResponse, ListGlobalSkillsResponses, ListIncidentsData, ListIncidentsErrors, ListIncidentsResponses, ListInsightsData, ListInsightsError, ListInsightsErrors, ListInsightsResponse, ListInsightsResponses, ListIpAccessControlData, ListIpAccessControlError, ListIpAccessControlErrors, ListIpAccessControlResponse, ListIpAccessControlResponses, ListJobsData, ListJobsErrors, ListJobsResponse, ListJobsResponse2, ListJobsResponses, ListKnownAiAgentsData, ListKnownAiAgentsError, ListKnownAiAgentsErrors, ListKnownAiAgentsResponse, ListKnownAiAgentsResponses, ListManagedDomainsData, ListManagedDomainsErrors, ListManagedDomainsResponse, ListManagedDomainsResponses, ListMcpsData, ListMcpsErrors, ListMcpsResponse, ListMcpsResponse2, ListMcpsResponses, ListMetricLabelKeysData, ListMetricLabelKeysError, ListMetricLabelKeysErrors, ListMetricLabelKeysResponse, ListMetricLabelKeysResponses, ListMetricLabelValuesData, ListMetricLabelValuesError, ListMetricLabelValuesErrors, ListMetricLabelValuesResponse, ListMetricLabelValuesResponses, ListMetricNamesData, ListMetricNamesError, ListMetricNamesErrors, ListMetricNamesResponse, ListMetricNamesResponses, ListModelsData, ListModelsError, ListModelsErrors, ListModelsResponse, ListModelsResponses, ListMonitorsData, ListMonitorsErrors, ListMonitorsResponse, ListMonitorsResponses, ListNotificationProvidersData, ListNotificationProvidersErrors, ListNotificationProvidersResponse, ListNotificationProvidersResponses, ListOidcProvidersData, ListOidcProvidersResponse, ListOidcProvidersResponses, ListOidcProviderUsersData, ListOidcProviderUsersErrors, ListOidcProviderUsersResponse, ListOidcProviderUsersResponses, ListOidcRoleMappingsData, ListOidcRoleMappingsResponse, ListOidcRoleMappingsResponses, ListOnDemandCertsData, ListOnDemandCertsErrors, ListOnDemandCertsResponse, ListOnDemandCertsResponse2, ListOnDemandCertsResponses, ListOrdersData, ListOrdersErrors, ListOrdersResponse, ListOrdersResponse2, ListOrdersResponses, ListPeersData, ListPeersErrors, ListPeersResponse, ListPeersResponses, ListPendingActionsData, ListPendingActionsErrors, ListPendingActionsResponse, ListPendingActionsResponses, ListPgUpgradesData, ListPgUpgradesErrors, ListPgUpgradesResponse, ListPgUpgradesResponses, ListPresetsData, ListPresetsErrors, ListPresetsResponse, ListPresetsResponse2, ListPresetsResponses, ListProjectAccessData, ListProjectAccessErrors, ListProjectAccessResponse, ListProjectAccessResponses, ListProjectAlarmsData, ListProjectAlarmsErrors, ListProjectAlarmsResponse, ListProjectAlarmsResponses, ListProjectScansData, ListProjectScansError, ListProjectScansErrors, ListProjectScansResponse, ListProjectScansResponses, ListProjectSecretsData, ListProjectSecretsErrors, ListProjectSecretsResponse, ListProjectSecretsResponses, ListProjectServicesData, ListProjectServicesErrors, ListProjectServicesResponse, ListProjectServicesResponses, ListProjectTemplatesData, ListProjectTemplatesErrors, ListProjectTemplatesResponse, ListProjectTemplatesResponses, ListProjectTemplateTagsData, ListProjectTemplateTagsErrors, ListProjectTemplateTagsResponse, ListProjectTemplateTagsResponses, ListProviderKeysData, ListProviderKeysError, ListProviderKeysErrors, ListProviderKeysResponse, ListProviderKeysResponses, ListProviderZonesData, ListProviderZonesErrors, ListProviderZonesResponse, ListProviderZonesResponses, ListPublicProvidersData, ListPublicProvidersResponse, ListPublicProvidersResponses, ListReleaseFilesData, ListReleaseFilesErrors, ListReleaseFilesResponse, ListReleaseFilesResponses, ListReleasesData, ListReleasesErrors, ListReleasesResponse, ListReleasesResponses, ListRemoteExternalImagesData, ListRemoteExternalImagesErrors, ListRemoteExternalImagesResponse, ListRemoteExternalImagesResponses, ListRepositoriesByConnectionData, ListRepositoriesByConnectionErrors, ListRepositoriesByConnectionResponse, ListRepositoriesByConnectionResponses, ListRepositoriesByProviderData, ListRepositoriesByProviderErrors, ListRepositoriesByProviderResponse, ListRepositoriesByProviderResponses, ListRestoreRunsForServiceData, ListRestoreRunsForServiceResponse, ListRestoreRunsForServiceResponses, ListRootContainersData, ListRootContainersErrors, ListRootContainersResponse, ListRootContainersResponses, ListRoutesData, ListRoutesErrors, ListRoutesResponse, ListRoutesResponses, ListRunsResponse, ListS3SourcesData, ListS3SourcesError, ListS3SourcesErrors, ListS3SourcesResponse, ListS3SourcesResponses, ListSandboxesData, ListSandboxesResponse, ListSandboxesResponse2, ListSandboxesResponses, ListScansQuery, ListScheduleRunJobsData, ListScheduleRunJobsError, ListScheduleRunJobsErrors, ListScheduleRunJobsResponse, ListScheduleRunJobsResponses, ListScheduleRunsData, ListScheduleRunsError, ListScheduleRunsErrors, ListScheduleRunsResponse, ListScheduleRunsResponses, ListScheduleServicesData, ListScheduleServicesError, ListScheduleServicesErrors, ListScheduleServicesResponse, ListScheduleServicesResponses, ListSecretsData, ListSecretsErrors, ListSecretsResponse, ListSecretsResponse2, ListSecretsResponses, ListServiceHealthStatusesData, ListServiceHealthStatusesErrors, ListServiceHealthStatusesResponse, ListServiceHealthStatusesResponses, ListServiceProjectsData, ListServiceProjectsErrors, ListServiceProjectsResponse, ListServiceProjectsResponses, ListServiceSchedulesData, ListServiceSchedulesError, ListServiceSchedulesErrors, ListServiceSchedulesResponse, ListServiceSchedulesResponses, ListServicesData, ListServicesErrors, ListServicesResponse, ListServicesResponses, ListSkillsData, ListSkillsErrors, ListSkillsResponse, ListSkillsResponse2, ListSkillsResponses, ListSourceBackupsData, ListSourceBackupsError, ListSourceBackupsErrors, ListSourceBackupsResponse, ListSourceBackupsResponses, ListSourceFilesData, ListSourceFilesErrors, ListSourceFilesResponse, ListSourceFilesResponses, ListSourceMapsData, ListSourceMapsErrors, ListSourceMapsResponse, ListSourceMapsResponses, ListSourcesData, ListSourcesErrors, ListSourcesResponse, ListSourcesResponses, ListStaticBundlesData, ListStaticBundlesErrors, ListStaticBundlesResponse, ListStaticBundlesResponses, ListSyncedRepositoriesData, ListSyncedRepositoriesErrors, ListSyncedRepositoriesResponse, ListSyncedRepositoriesResponses, ListTagsResponse, ListTeamMembersData, ListTeamMembersErrors, ListTeamMembersResponse, ListTeamMembersResponses, ListTeamProjectsData, ListTeamProjectsErrors, ListTeamProjectsResponse, ListTeamProjectsResponses, ListTeamsData, ListTeamsErrors, ListTeamsResponse, ListTeamsResponses, ListTemplatesQuery, ListTemplatesResponse, ListUsersData, ListUsersErrors, ListUsersResponse, ListUsersResponses, ListVulnerabilitiesQuery, ListWebhooksData, ListWebhooksErrors, ListWebhooksResponse, ListWebhooksResponses, LiveVisitorInfo, LiveVisitorsListResponse, LocationCount, LocationGranularity, LocationInfo, LoginData, LoginErrors, LoginRequest, LoginResponse, LoginResponses, LogLevel, LogoutData, LogoutErrors, LogoutResponses, LogRecord, LogSearchLine, LogSeverity, LogSource, LogsQuery, LogsResponse, LogStream, LookupDnsARecordsData, LookupDnsARecordsError, LookupDnsARecordsErrors, LookupDnsARecordsResponse, LookupDnsARecordsResponses, ManagedDomainResponse, ManualAction, ManualActionTiming, McpDefinitionResponse, MessageContent, MessagePart, MessageResponse, MeteredMode, MetricAggregation, MetricBucket, MetricDataPoint, MetricsOverTimeResponse, MetricsQuery, MetricsRangeQuery, MetricsStatusResponse, MetricsStoreKind, MetricsSummaryResponse, MetricType, MfaRequiredResponse, MfaSetupResponse, MfaVerificationRequest, MigrationStep, MigrationSummary, MintEnrollmentTokenData, MintEnrollmentTokenErrors, MintEnrollmentTokenRequest, MintEnrollmentTokenResponse, MintEnrollmentTokenResponse2, MintEnrollmentTokenResponses, MiscResult, MkdirBody, MkdirData, MkdirErrors, MkdirResponse, MkdirResponses, ModelInfo, ModelListResponse, ModelPricing, ModelUsage, MonitoringSettings, MonitoringSettingsMasked, MonitorResponse, MonitorStatus, MrrBucketResponse, MultiNodeSettings, MultiNodeSettingsMasked, MxResult, NavEntry, NavSection, NetworkConfiguration, NetworkMode, NixpacksPresetConfig, NixpacksProvider, NodeContainerListResponse, NodeContainerResponse, NodeCostInfo, NodeHeartbeatData, NodeHeartbeatErrors, NodeHeartbeatResponse, NodeHeartbeatResponses, NodeInfoResponse, NodeListResponse, NodeMetricsGetRangeData, NodeMetricsGetRangeErrors, NodeMetricsGetRangeResponse, NodeMetricsGetRangeResponses, NotificationPreferencesResponse, NotificationProviderResponse, ObservabilityCompressionSettings, ObservabilityEvent, ObservabilityFullEventData, ObservabilityFullEventError, ObservabilityFullEventErrors, ObservabilityFullEventResponse, ObservabilityFullEventResponses, ObservabilityListEventsData, ObservabilityListEventsError, ObservabilityListEventsErrors, ObservabilityListEventsResponse, ObservabilityListEventsResponses, ObservabilityRetentionSettings, OidcCallbackData, OidcProviderResponse, OidcProvidersListResponse, OidcProviderSummary, OidcProviderUserResponse, OidcRoleMappingResponse, OidcTestConnectionResponse, OnDemandCertAttemptResponse, OnDemandCertRow, OnDemandTlsSettings, OpenAiError, OpenAiErrorResponse, OperatingSystemCount, OperationResultResponse, OperationResultsResponse, OtelDashboardResponse, OtelDashboardsResponse, OtelMetricAlertRuleResponse, OtelMetricAlertsResponse, OtelMetricLabelKeysResponse, OtelMetricLabelValuesResponse, OtelMetricNamesResponse, OtelMetricsResponse, OutlierAlgorithm, OutlierParams, OverprovisioningAssessment, OverprovisioningVerdict, PageActivityBucket, PageCountryStats, PageFlowEntry, PageFlowQuery, PageFlowResponse, PageHourlySessionsQuery, PageHourlySessionsResponse, PagePathDetailQuery, PagePathDetailResponse, PagePathInfo, PagePathSparkline, PagePathSparklinePoint, PagePathsQuery, PagePathsResponse, PagePathsSparklineQuery, PagePathsSparklineResponse, PagePathVisitorsQuery, PagePathVisitorsResponse, PageReferrerStats, PagesComparisonResponse, PageSessionComparison, PageSessionStats, PageSessionStatsQuery, PageTransition, PageVisit, PageVisitorSession, PaginatedEmailsResponse, PaginatedEntitiesResponse, PaginatedErrorEventsResponse, PaginatedErrorGroupsResponse, PaginatedEventsResponse, PaginatedExternalImagesResponse, PaginatedProjectList, PaginatedStaticBundlesResponse, Pagination, PaginationMeta, PaginationParams, PasswordProtectionConfig, PatchAdminGateData, PatchAdminGateErrors, PatchAdminGateResponse, PatchAdminGateResponses, PatchPreviewGatewaySettingsData, PatchPreviewGatewaySettingsResponse, PatchPreviewGatewaySettingsResponses, PatchSettingsRequest, PathVisitors, PathVisitorsAnalyticsQuery, PathVisitorsResponse, PauseDeploymentData, PauseDeploymentErrors, PauseDeploymentResponse, PauseDeploymentResponses, PauseSandboxData, PauseSandboxErrors, PauseSandboxResponse, PauseSandboxResponses, PeerEntry, PeerListResponse, PendingActionResponse, PerformanceMetricsQuery, PerformanceMetricsResponse, PermissionInfo, PgUpgradeLogResponse, PgUpgradeResponse, PipelineStats, PipelineStatsResponse, PlanComplexity, PlanMetadata, PlanRestoreData, PlanRestoreError, PlanRestoreErrors, PlanRestoreResponse, PlanRestoreResponses, PlanSourceBackup, PlanTarget, PlatformInfo, PluginManifest, PortMapping, PostDnsAckData, PostDnsAckErrors, PostDnsAckResponse, PostDnsAckResponses, PostgresWalHealth, PresetConfigSchema, PresetInfo, PresetResponse, PreviewAlertData, PreviewAlertError, PreviewAlertErrors, PreviewAlertResponse, PreviewAlertResponses, PreviewFunnelMetricsData, PreviewFunnelMetricsErrors, PreviewFunnelMetricsResponse, PreviewFunnelMetricsResponses, PreviewGatewaySettings, PreviewGatewaySettingsMasked, PreviewGatewaySettingsResponse, PreviewHostnameModeData, PreviewHostnameModeErrors, PreviewHostnameModeResponse, PreviewHostnameModeResponses, PreviewShareLinkBody, PreviewShareLinkResponse, PricingResponse, ProblemDetails, ProjectAccessResponse, ProjectConfiguration, ProjectDashboardAnalytics, ProjectDsnResponse, ProjectHealthSummary, ProjectInfo, ProjectMonitorHealth, ProjectPresetResponse, ProjectQuery, ProjectRef, ProjectResponse, ProjectSecretEnvironmentInfo, ProjectSecretResponse, ProjectServiceInfo, ProjectsHealthResponse, ProjectsMonitorHealthResponse, ProjectStatisticsResponse, ProjectStatsBreakdown, ProjectType, ProjectUsageInfoResponse, PromoteClusterMemberData, PromoteClusterMemberErrors, PromoteClusterMemberResponses, PromoteDeploymentData, PromoteDeploymentErrors, PromoteDeploymentRequest, PromoteDeploymentResponse, PromoteDeploymentResponses, PropertyBreakdownItem, PropertyBreakdownQuery, PropertyBreakdownResponse, PropertyColumn, PropertyTimelineItem, PropertyTimelineQuery, PropertyTimelineResponse, Protocol, ProviderCatalogDto, ProviderCatalogResponse, ProviderConfig, ProviderConfigMasked, ProviderDeletionCheckResponse, ProviderDescriptor, ProviderKeyResponse, ProviderMetadata, ProviderResponse, ProviderUsage, ProvisionDomainData, ProvisionDomainErrors, ProvisionDomainResponse, ProvisionDomainResponses, ProvisionResponse, ProxyLogResponse, ProxyLogsPaginatedResponse, PublicHostnameStrategy, PublicPresetResponse, PublicRepositoryInfo, PurgeLogsRequest, PurgeProjectLogsData, PurgeProjectLogsError, PurgeProjectLogsErrors, PurgeProjectLogsResponses, PushedExternalImageResponse, PushExternalImageData, PushExternalImageErrors, PushExternalImageResponse, PushExternalImageResponses, PushImageRequest, QueryDataData, QueryDataErrors, QueryDataRequest, QueryDataResponse, QueryDataResponse2, QueryDataResponses, QueryGenaiTracesData, QueryGenaiTracesError, QueryGenaiTracesErrors, QueryGenaiTracesResponse, QueryGenaiTracesResponses, QueryLogsData, QueryLogsError, QueryLogsErrors, QueryLogsResponse, QueryLogsResponses, QueryMetricsData, QueryMetricsError, QueryMetricsErrors, QueryMetricsResponse, QueryMetricsResponses, QueryTracesData, QueryTracesError, QueryTracesErrors, QueryTracesResponse, QueryTracesResponses, QueryTraceSummariesData, QueryTraceSummariesError, QueryTraceSummariesErrors, QueryTraceSummariesResponse, QueryTraceSummariesResponses, QuotaResponse, RateLimitConfig, RateLimitSettings, ReachabilityStatus, ReadFileData, ReadFileErrors, ReadFileResponse, ReadFileResponse2, ReadFileResponses, ReAnalyzeData, ReAnalyzeErrors, ReAnalyzeResponses, RecentActivityQuery, RecentActivityResponse, RecentEventResponse, RecentQueryParams, RecordConsoleEventData, RecordConsoleEventErrors, RecordConsoleEventResponses, RecordEventMetricsData, RecordEventMetricsErrors, RecordEventMetricsResponse, RecordEventMetricsResponses, RecordExposureRequest, RecordExposureResponse, RecordFlagExposureData, RecordFlagExposureErrors, RecordFlagExposureResponse, RecordFlagExposureResponses, RecordListResponse, RecordSpeedMetricsData, RecordSpeedMetricsError, RecordSpeedMetricsErrors, RecordSpeedMetricsResponse, RecordSpeedMetricsResponses, RecoveryTarget, ReferrerCount, ReferrersAnalyticsQuery, RefreshRouteTableData, RefreshRouteTableErrors, RefreshRouteTableResponse, RefreshRouteTableResponses, RegenerateDsnData, RegenerateDsnErrors, RegenerateDsnRequest, RegenerateDsnResponse, RegenerateDsnResponses, RegisterExternalImageData, RegisterExternalImageErrors, RegisterExternalImageResponse, RegisterExternalImageResponses, RegisterImageRequest, RegisterNodeApiRequest, RegisterNodeData, RegisterNodeErrors, RegisterNodeResponse, RegisterNodeResponse2, RegisterNodeResponses, RegisterRequest, ReinstallGitlabWebhookData, ReinstallGitlabWebhookErrors, ReinstallGitlabWebhookResponse, ReinstallGitlabWebhookResponses, ReinstallWebhookResponse, RejectPendingActionData, RejectPendingActionErrors, RejectPendingActionResponse, RejectPendingActionResponses, ReleaseListResponse, ReloadPluginsData, ReloadPluginsErrors, ReloadPluginsResponse, ReloadPluginsResponses, ReloadResponse, RemoteDeploymentResponse, RemoveClusterMemberData, RemoveClusterMemberErrors, RemoveClusterMemberResponse, RemoveClusterMemberResponses, RemoveManagedDomainData, RemoveManagedDomainErrors, RemoveManagedDomainResponse, RemoveManagedDomainResponses, RemoveNodeResponse, RemoveRoleData, RemoveRoleErrors, RemoveRoleResponse, RemoveRoleResponses, RemoveTeamMemberData, RemoveTeamMemberErrors, RemoveTeamMemberResponse, RemoveTeamMemberResponses, RenameConversationData, RenameConversationErrors, RenameConversationRequest, RenameConversationResponse, RenameConversationResponses, RenewDomainData, RenewDomainErrors, RenewDomainResponse, RenewDomainResponses, RepositoryListQuery, RepositoryListResponse, RepositoryPresetResponse, RepositoryResponse, RepositorySyncStartedResponse, RequestPasswordResetData, RequestPasswordResetErrors, RequestPasswordResetResponse, RequestPasswordResetResponses, RequestRow, ResetPasswordData, ResetPasswordErrors, ResetPasswordRequest, ResetPasswordResponse, ResetPasswordResponses, ResetPgStatStatementsRequest, ResetPgStatStatementsResponse, ResizeSandboxBody, ResizeSandboxData, ResizeSandboxErrors, ResizeSandboxResponse, ResizeSandboxResponses, ResolveAlarmData, ResolveAlarmErrors, ResolveAlarmResponses, ResolvedEnvVarResponse, ResolvedEnvVarSource, ResourceCounts, ResourceFootprint, ResourceInfo, ResourceLimitApplyResult, ResourceLimits, ResourceLimitsResponse, ResourceLimitsUpdateResponse, ResourcesBody, RestartContainerData, RestartContainerErrors, RestartContainerResponse, RestartContainerResponses, RestartPreviewGatewayData, RestartPreviewGatewayResponse, RestartPreviewGatewayResponses, RestartSandboxData, RestartSandboxErrors, RestartSandboxResponse, RestartSandboxResponses, RestoreCapabilities, RestoreCapabilitiesResponse, RestoreFlagData, RestoreFlagErrors, RestoreFlagResponse, RestoreFlagResponses, RestorePlan, RestoreRequestMode, RestoreRunView, RestoreUserData, RestoreUserErrors, RestoreUserResponse, RestoreUserResponses, ResumeDeploymentData, ResumeDeploymentErrors, ResumeDeploymentResponse, ResumeDeploymentResponses, ResumeSandboxData, ResumeSandboxErrors, ResumeSandboxResponse, ResumeSandboxResponses, RetentionCleanupFailure, RetentionCleanupReport, RetryClusterData, RetryClusterErrors, RetryClusterRequest, RetryClusterResponse, RetryClusterResponses, RetryDeliveryData, RetryDeliveryErrors, RetryDeliveryResponse, RetryDeliveryResponses, RetryPgUpgradeData, RetryPgUpgradeErrors, RetryPgUpgradeResponse, RetryPgUpgradeResponses, RetryRunData, RetryRunErrors, RetryRunResponse, RetryRunResponses, RevealGlobalMcpConfigData, RevealGlobalMcpConfigErrors, RevealGlobalMcpConfigResponse, RevealGlobalMcpConfigResponses, RevealMcpConfigData, RevealMcpConfigErrors, RevealMcpConfigResponse, RevealMcpConfigResponses, RevealNotificationProviderConfigData, RevealNotificationProviderConfigErrors, RevealNotificationProviderConfigResponse, RevealNotificationProviderConfigResponses, RevealServiceParameterData, RevealServiceParameterErrors, RevealServiceParameterResponse, RevealServiceParameterResponses, RevenueCreateIntegrationData, RevenueCreateIntegrationErrors, RevenueCreateIntegrationResponse, RevenueCreateIntegrationResponses, RevenueDeleteIntegrationData, RevenueDeleteIntegrationResponse, RevenueDeleteIntegrationResponses, RevenueGlobalEventsData, RevenueGlobalEventsResponse, RevenueGlobalEventsResponses, RevenueImportInvoicesCsvData, RevenueImportInvoicesCsvErrors, RevenueImportInvoicesCsvResponse, RevenueImportInvoicesCsvResponses, RevenueImportSubscriptionsCsvData, RevenueImportSubscriptionsCsvErrors, RevenueImportSubscriptionsCsvResponse, RevenueImportSubscriptionsCsvResponses, RevenueListIntegrationsData, RevenueListIntegrationsResponse, RevenueListIntegrationsResponses, RevenueListProvidersData, RevenueListProvidersResponse, RevenueListProvidersResponses, RevenueMetricsCustomersData, RevenueMetricsCustomersResponse, RevenueMetricsCustomersResponses, RevenueMetricsGlobalMrrData, RevenueMetricsGlobalMrrResponse, RevenueMetricsGlobalMrrResponses, RevenueMetricsGlobalSummaryData, RevenueMetricsGlobalSummaryResponse, RevenueMetricsGlobalSummaryResponses, RevenueMetricsMrrData, RevenueMetricsMrrResponse, RevenueMetricsMrrResponses, RevenueMetricsSummaryData, RevenueMetricsSummaryResponse, RevenueMetricsSummaryResponses, RevenueRecentEventsData, RevenueRecentEventsResponse, RevenueRecentEventsResponses, RevenueRotateTokenData, RevenueRotateTokenResponse, RevenueRotateTokenResponses, RevenueRow, RevenueUpdateConfigData, RevenueUpdateConfigErrors, RevenueUpdateConfigResponse, RevenueUpdateConfigResponses, RevenueUpdateSecretData, RevenueUpdateSecretErrors, RevenueUpdateSecretResponse, RevenueUpdateSecretResponses, RevokeDsnData, RevokeDsnErrors, RevokeDsnResponse, RevokeDsnResponses, RevokeEnrollmentTokenData, RevokeEnrollmentTokenErrors, RevokeEnrollmentTokenResponse, RevokeEnrollmentTokenResponses, RevokeJoinTokenData, RevokeJoinTokenErrors, RevokeJoinTokenResponse, RevokeJoinTokenResponses, RevokeProjectAccessData, RevokeProjectAccessErrors, RevokeProjectAccessResponse, RevokeProjectAccessResponses, RiskLevel, RoleInfo, RollbackPgUpgradeData, RollbackPgUpgradeErrors, RollbackPgUpgradeResponse, RollbackPgUpgradeResponses, RollbackToDeploymentData, RollbackToDeploymentErrors, RollbackToDeploymentResponse, RollbackToDeploymentResponses, RootfsCacheEntry, RootfsGcData, RootfsGcReport, RootfsGcResponses, RootfsReport, RootfsReportData, RootfsReportResponses, RootfsVmEntry, RotateApiKeyData, RotateApiKeyErrors, RotateApiKeyResponse, RotateApiKeyResponses, RotateDeploymentTokenData, RotateDeploymentTokenErrors, RotateDeploymentTokenResponse, RotateDeploymentTokenResponses, RouteRefreshResponse, RouteResponse, RouteRole, RouteUser, RouteUserWithRoles, RunBackupForSourceData, RunBackupForSourceError, RunBackupForSourceErrors, RunBackupForSourceResponse, RunBackupForSourceResponses, RunBackupRequest, RunConnectionHealthCheckData, RunConnectionHealthCheckErrors, RunConnectionHealthCheckResponse, RunConnectionHealthCheckResponses, RunExternalServiceBackupData, RunExternalServiceBackupError, RunExternalServiceBackupErrors, RunExternalServiceBackupRequest, RunExternalServiceBackupResponse, RunExternalServiceBackupResponses, RunScheduleNowData, RunScheduleNowError, RunScheduleNowErrors, RunScheduleNowResponse, RunScheduleNowResponses, S3ConnectionTestResponse, S3CredentialsResponse, S3SourceResponse, S3SourceResponseWritable, SandboxCreatePreviewLinkData, SandboxCreatePreviewLinkErrors, SandboxCreatePreviewLinkResponse, SandboxCreatePreviewLinkResponses, SandboxDomainResponse, SandboxEvent, SandboxEventsResponse, SandboxInner, SandboxResponse, SandboxRoute, SandboxStatusResponse, SaveAgentTokenData, SaveAgentTokenErrors, SaveAgentTokenRequest, SaveAgentTokenResponse, SaveAgentTokenResponse2, SaveAgentTokenResponses, SaveAiProviderCredentialData, SaveAiProviderCredentialErrors, SaveAiProviderCredentialResponse, SaveAiProviderCredentialResponses, SaveCredentialRequest, SaveCredentialResponse, ScalewayCredentialsRequest, ScanResponse, ScheduleRunEntry, ScheduleRunJobEntry, ScheduleRunListResponse, ScheduleRunResponse, ScheduleRunSummary, ScheduleRunSummaryList, ScreenshotSettings, SearchLogsData, SearchLogsError, SearchLogsErrors, SearchLogsRequest, SearchLogsResponse, SearchLogsResponse2, SearchLogsResponses, SearchMode, Seasonality, SecretResponse, SecurityConfig, SecurityHeadersConfig, SecurityHeadersSettings, SendEmailData, SendEmailErrors, SendEmailRequestBody, SendEmailResponse, SendEmailResponseBody, SendEmailResponses, SendMessageRequest, SensitiveConfigValueResponse, SensitiveMcpConfigValueResponse, SensitiveValueResponse, SentryChunkUploadResponse, SentryCreateReleaseRequest, SentryEventRequest, SentryEventResponse, SentryReleaseFileResponse, SentryReleaseProjectRef, SentryReleaseResponse, SeriesStateEntry, ServiceAccessInfo, ServiceAction, ServiceAlertRuleResponse, ServiceBackupEntryResponse, ServiceBackupListResponse, ServiceCreateAlertRuleRequest, ServiceHealthResponse, ServiceHealthStatusBatchResponse, ServiceHealthStatusEntryResponse, ServiceMemberInfo, ServiceParameter, ServicePlan, ServiceResourceLimits, ServiceRuntimeReport, ServiceStatsReport, ServiceTypeInfo, ServiceTypeRoute, ServiceUpdateAlertRuleRequest, SesCredentialsRequest, SessionDetails, SessionDetailsQuery, SessionEvent, SessionEventDto, SessionEventsQuery, SessionEventsResponse, SessionLogsQuery, SessionLogsResponse, SessionReplayEventsRequest, SessionReplayInfoDto, SessionReplayInitRequest, SessionReplayInitResponse, SessionReplayWithEventsDto, SessionReplayWithVisitorDto, SessionRequestLog, SessionSummary, SetDefaultS3SourceData, SetDefaultS3SourceError, SetDefaultS3SourceErrors, SetDefaultS3SourceResponse, SetDefaultS3SourceResponses, SetFlagEnvironmentData, SetFlagEnvironmentErrors, SetFlagEnvironmentRequest, SetFlagEnvironmentResponse, SetFlagEnvironmentResponses, SetPreviewPasswordBody, SetPreviewPasswordData, SetPreviewPasswordErrors, SetPreviewPasswordResponse, SetPreviewPasswordResponse2, SetPreviewPasswordResponses, SetRequest, SetResponse, SettingsUpdateResponse, SetupDnsChallengeData, SetupDnsChallengeErrors, SetupDnsChallengeRequest, SetupDnsChallengeResponse, SetupDnsChallengeResponse2, SetupDnsChallengeResponses, SetupDnsData, SetupDnsErrors, SetupDnsRequest, SetupDnsResponse, SetupDnsResponse2, SetupDnsResponses, SetupEmailTrackingData, SetupEmailTrackingErrors, SetupEmailTrackingResponse, SetupEmailTrackingResponses, SetupMfaData, SetupMfaErrors, SetupMfaResponse, SetupMfaResponses, SiblingRef, SkillDefinitionResponse, SlackConfig, SleepEnvironmentData, SleepEnvironmentErrors, SleepEnvironmentResponse, SleepEnvironmentResponses, SlowQueriesResponse, SlowQueryRow, SmartFilter, SmokeTestAgentData, SmokeTestAgentErrors, SmokeTestAgentResponse, SmokeTestAgentResponses, SmokeTestResponse, SmtpCredentialsRequest, SmtpEncryptionRoute, SmtpResult, SourceArchiveUpload, SourceBackupEntry, SourceBackupIndexResponse, SourceBody, SourceFileListResponse, SourceFileResponse, SourceMapListResponse, SourceMapResponse, SourceSandboxData, SourceSandboxErrors, SourceSandboxResponse, SourceSandboxResponses, SourceType, SpanEvent, SpanKind, SpanRecord, SpanRow, SpanStatusCode, SpeedMetricsPayload, SpeedSegmentFilters, StaleSlot, StartAnalysisData, StartAnalysisErrors, StartAnalysisRequest, StartAnalysisResponse, StartAnalysisResponses, StartContainerData, StartContainerErrors, StartContainerResponse, StartContainerResponses, StartFixData, StartFixErrors, StartFixResponses, StartGitProviderOauthData, StartGitProviderOauthErrors, StartOidcLoginBySlugData, StartOidcLoginBySlugErrors, StartPgUpgradeData, StartPgUpgradeErrors, StartPgUpgradeRequest, StartPgUpgradeResponse, StartPgUpgradeResponses, StartRestoreData, StartRestoreError, StartRestoreErrors, StartRestoreRequest, StartRestoreResponse, StartRestoreResponses, StartServiceData, StartServiceErrors, StartServiceResponse, StartServiceResponses, StaticBundleResponse, StaticParams, StaticPresetConfig, StatPathData, StatPathErrors, StatPathResponse, StatPathResponses, StatResponse, StatsFilters, StatusBucket, StatusBucketedResponse, StatusCodeCount, StatusCodesQuery, StatusPageOverview, StepConversionResponse, StepResourceType, StepResult, StepUpResponse, StopContainerData, StopContainerErrors, StopContainerResponse, StopContainerResponses, StopSandboxData, StopSandboxErrors, StopSandboxResponse, StopSandboxResponses, StopSequence, StopServiceData, StopServiceErrors, StopServiceResponse, StopServiceResponses, StorageQuota, StreamContainerMetricsData, StreamContainerMetricsErrors, StreamContainerMetricsResponses, StreamEventsData, StreamEventsErrors, StreamEventsResponses, StreamRunEventsData, StreamRunEventsErrors, StreamRunEventsResponses, StripeConfig, SyncedRepositoryListQuery, SyncRepositoriesData, SyncRepositoriesErrors, SyncRepositoriesResponse, SyncRepositoriesResponses, SyntaxResult, TagInfo, TagListResponse, TailDeploymentJobLogsData, TailDeploymentJobLogsErrors, TailLogsData, TailLogsError, TailLogsErrors, TailLogsRequest, TailLogsResponses, TargetRecommendation, TeamListResponse, TeamMemberResponse, TeamResponse, TeamRole, TeardownDeploymentData, TeardownDeploymentErrors, TeardownDeploymentResponse, TeardownDeploymentResponses, TeardownEnvironmentData, TeardownEnvironmentErrors, TeardownEnvironmentResponse, TeardownEnvironmentResponses, TemplateResponse, TestEmailRequest, TestEmailResponse, TestNotificationProviderData, TestNotificationProviderErrors, TestNotificationProviderResponse, TestNotificationProviderResponses, TestOidcProviderData, TestOidcProviderResponse, TestOidcProviderResponses, TestProviderConnectionData, TestProviderConnectionErrors, TestProviderConnectionResponse, TestProviderConnectionResponses, TestProviderData, TestProviderErrors, TestProviderKeyByIdData, TestProviderKeyByIdError, TestProviderKeyByIdErrors, TestProviderKeyByIdResponse, TestProviderKeyByIdResponses, TestProviderKeyInlineData, TestProviderKeyInlineError, TestProviderKeyInlineErrors, TestProviderKeyInlineResponse, TestProviderKeyInlineResponses, TestProviderKeyRequest, TestProviderKeyResponse, TestProviderResponse, TestProviderResponse2, TestProviderResponses, TestS3ConnectionPreviewData, TestS3ConnectionPreviewError, TestS3ConnectionPreviewErrors, TestS3ConnectionPreviewResponse, TestS3ConnectionPreviewResponses, TestS3SourceConnectionData, TestS3SourceConnectionError, TestS3SourceConnectionErrors, TestS3SourceConnectionResponse, TestS3SourceConnectionResponses, TimeBucketStats, TimeBucketStatsResponse, TimeseriesBucket, TimeseriesQueryParams, TlsMode, TodayStatsResponse, ToggleDeploymentMetricsRequest, ToggleServiceMetricsRequest, TokenRenewalRequest, ToolCallEvent, ToolInfo, ToolResultEvent, TopModelsQueryParams, TraceProjectRef, TracesResponse, TraceSummariesResponse, TraceSummary, TrackClickData, TrackClickErrors, TrackedLinkResponse, TrackingEventResponse, TrackOpenData, TrackOpenErrors, TrackOpenResponses, TriggerAgentData, TriggerAgentErrors, TriggerAgentRequest, TriggerAgentResponse, TriggerAgentResponses, TriggerDigestResponse, TriggerPipelinePayload, TriggerPipelineResponse, TriggerProjectPipelineData, TriggerProjectPipelineErrors, TriggerProjectPipelineResponse, TriggerProjectPipelineResponses, TriggerScanData, TriggerScanError, TriggerScanErrors, TriggerScanRequest, TriggerScanResponse, TriggerScanResponse2, TriggerScanResponses, TriggerServiceHealthCheckData, TriggerServiceHealthCheckErrors, TriggerServiceHealthCheckResponse, TriggerServiceHealthCheckResponses, TriggerWeeklyDigestData, TriggerWeeklyDigestErrors, TriggerWeeklyDigestResponse, TriggerWeeklyDigestResponses, TtlRequest, TtlResponse, TxtRecord, UiManifest, UiRoute, UndrainNodeResponse, UnifiedTrace, UniqueCountsQuery, UniqueCountsResponse, UnlinkServiceFromProjectData, UnlinkServiceFromProjectErrors, UnlinkServiceFromProjectResponse, UnlinkServiceFromProjectResponses, UnsupportedFeature, UpdateAdminGateRequest, UpdateAgentData, UpdateAgentErrors, UpdateAgentResponse, UpdateAgentResponses, UpdateAiProviderData, UpdateAiProviderErrors, UpdateAiProviderRequest, UpdateAiProviderResponse, UpdateAiProviderResponse2, UpdateAiProviderResponses, UpdateAlertData, UpdateAlertError, UpdateAlertErrors, UpdateAlertResponse, UpdateAlertResponses, UpdateAlertRuleData, UpdateAlertRuleErrors, UpdateAlertRuleRequest, UpdateAlertRuleResponse, UpdateAlertRuleResponses, UpdateApiKeyData, UpdateApiKeyErrors, UpdateApiKeyRequest, UpdateApiKeyResponse, UpdateApiKeyResponses, UpdateAutomaticDeployData, UpdateAutomaticDeployErrors, UpdateAutomaticDeployRequest, UpdateAutomaticDeployResponse, UpdateAutomaticDeployResponses, UpdateBackupScheduleData, UpdateBackupScheduleError, UpdateBackupScheduleErrors, UpdateBackupScheduleRequest, UpdateBackupScheduleResponse, UpdateBackupScheduleResponses, UpdateBlobRequest, UpdateBlobResponse, UpdateCloudflareProviderData, UpdateCloudflareProviderErrors, UpdateCloudflareProviderRequest, UpdateCloudflareProviderResponse, UpdateCloudflareProviderResponses, UpdateConfigBody, UpdateConnectionTokenData, UpdateConnectionTokenErrors, UpdateConnectionTokenResponse, UpdateConnectionTokenResponses, UpdateCustomDomainData, UpdateCustomDomainErrors, UpdateCustomDomainRequest, UpdateCustomDomainResponse, UpdateCustomDomainResponses, UpdateDashboardData, UpdateDashboardError, UpdateDashboardErrors, UpdateDashboardRequest, UpdateDashboardResponse, UpdateDashboardResponses, UpdateDeploymentConfigRequest, UpdateDeploymentTokenData, UpdateDeploymentTokenErrors, UpdateDeploymentTokenRequest, UpdateDeploymentTokenResponse, UpdateDeploymentTokenResponses, UpdateDnsProviderRequest, UpdateEmailProviderData, UpdateEmailProviderErrors, UpdateEmailProviderRequest, UpdateEmailProviderResponse, UpdateEmailProviderResponses, UpdateEnvironmentSettingsData, UpdateEnvironmentSettingsErrors, UpdateEnvironmentSettingsRequest, UpdateEnvironmentSettingsResponse, UpdateEnvironmentSettingsResponses, UpdateEnvironmentSubdomainData, UpdateEnvironmentSubdomainErrors, UpdateEnvironmentSubdomainRequest, UpdateEnvironmentSubdomainResponse, UpdateEnvironmentSubdomainResponses, UpdateEnvironmentVariableData, UpdateEnvironmentVariableErrors, UpdateEnvironmentVariableRequest, UpdateEnvironmentVariableResponse, UpdateEnvironmentVariableResponses, UpdateErrorGroupData, UpdateErrorGroupErrors, UpdateErrorGroupRequest, UpdateErrorGroupResponses, UpdateExternalServiceRequest, UpdateFlagData, UpdateFlagErrors, UpdateFlagRequest, UpdateFlagResponse, UpdateFlagResponses, UpdateFunnelData, UpdateFunnelErrors, UpdateFunnelResponses, UpdateGitProviderCredentialsData, UpdateGitProviderCredentialsErrors, UpdateGitProviderCredentialsResponse, UpdateGitProviderCredentialsResponses, UpdateGitSettingsData, UpdateGitSettingsErrors, UpdateGitSettingsRequest, UpdateGitSettingsResponse, UpdateGitSettingsResponses, UpdateGlobalMcpData, UpdateGlobalMcpErrors, UpdateGlobalMcpResponse, UpdateGlobalMcpResponses, UpdateGlobalSkillData, UpdateGlobalSkillErrors, UpdateGlobalSkillResponse, UpdateGlobalSkillResponses, UpdateIncidentStatusData, UpdateIncidentStatusErrors, UpdateIncidentStatusRequest, UpdateIncidentStatusResponse, UpdateIncidentStatusResponses, UpdateIpAccessControlData, UpdateIpAccessControlError, UpdateIpAccessControlErrors, UpdateIpAccessControlRequest, UpdateIpAccessControlResponse, UpdateIpAccessControlResponses, UpdateKvRequest, UpdateKvResponse, UpdateManagedDomainApiRequest, UpdateManagedDomainData, UpdateManagedDomainErrors, UpdateManagedDomainResponse, UpdateManagedDomainResponses, UpdateMcpData, UpdateMcpErrors, UpdateMcpRequest, UpdateMcpResponse, UpdateMcpResponses, UpdateMemberRoleRequest, UpdateMetricAlertRequest, UpdateNotificationEmailProviderData, UpdateNotificationEmailProviderErrors, UpdateNotificationEmailProviderRequest, UpdateNotificationEmailProviderResponse, UpdateNotificationEmailProviderResponses, UpdateNotificationProviderData, UpdateNotificationProviderErrors, UpdateNotificationProviderResponse, UpdateNotificationProviderResponses, UpdateOidcProviderData, UpdateOidcProviderRequest, UpdateOidcProviderResponse, UpdateOidcProviderResponses, UpdatePreferencesData, UpdatePreferencesErrors, UpdatePreferencesRequest, UpdatePreferencesResponse, UpdatePreferencesResponses, UpdateProjectData, UpdateProjectDeploymentConfigData, UpdateProjectDeploymentConfigErrors, UpdateProjectDeploymentConfigResponse, UpdateProjectDeploymentConfigResponses, UpdateProjectErrors, UpdateProjectResponse, UpdateProjectResponses, UpdateProjectSecretData, UpdateProjectSecretErrors, UpdateProjectSecretRequest, UpdateProjectSecretResponse, UpdateProjectSecretResponses, UpdateProjectSettingsData, UpdateProjectSettingsErrors, UpdateProjectSettingsRequest, UpdateProjectSettingsResponse, UpdateProjectSettingsResponses, UpdateProviderCredentialsRequest, UpdateProviderData, UpdateProviderErrors, UpdateProviderKeyData, UpdateProviderKeyError, UpdateProviderKeyErrors, UpdateProviderKeyRequest, UpdateProviderKeyResponse, UpdateProviderKeyResponses, UpdateProviderRequest, UpdateProviderResponse, UpdateProviderResponses, UpdateRouteData, UpdateRouteErrors, UpdateRouteRequest, UpdateRouteResponse, UpdateRouteResponses, UpdateS3SourceData, UpdateS3SourceError, UpdateS3SourceErrors, UpdateS3SourceRequest, UpdateS3SourceResponse, UpdateS3SourceResponses, UpdateSecretBody, UpdateSelfData, UpdateSelfErrors, UpdateSelfRequest, UpdateSelfResponse, UpdateSelfResponses, UpdateServiceData, UpdateServiceErrors, UpdateServiceResourcesData, UpdateServiceResourcesErrors, UpdateServiceResourcesResponse, UpdateServiceResourcesResponses, UpdateServiceResponse, UpdateServiceResponses, UpdateSessionDurationData, UpdateSessionDurationError, UpdateSessionDurationErrors, UpdateSessionDurationRequest, UpdateSessionDurationResponse, UpdateSessionDurationResponse2, UpdateSessionDurationResponses, UpdateSettingsData, UpdateSettingsErrors, UpdateSettingsResponse, UpdateSettingsResponses, UpdateSkillData, UpdateSkillErrors, UpdateSkillRequest, UpdateSkillResponse, UpdateSkillResponses, UpdateSlackProviderData, UpdateSlackProviderErrors, UpdateSlackProviderRequest, UpdateSlackProviderResponse, UpdateSlackProviderResponses, UpdateSpeedMetricsData, UpdateSpeedMetricsError, UpdateSpeedMetricsErrors, UpdateSpeedMetricsPayload, UpdateSpeedMetricsResponse, UpdateSpeedMetricsResponses, UpdateStatusResponse, UpdateTeamData, UpdateTeamErrors, UpdateTeamMemberRoleData, UpdateTeamMemberRoleErrors, UpdateTeamMemberRoleResponse, UpdateTeamMemberRoleResponses, UpdateTeamRequest, UpdateTeamResponse, UpdateTeamResponses, UpdateTokenRequest, UpdateTokenResponse, UpdateUserData, UpdateUserErrors, UpdateUserRequest, UpdateUserResponse, UpdateUserResponses, UpdateWebhookData, UpdateWebhookErrors, UpdateWebhookProviderData, UpdateWebhookProviderErrors, UpdateWebhookProviderRequest, UpdateWebhookProviderResponse, UpdateWebhookProviderResponses, UpdateWebhookRequestBody, UpdateWebhookResponse, UpdateWebhookResponses, UpgradeExternalServiceRequest, UpgradePreviewGatewayData, UpgradePreviewGatewayResponse, UpgradePreviewGatewayResponses, UpgradeRequest, UpgradeServiceData, UpgradeServiceErrors, UpgradeServiceResponse, UpgradeServiceResponses, UploadGlobalSkillData, UploadGlobalSkillErrors, UploadGlobalSkillResponse, UploadGlobalSkillResponses, UploadReleaseFileData, UploadReleaseFileErrors, UploadReleaseFileResponse, UploadReleaseFileResponses, UploadSkillData, UploadSkillErrors, UploadSkillResponse, UploadSkillResponses, UploadSourceFileData, UploadSourceFileErrors, UploadSourceFileResponse, UploadSourceFileResponses, UploadSourceMapData, UploadSourceMapErrors, UploadSourceMapResponse, UploadSourceMapResponses, UploadStaticBundleData, UploadStaticBundleErrors, UploadStaticBundleResponse, UploadStaticBundleResponses, UpsertAgentRequest, UpsertSecretData, UpsertSecretErrors, UpsertSecretRequest, UpsertSecretResponse, UpsertSecretResponses, UptimeDataPoint, UptimeHistoryResponse, UsageFilter, UsageInfo, UsageLogEntry, UsageLogPage, UsageQueryParams, UsageSource, UsageSummary, UserResponse, ValidateConnectionData, ValidateConnectionErrors, ValidateConnectionResponse, ValidateConnectionResponses, ValidateEmailData, ValidateEmailErrors, ValidateEmailRequest, ValidateEmailResponse, ValidateEmailResponse2, ValidateEmailResponses, ValidationLevel, ValidationReport, ValidationResponse, ValidationResult, ValidationStatus, ValidationSummary, VerifyAndEnableMfaData, VerifyAndEnableMfaErrors, VerifyAndEnableMfaResponse, VerifyAndEnableMfaResponses, VerifyDomainData, VerifyDomainErrors, VerifyDomainResponse, VerifyDomainResponses, VerifyEmailData, VerifyEmailErrors, VerifyEmailResponse, VerifyEmailResponses, VerifyManagedDomainData, VerifyManagedDomainErrors, VerifyManagedDomainResponse, VerifyManagedDomainResponses, VerifyMfaChallengeData, VerifyMfaChallengeErrors, VerifyMfaChallengeResponse, VerifyMfaChallengeResponses, VerifyMfaRequest, VerifyStepUpData, VerifyStepUpErrors, VerifyStepUpRequest, VerifyStepUpResponse, VerifyStepUpResponses, ViewItem, ViewsOverTime, ViewsOverTimeQuery, VisitorDetails, VisitorFacets, VisitorFacetsQuery, VisitorFacetValue, VisitorInfo, VisitorJourneyQuery, VisitorJourneyResponse, VisitorLocationsQuery, VisitorRecord, VisitorSegmentFilters, VisitorSessionsQuery, VisitorSessionsResponse, VisitorsListQuery, VisitorsResponse, VisitorStats, VisitorWithGeolocation, VolumeMount, VolumeType, VulnerabilityResponse, WakeEnvironmentData, WakeEnvironmentErrors, WakeEnvironmentResponse, WakeEnvironmentResponses, WalWarning, WalWarningSeverity, WebhookConfig, WebhookDeliveryResponse, WebhookResponse, WebhookTriggerData, WebhookTriggerErrors, WebhookTriggerRequest, WebhookTriggerResponse, WebhookTriggerResponse2, WebhookTriggerResponses, WorkflowDryRunData, WorkflowDryRunErrors, WorkflowDryRunRequest, WorkflowDryRunResponse, WorkflowDryRunResponses, WorkloadDescriptor, WorkloadId, WorkloadStatus, WorkloadType, WriteFileBody, WriteFileData, WriteFileErrors, WriteFileResponse, WriteFileResponses, WriteFilesBody, WriteFilesData, WriteFilesErrors, WriteFilesResponse, WriteFilesResponse2, WriteFilesResponses, ZoneListResponse } from './types.gen'; diff --git a/web/src/api/client/sdk.gen.ts b/web/src/api/client/sdk.gen.ts index c075a1e2e..7f564a1c2 100644 --- a/web/src/api/client/sdk.gen.ts +++ b/web/src/api/client/sdk.gen.ts @@ -2,7 +2,7 @@ import { type Client, type ClientMeta, formDataBodySerializer, type Options as Options2, type RequestResult, type ServerSentEventsResult, type TDataShape } from './client'; import { client } from './client.gen'; -import type { AcknowledgeAlarmData, AcknowledgeAlarmErrors, AcknowledgeAlarmResponses, ActivateAiProviderData, ActivateAiProviderErrors, ActivateAiProviderResponses, ActivateApiKeyData, ActivateApiKeyErrors, ActivateApiKeyResponses, ActivateConnectionData, ActivateConnectionErrors, ActivateConnectionResponses, ActivateProviderData, ActivateProviderErrors, ActivateProviderResponses, AddClusterMemberData, AddClusterMemberErrors, AddClusterMemberResponses, AddContextData, AddContextErrors, AddContextResponses, AddEnvironmentDomainData, AddEnvironmentDomainErrors, AddEnvironmentDomainResponses, AddEventsData, AddEventsErrors, AddEventsResponses, AddManagedDomainData, AddManagedDomainErrors, AddManagedDomainResponses, AddSessionReplayEventsData, AddSessionReplayEventsErrors, AddSessionReplayEventsResponses, AddTeamMemberData, AddTeamMemberErrors, AddTeamMemberResponses, AdminDrainNodeData, AdminDrainNodeErrors, AdminDrainNodeResponses, AdminDrainStatusData, AdminDrainStatusErrors, AdminDrainStatusResponses, AdminGetNodeData, AdminGetNodeErrors, AdminGetNodeResponses, AdminListNodeContainersData, AdminListNodeContainersErrors, AdminListNodeContainersResponses, AdminListNodesData, AdminListNodesErrors, AdminListNodesResponses, AdminRemoveNodeData, AdminRemoveNodeErrors, AdminRemoveNodeResponses, AdminUndrainNodeData, AdminUndrainNodeErrors, AdminUndrainNodeResponses, ApplyHostnameModeData, ApplyHostnameModeErrors, ApplyHostnameModeResponses, ArchiveConversationData, ArchiveConversationErrors, ArchiveConversationResponses, ArchiveFlagData, ArchiveFlagErrors, ArchiveFlagResponses, AssignRoleData, AssignRoleErrors, AssignRoleResponses, AttachScheduleServicesData, AttachScheduleServicesErrors, AttachScheduleServicesResponses, BlobCopyData, BlobCopyErrors, BlobCopyResponses, BlobDeleteData, BlobDeleteErrors, BlobDeleteResponses, BlobDisableData, BlobDisableErrors, BlobDisableResponses, BlobDownloadData, BlobDownloadErrors, BlobDownloadResponses, BlobEnableData, BlobEnableErrors, BlobEnableResponses, BlobHeadData, BlobHeadErrors, BlobHeadResponses, BlobListData, BlobListErrors, BlobListResponses, BlobPutData, BlobPutErrors, BlobPutResponses, BlobStatusData, BlobStatusErrors, BlobStatusResponses, BlobUpdateData, BlobUpdateErrors, BlobUpdateResponses, CancelBackupData, CancelBackupErrors, CancelBackupResponses, CancelData, CancelDeploymentData, CancelDeploymentErrors, CancelDeploymentResponses, CancelDomainOrderData, CancelDomainOrderErrors, CancelDomainOrderResponses, CancelErrors, CancelPgUpgradeData, CancelPgUpgradeErrors, CancelPgUpgradeResponses, CancelResponses, CancelRunData, CancelRunErrors, CancelRunResponses, CancelScheduleRunData, CancelScheduleRunErrors, CancelScheduleRunResponses, ChangePasswordSelfData, ChangePasswordSelfErrors, ChangePasswordSelfResponses, ChangeProjectSourceData, ChangeProjectSourceErrors, ChangeProjectSourceResponses, ChatCompletionsData, ChatCompletionsErrors, ChatCompletionsResponses, CheckAnalyticsHasEventsData, CheckAnalyticsHasEventsErrors, CheckAnalyticsHasEventsResponses, CheckCommitExistsData, CheckCommitExistsErrors, CheckCommitExistsResponses, CheckDomainStatusData, CheckDomainStatusErrors, CheckDomainStatusResponses, CheckExplorerSupportData, CheckExplorerSupportErrors, CheckExplorerSupportResponses, CheckIpBlockedData, CheckIpBlockedErrors, CheckIpBlockedResponses, CheckProviderDeletionSafetyData, CheckProviderDeletionSafetyErrors, CheckProviderDeletionSafetyResponses, ChunkUploadOptionsData, ChunkUploadOptionsResponses, CleanupExpiredBackupsData, CleanupExpiredBackupsErrors, CleanupExpiredBackupsResponses, ClearPreviewPasswordData, ClearPreviewPasswordErrors, ClearPreviewPasswordResponses, CliDeviceApproveData, CliDeviceApproveErrors, CliDeviceApproveResponses, CliDeviceDenyData, CliDeviceDenyErrors, CliDeviceDenyResponses, CliDeviceLookupData, CliDeviceLookupErrors, CliDeviceLookupResponses, CliDevicePollData, CliDevicePollErrors, CliDevicePollResponses, CliDeviceStartData, CliDeviceStartErrors, CliDeviceStartResponses, CliLogoutData, CliLogoutErrors, CliLogoutResponses, CmdData, CmdErrors, CmdKillData, CmdKillErrors, CmdKillResponses, CmdLogsData, CmdLogsErrors, CmdLogsResponses, CmdResponses, ConfirmPendingActionData, ConfirmPendingActionErrors, ConfirmPendingActionResponses, ContainerMetricsGetHistoryData, ContainerMetricsGetHistoryErrors, ContainerMetricsGetHistoryResponses, CreateAgentData, CreateAgentErrors, CreateAgentResponses, CreateAlertData, CreateAlertErrors, CreateAlertResponses, CreateAlertRuleData, CreateAlertRuleErrors, CreateAlertRuleResponses, CreateApiKeyData, CreateApiKeyErrors, CreateApiKeyResponses, CreateBackupScheduleData, CreateBackupScheduleErrors, CreateBackupScheduleResponses, CreateBitbucketProviderData, CreateBitbucketProviderErrors, CreateBitbucketProviderResponses, CreateCloudflareProviderData, CreateCloudflareProviderErrors, CreateCloudflareProviderResponses, CreateConversationData, CreateConversationErrors, CreateConversationResponses, CreateCustomDomainData, CreateCustomDomainErrors, CreateCustomDomainResponses, CreateDashboardData, CreateDashboardErrors, CreateDashboardResponses, CreateDeploymentTokenData, CreateDeploymentTokenErrors, CreateDeploymentTokenResponses, CreateDnsProviderData, CreateDnsProviderErrors, CreateDnsProviderResponses, CreateDomainData, CreateDomainErrors, CreateDomainResponses, CreateDsnData, CreateDsnErrors, CreateDsnResponses, CreateEmailDomainData, CreateEmailDomainErrors, CreateEmailDomainResponses, CreateEmailProviderData, CreateEmailProviderErrors, CreateEmailProviderResponses, CreateEnvironmentData, CreateEnvironmentErrors, CreateEnvironmentResponses, CreateEnvironmentVariableData, CreateEnvironmentVariableErrors, CreateEnvironmentVariableResponses, CreateFlagData, CreateFlagErrors, CreateFlagResponses, CreateFunnelData, CreateFunnelErrors, CreateFunnelResponses, CreateGenericProviderData, CreateGenericProviderErrors, CreateGenericProviderResponses, CreateGiteaPatProviderData, CreateGiteaPatProviderErrors, CreateGiteaPatProviderResponses, CreateGithubPatProviderData, CreateGithubPatProviderErrors, CreateGithubPatProviderResponses, CreateGitlabOauthProviderData, CreateGitlabOauthProviderErrors, CreateGitlabOauthProviderResponses, CreateGitlabPatProviderData, CreateGitlabPatProviderErrors, CreateGitlabPatProviderResponses, CreateGitProviderData, CreateGitProviderErrors, CreateGitProviderResponses, CreateGlobalMcpData, CreateGlobalMcpErrors, CreateGlobalMcpResponses, CreateGlobalSkillData, CreateGlobalSkillErrors, CreateGlobalSkillResponses, CreateIncidentData, CreateIncidentErrors, CreateIncidentResponses, CreateIpAccessControlData, CreateIpAccessControlErrors, CreateIpAccessControlResponses, CreateMcpData, CreateMcpErrors, CreateMcpResponses, CreateMonitorData, CreateMonitorErrors, CreateMonitorResponses, CreateNotificationEmailProviderData, CreateNotificationEmailProviderErrors, CreateNotificationEmailProviderResponses, CreateNotificationProviderData, CreateNotificationProviderErrors, CreateNotificationProviderResponses, CreateOidcProviderData, CreateOidcProviderErrors, CreateOidcProviderResponses, CreateOidcRoleMappingData, CreateOidcRoleMappingResponses, CreateOrRecreateOrderData, CreateOrRecreateOrderErrors, CreateOrRecreateOrderResponses, CreatePlanData, CreatePlanErrors, CreatePlanResponses, CreatePrData, CreatePrErrors, CreateProjectData, CreateProjectErrors, CreateProjectFromTemplateData, CreateProjectFromTemplateErrors, CreateProjectFromTemplateResponses, CreateProjectReleaseData, CreateProjectReleaseErrors, CreateProjectReleaseResponses, CreateProjectResponses, CreateProjectSecretData, CreateProjectSecretErrors, CreateProjectSecretResponses, CreateProviderKeyData, CreateProviderKeyErrors, CreateProviderKeyResponses, CreatePrResponses, CreateReleaseData, CreateReleaseErrors, CreateReleaseResponses, CreateRouteData, CreateRouteErrors, CreateRouteResponses, CreateS3SourceData, CreateS3SourceErrors, CreateS3SourceResponses, CreateSandboxData, CreateSandboxErrors, CreateSandboxResponses, CreateServiceData, CreateServiceErrors, CreateServiceResponses, CreateSkillData, CreateSkillErrors, CreateSkillResponses, CreateSlackProviderData, CreateSlackProviderErrors, CreateSlackProviderResponses, CreateTeamData, CreateTeamErrors, CreateTeamResponses, CreateUserData, CreateUserErrors, CreateUserResponses, CreateWebhookData, CreateWebhookErrors, CreateWebhookProviderData, CreateWebhookProviderErrors, CreateWebhookProviderResponses, CreateWebhookResponses, DeactivateApiKeyData, DeactivateApiKeyErrors, DeactivateApiKeyResponses, DeactivateConnectionData, DeactivateConnectionErrors, DeactivateConnectionResponses, DeactivateProviderData, DeactivateProviderErrors, DeactivateProviderResponses, DeleteAgentData, DeleteAgentErrors, DeleteAgentResponses, DeleteAlertData, DeleteAlertErrors, DeleteAlertResponses, DeleteAlertRuleData, DeleteAlertRuleErrors, DeleteAlertRuleResponses, DeleteApiKeyData, DeleteApiKeyErrors, DeleteApiKeyResponses, DeleteBackupData, DeleteBackupErrors, DeleteBackupResponses, DeleteBackupScheduleData, DeleteBackupScheduleErrors, DeleteBackupScheduleResponses, DeleteConnectionData, DeleteConnectionErrors, DeleteConnectionResponses, DeleteCustomDomainData, DeleteCustomDomainErrors, DeleteCustomDomainResponses, DeleteDashboardData, DeleteDashboardErrors, DeleteDashboardResponses, DeleteDeploymentTokenData, DeleteDeploymentTokenErrors, DeleteDeploymentTokenResponses, DeleteDnsProviderData, DeleteDnsProviderErrors, DeleteDnsProviderResponses, DeleteDomainData, DeleteDomainErrors, DeleteDomainResponses, DeleteEmailDomainData, DeleteEmailDomainErrors, DeleteEmailDomainResponses, DeleteEmailProviderData, DeleteEmailProviderErrors, DeleteEmailProviderResponses, DeleteEnvironmentData, DeleteEnvironmentDomainData, DeleteEnvironmentDomainErrors, DeleteEnvironmentDomainResponses, DeleteEnvironmentErrors, DeleteEnvironmentResponses, DeleteEnvironmentVariableData, DeleteEnvironmentVariableErrors, DeleteEnvironmentVariableResponses, DeleteExternalImageData, DeleteExternalImageErrors, DeleteExternalImageResponses, DeleteFunnelData, DeleteFunnelErrors, DeleteFunnelResponses, DeleteGitProviderData, DeleteGitProviderErrors, DeleteGitProviderResponses, DeleteGlobalMcpData, DeleteGlobalMcpErrors, DeleteGlobalMcpResponses, DeleteGlobalSkillData, DeleteGlobalSkillErrors, DeleteGlobalSkillResponses, DeleteIpAccessControlData, DeleteIpAccessControlErrors, DeleteIpAccessControlResponses, DeleteMcpData, DeleteMcpErrors, DeleteMcpResponses, DeleteMonitorData, DeleteMonitorErrors, DeleteMonitorResponses, DeleteNotificationProviderData, DeleteNotificationProviderErrors, DeleteNotificationProviderResponses, DeleteOidcProviderData, DeleteOidcProviderResponses, DeleteOidcRoleMappingData, DeleteOidcRoleMappingResponses, DeletePreferencesData, DeletePreferencesErrors, DeletePreferencesResponses, DeleteProjectData, DeleteProjectErrors, DeleteProjectResponses, DeleteProjectSecretData, DeleteProjectSecretErrors, DeleteProjectSecretResponses, DeleteProviderKeyData, DeleteProviderKeyErrors, DeleteProviderKeyResponses, DeleteProviderSafelyData, DeleteProviderSafelyErrors, DeleteProviderSafelyResponses, DeleteReleaseSourceFilesData, DeleteReleaseSourceFilesErrors, DeleteReleaseSourceFilesResponses, DeleteReleaseSourceMapsData, DeleteReleaseSourceMapsErrors, DeleteReleaseSourceMapsResponses, DeleteRouteData, DeleteRouteErrors, DeleteRouteResponses, DeleteS3SourceData, DeleteS3SourceErrors, DeleteS3SourceResponses, DeleteScanData, DeleteScanErrors, DeleteScanResponses, DeleteSecretData, DeleteSecretErrors, DeleteSecretResponses, DeleteServiceData, DeleteServiceErrors, DeleteServiceResponses, DeleteSessionReplayData, DeleteSessionReplayErrors, DeleteSessionReplayResponses, DeleteSkillData, DeleteSkillErrors, DeleteSkillResponses, DeleteSourceMapData, DeleteSourceMapErrors, DeleteSourceMapResponses, DeleteStaticBundleData, DeleteStaticBundleErrors, DeleteStaticBundleResponses, DeleteTeamData, DeleteTeamErrors, DeleteTeamResponses, DeleteUserData, DeleteUserErrors, DeleteUserResponses, DeleteWebhookData, DeleteWebhookErrors, DeleteWebhookResponses, DeployFromImageData, DeployFromImageErrors, DeployFromImageResponses, DeployFromImageUploadData, DeployFromImageUploadErrors, DeployFromImageUploadResponses, DeployFromStaticData, DeployFromStaticErrors, DeployFromStaticResponses, DeployFromUploadedSourceData, DeployFromUploadedSourceErrors, DeployFromUploadedSourceResponses, DeploymentMetricsGetLatestData, DeploymentMetricsGetLatestErrors, DeploymentMetricsGetLatestResponses, DeploymentMetricsGetRangeData, DeploymentMetricsGetRangeErrors, DeploymentMetricsGetRangeResponses, DeploymentMetricsToggleData, DeploymentMetricsToggleErrors, DeploymentMetricsToggleResponses, DestroySandboxData, DestroySandboxErrors, DestroySandboxResponses, DetachScheduleServiceData, DetachScheduleServiceErrors, DetachScheduleServiceResponses, DetectPublicPresetsData, DetectPublicPresetsErrors, DetectPublicPresetsResponses, DisableBackupScheduleData, DisableBackupScheduleErrors, DisableBackupScheduleResponses, DisableMfaData, DisableMfaErrors, DisableMfaResponses, DiscoverWorkloadsData, DiscoverWorkloadsErrors, DiscoverWorkloadsResponses, DomainData, DomainErrors, DomainResponses, DownloadGlobalSkillArchiveData, DownloadGlobalSkillArchiveErrors, DownloadGlobalSkillArchiveResponses, DownloadObjectData, DownloadObjectErrors, DownloadObjectResponses, DownloadSkillArchiveData, DownloadSkillArchiveErrors, DownloadSkillArchiveResponses, EmailStatusData, EmailStatusErrors, EmailStatusResponses, EmbeddingsData, EmbeddingsErrors, EmbeddingsResponses, EnableBackupScheduleData, EnableBackupScheduleErrors, EnableBackupScheduleResponses, EnrichVisitorData, EnrichVisitorErrors, EnrichVisitorResponses, ExecData, ExecDetachedData, ExecDetachedErrors, ExecDetachedResponses, ExecErrors, ExecResponses, ExecuteDeploymentOperationData, ExecuteDeploymentOperationErrors, ExecuteDeploymentOperationResponses, ExecuteImportData, ExecuteImportErrors, ExecuteImportResponses, ExtendTimeoutData, ExtendTimeoutErrors, ExtendTimeoutResponses, ExternalServiceEnablePgStatStatementsData, ExternalServiceEnablePgStatStatementsErrors, ExternalServiceEnablePgStatStatementsResponses, ExternalServiceMetricsByDatabaseData, ExternalServiceMetricsByDatabaseErrors, ExternalServiceMetricsByDatabaseResponses, ExternalServiceMetricsCreateAlertRuleData, ExternalServiceMetricsCreateAlertRuleErrors, ExternalServiceMetricsCreateAlertRuleResponses, ExternalServiceMetricsDeleteAlertRuleData, ExternalServiceMetricsDeleteAlertRuleErrors, ExternalServiceMetricsDeleteAlertRuleResponses, ExternalServiceMetricsGetAlertRulesData, ExternalServiceMetricsGetAlertRulesErrors, ExternalServiceMetricsGetAlertRulesResponses, ExternalServiceMetricsGetLatestData, ExternalServiceMetricsGetLatestErrors, ExternalServiceMetricsGetLatestResponses, ExternalServiceMetricsGetRangeData, ExternalServiceMetricsGetRangeErrors, ExternalServiceMetricsGetRangeResponses, ExternalServiceMetricsStatusData, ExternalServiceMetricsStatusErrors, ExternalServiceMetricsStatusResponses, ExternalServiceMetricsToggleData, ExternalServiceMetricsToggleErrors, ExternalServiceMetricsToggleResponses, ExternalServiceMetricsUpdateAlertRuleData, ExternalServiceMetricsUpdateAlertRuleErrors, ExternalServiceMetricsUpdateAlertRuleResponses, ExternalServiceResetPgStatStatementsData, ExternalServiceResetPgStatStatementsErrors, ExternalServiceResetPgStatStatementsResponses, FinalizeOrderData, FinalizeOrderErrors, FinalizeOrderResponses, FinalizeProjectReleaseData, FinalizeProjectReleaseErrors, FinalizeProjectReleaseResponses, FindConversationData, FindConversationErrors, FindConversationResponses, GenerateJoinTokenData, GenerateJoinTokenErrors, GenerateJoinTokenResponses, GeneratePresetDockerfileData, GeneratePresetDockerfileErrors, GeneratePresetDockerfileResponses, GetAccessInfoData, GetAccessInfoErrors, GetAccessInfoResponses, GetActiveVisitorsData, GetActiveVisitorsErrors, GetActiveVisitorsResponses, GetActivityGraphData, GetActivityGraphErrors, GetActivityGraphResponses, GetAdminGateData, GetAdminGateErrors, GetAdminGateResponses, GetAgentData, GetAgentErrors, GetAgentResponses, GetAggregatedBucketsData, GetAggregatedBucketsErrors, GetAggregatedBucketsResponses, GetAiAgentBreakdownData, GetAiAgentBreakdownErrors, GetAiAgentBreakdownResponses, GetAiAgentPagesData, GetAiAgentPagesErrors, GetAiAgentPagesResponses, GetAiAgentTimelineData, GetAiAgentTimelineErrors, GetAiAgentTimelineResponses, GetAiPageBreakdownData, GetAiPageBreakdownErrors, GetAiPageBreakdownResponses, GetAiStatusBreakdownData, GetAiStatusBreakdownErrors, GetAiStatusBreakdownResponses, GetAlertData, GetAlertErrors, GetAlertResponses, GetAlertRuleData, GetAlertRuleErrors, GetAlertRuleResponses, GetAllRepositoriesByNameData, GetAllRepositoriesByNameErrors, GetAllRepositoriesByNameResponses, GetAnalyticsActiveVisitorsData, GetAnalyticsActiveVisitorsErrors, GetAnalyticsActiveVisitorsResponses, GetAnalyticsEventsCountData, GetAnalyticsEventsCountErrors, GetAnalyticsEventsCountResponses, GetAnalyticsSessionEventsData, GetAnalyticsSessionEventsErrors, GetAnalyticsSessionEventsResponses, GetAnalyticsVisitorSessionsData, GetAnalyticsVisitorSessionsErrors, GetAnalyticsVisitorSessionsResponses, GetApiKeyData, GetApiKeyErrors, GetApiKeyPermissionsData, GetApiKeyPermissionsErrors, GetApiKeyPermissionsResponses, GetApiKeyResponses, GetAuditLogData, GetAuditLogErrors, GetAuditLogResponses, GetBackupData, GetBackupErrors, GetBackupResponses, GetBackupScheduleData, GetBackupScheduleErrors, GetBackupScheduleResponses, GetBranchesByRepositoryIdData, GetBranchesByRepositoryIdErrors, GetBranchesByRepositoryIdResponses, GetBucketedIncidentsData, GetBucketedIncidentsErrors, GetBucketedIncidentsResponses, GetBucketedStatusData, GetBucketedStatusErrors, GetBucketedStatusResponses, GetChallengeTokenData, GetChallengeTokenErrors, GetChallengeTokenResponses, GetChatReadinessData, GetChatReadinessErrors, GetChatReadinessResponses, GetCliStatusData, GetCliStatusErrors, GetCliStatusResponses, GetClusterHealthData, GetClusterHealthErrors, GetClusterHealthResponses, GetClusterMemberData, GetClusterMemberErrors, GetClusterMemberResponses, GetCmdData, GetCmdErrors, GetCmdResponses, GetContainerDetailData, GetContainerDetailErrors, GetContainerDetailResponses, GetContainerEnvironmentVariableData, GetContainerEnvironmentVariableErrors, GetContainerEnvironmentVariableResponses, GetContainerInfoData, GetContainerInfoErrors, GetContainerInfoResponses, GetContainerLogsByIdData, GetContainerLogsByIdErrors, GetContainerLogsData, GetContainerLogsErrors, GetContainerMetricsData, GetContainerMetricsErrors, GetContainerMetricsResponses, GetConversationData, GetConversationDetailData, GetConversationDetailErrors, GetConversationDetailResponses, GetConversationErrors, GetConversationResponses, GetConversationsData, GetConversationsErrors, GetConversationsResponses, GetCronByIdData, GetCronByIdErrors, GetCronByIdResponses, GetCronExecutionsData, GetCronExecutionsErrors, GetCronExecutionsResponses, GetCrossProjectTraceSiblingsData, GetCrossProjectTraceSiblingsErrors, GetCrossProjectTraceSiblingsResponses, GetCurrentMonitorStatusData, GetCurrentMonitorStatusErrors, GetCurrentMonitorStatusResponses, GetCurrentUserData, GetCurrentUserErrors, GetCurrentUserResponses, GetCustomDomainData, GetCustomDomainErrors, GetCustomDomainResponses, GetDashboardData, GetDashboardErrors, GetDashboardProjectsAnalyticsData, GetDashboardProjectsAnalyticsErrors, GetDashboardProjectsAnalyticsResponses, GetDashboardResponses, GetDeliveryData, GetDeliveryErrors, GetDeliveryResponses, GetDeploymentContainerLogContentData, GetDeploymentContainerLogContentErrors, GetDeploymentContainerLogContentResponses, GetDeploymentData, GetDeploymentErrors, GetDeploymentJobLogsData, GetDeploymentJobLogsErrors, GetDeploymentJobLogsResponses, GetDeploymentJobsData, GetDeploymentJobsErrors, GetDeploymentJobsResponses, GetDeploymentOperationsData, GetDeploymentOperationsErrors, GetDeploymentOperationsResponses, GetDeploymentOperationStatusData, GetDeploymentOperationStatusErrors, GetDeploymentOperationStatusResponses, GetDeploymentResponses, GetDeploymentTokenData, GetDeploymentTokenErrors, GetDeploymentTokenResponses, GetDiskStatusData, GetDiskStatusErrors, GetDiskStatusResponses, GetDnsChangesData, GetDnsChangesErrors, GetDnsChangesResponses, GetDnsProviderData, GetDnsProviderErrors, GetDnsProviderResponses, GetDomainByHostData, GetDomainByHostErrors, GetDomainByHostResponses, GetDomainByIdData, GetDomainByIdErrors, GetDomainByIdResponses, GetDomainByNameData, GetDomainByNameErrors, GetDomainByNameResponses, GetDomainData, GetDomainDnsRecordsData, GetDomainDnsRecordsErrors, GetDomainDnsRecordsResponses, GetDomainErrors, GetDomainOrderData, GetDomainOrderErrors, GetDomainOrderResponses, GetDomainResponses, GetEmailData, GetEmailErrors, GetEmailEventsData, GetEmailEventsErrors, GetEmailEventsResponses, GetEmailLinksData, GetEmailLinksErrors, GetEmailLinksResponses, GetEmailProviderData, GetEmailProviderErrors, GetEmailProviderResponses, GetEmailResponses, GetEmailStatsData, GetEmailStatsErrors, GetEmailStatsResponses, GetEmailTrackingData, GetEmailTrackingErrors, GetEmailTrackingResponses, GetEmailTrackingStatusData, GetEmailTrackingStatusErrors, GetEmailTrackingStatusResponses, GetEntityInfoData, GetEntityInfoErrors, GetEntityInfoResponses, GetEnvironmentCronsData, GetEnvironmentCronsErrors, GetEnvironmentCronsResponses, GetEnvironmentData, GetEnvironmentDomainsData, GetEnvironmentDomainsErrors, GetEnvironmentDomainsResponses, GetEnvironmentErrors, GetEnvironmentResponses, GetEnvironmentsData, GetEnvironmentsErrors, GetEnvironmentsResponses, GetEnvironmentVariablesData, GetEnvironmentVariablesErrors, GetEnvironmentVariablesResponses, GetEnvironmentVariableValueData, GetEnvironmentVariableValueErrors, GetEnvironmentVariableValueResponses, GetErrorDashboardStatsData, GetErrorDashboardStatsErrors, GetErrorDashboardStatsResponses, GetErrorEventData, GetErrorEventErrors, GetErrorEventResponses, GetErrorGroupData, GetErrorGroupErrors, GetErrorGroupResponses, GetErrorStatsData, GetErrorStatsErrors, GetErrorStatsResponses, GetErrorTimeSeriesData, GetErrorTimeSeriesErrors, GetErrorTimeSeriesResponses, GetEventDetailData, GetEventDetailErrors, GetEventDetailResponses, GetEventEntriesData, GetEventEntriesErrors, GetEventEntriesResponses, GetEventsCountData, GetEventsCountErrors, GetEventsCountResponses, GetEventsTimelineData, GetEventsTimelineErrors, GetEventsTimelineResponses, GetEventTypeBreakdownData, GetEventTypeBreakdownErrors, GetEventTypeBreakdownResponses, GetEventVisitorsData, GetEventVisitorsErrors, GetEventVisitorsResponses, GetExternalImageData, GetExternalImageErrors, GetExternalImageResponses, GetFileData, GetFileErrors, GetFileResponses, GetFlagData, GetFlagErrors, GetFlagResponses, GetFlagSnapshotData, GetFlagSnapshotErrors, GetFlagSnapshotResponses, GetFunnelMetricsData, GetFunnelMetricsErrors, GetFunnelMetricsResponses, GetGenaiTraceData, GetGenaiTraceErrors, GetGenaiTraceResponses, GetGeneralStatsData, GetGeneralStatsErrors, GetGeneralStatsResponses, GetGitProviderData, GetGitProviderErrors, GetGitProviderResponses, GetGlobalEventsData, GetGlobalEventsErrors, GetGlobalEventsResponses, GetGlobalEventStatsData, GetGlobalEventStatsErrors, GetGlobalEventStatsResponses, GetGlobalMcpData, GetGlobalMcpErrors, GetGlobalMcpResponses, GetGlobalSandboxStatusData, GetGlobalSandboxStatusErrors, GetGlobalSandboxStatusResponses, GetGlobalSkillData, GetGlobalSkillErrors, GetGlobalSkillResponses, GetGroupedPageMetricsData, GetGroupedPageMetricsErrors, GetGroupedPageMetricsResponses, GetHealthData, GetHealthErrors, GetHealthResponses, GetHourlyVisitsData, GetHourlyVisitsErrors, GetHourlyVisitsResponses, GetHttpChallengeDebugData, GetHttpChallengeDebugErrors, GetHttpChallengeDebugResponses, GetImportStatusData, GetImportStatusErrors, GetImportStatusResponses, GetIncidentData, GetIncidentErrors, GetIncidentResponses, GetIncidentUpdatesData, GetIncidentUpdatesErrors, GetIncidentUpdatesResponses, GetIpAccessControlData, GetIpAccessControlErrors, GetIpAccessControlResponses, GetIpGeolocationData, GetIpGeolocationErrors, GetIpGeolocationResponses, GetJoinTokenStatusData, GetJoinTokenStatusErrors, GetJoinTokenStatusResponses, GetLastDeploymentData, GetLastDeploymentErrors, GetLastDeploymentResponses, GetLatestScanData, GetLatestScanErrors, GetLatestScanResponses, GetLatestScansPerEnvironmentData, GetLatestScansPerEnvironmentErrors, GetLatestScansPerEnvironmentResponses, GetLiveVisitorsListData, GetLiveVisitorsListErrors, GetLiveVisitorsListResponses, GetLogContextData, GetLogContextErrors, GetLogContextResponses, GetMcpData, GetMcpErrors, GetMcpResponses, GetMetricsOverTimeData, GetMetricsOverTimeErrors, GetMetricsOverTimeResponses, GetMonitorData, GetMonitorErrors, GetMonitorResponses, GetNotificationProviderData, GetNotificationProviderErrors, GetNotificationProviderResponses, GetOnDemandCertStatusData, GetOnDemandCertStatusErrors, GetOnDemandCertStatusResponses, GetOrCreateDsnData, GetOrCreateDsnErrors, GetOrCreateDsnResponses, GetPageFlowData, GetPageFlowErrors, GetPageFlowResponses, GetPageHourlySessionsData, GetPageHourlySessionsErrors, GetPageHourlySessionsResponses, GetPagePathDetailData, GetPagePathDetailErrors, GetPagePathDetailResponses, GetPagePathsData, GetPagePathsErrors, GetPagePathsResponses, GetPagePathsSparklinesData, GetPagePathsSparklinesErrors, GetPagePathsSparklinesResponses, GetPagePathVisitorsData, GetPagePathVisitorsErrors, GetPagePathVisitorsResponses, GetPendingActionData, GetPendingActionErrors, GetPendingActionResponses, GetPerformanceMetricsData, GetPerformanceMetricsErrors, GetPerformanceMetricsResponses, GetPgUpgradeData, GetPgUpgradeErrors, GetPgUpgradeLogsData, GetPgUpgradeLogsErrors, GetPgUpgradeLogsResponses, GetPgUpgradeResponses, GetPipelineStatsData, GetPipelineStatsErrors, GetPipelineStatsResponses, GetPlatformInfoData, GetPlatformInfoErrors, GetPlatformInfoResponses, GetPostgresWalHealthData, GetPostgresWalHealthErrors, GetPostgresWalHealthResponses, GetPreferencesData, GetPreferencesErrors, GetPreferencesResponses, GetPreviewGatewayLogsData, GetPreviewGatewayLogsResponses, GetPreviewGatewaySettingsData, GetPreviewGatewaySettingsResponses, GetPreviewGatewayStatusData, GetPreviewGatewayStatusResponses, GetPricingData, GetPricingErrors, GetPricingResponses, GetPrivateIpData, GetPrivateIpErrors, GetPrivateIpResponses, GetProjectAlarmsSummaryData, GetProjectAlarmsSummaryErrors, GetProjectAlarmsSummaryResponses, GetProjectBySlugData, GetProjectBySlugErrors, GetProjectBySlugResponses, GetProjectData, GetProjectDeploymentsData, GetProjectDeploymentsErrors, GetProjectDeploymentsResponses, GetProjectErrors, GetProjectResponses, GetProjectsData, GetProjectsErrors, GetProjectServiceEnvironmentVariablesData, GetProjectServiceEnvironmentVariablesErrors, GetProjectServiceEnvironmentVariablesResponses, GetProjectSessionReplaysData, GetProjectSessionReplaysErrors, GetProjectSessionReplaysResponses, GetProjectsHealthData, GetProjectsHealthErrors, GetProjectsHealthResponses, GetProjectsMonitorHealthData, GetProjectsMonitorHealthErrors, GetProjectsMonitorHealthResponses, GetProjectsResponses, GetProjectStatisticsData, GetProjectStatisticsErrors, GetProjectStatisticsResponses, GetProjectTemplateData, GetProjectTemplateErrors, GetProjectTemplateResponses, GetPropertyBreakdownData, GetPropertyBreakdownErrors, GetPropertyBreakdownResponses, GetPropertyTimelineData, GetPropertyTimelineErrors, GetPropertyTimelineResponses, GetProviderConnectionsData, GetProviderConnectionsErrors, GetProviderConnectionsResponses, GetProviderMetadataData, GetProviderMetadataErrors, GetProviderMetadataResponses, GetProvidersMetadataData, GetProvidersMetadataErrors, GetProvidersMetadataResponses, GetProxyLogByIdData, GetProxyLogByIdErrors, GetProxyLogByIdResponses, GetProxyLogByRequestIdData, GetProxyLogByRequestIdErrors, GetProxyLogByRequestIdResponses, GetProxyLogsData, GetProxyLogsErrors, GetProxyLogsResponses, GetPublicBranchesData, GetPublicBranchesErrors, GetPublicBranchesResponses, GetPublicIpData, GetPublicIpErrors, GetPublicIpResponses, GetPublicRepositoryData, GetPublicRepositoryErrors, GetPublicRepositoryResponses, GetQuotaData, GetQuotaErrors, GetQuotaResponses, GetRecentActivityData, GetRecentActivityErrors, GetRecentActivityResponses, GetRemoteExternalImageData, GetRemoteExternalImageErrors, GetRemoteExternalImageResponses, GetRepositoryBranchesData, GetRepositoryBranchesErrors, GetRepositoryBranchesResponses, GetRepositoryByIdData, GetRepositoryByIdErrors, GetRepositoryByIdResponses, GetRepositoryByNameData, GetRepositoryByNameErrors, GetRepositoryByNameResponses, GetRepositoryPresetByNameData, GetRepositoryPresetByNameErrors, GetRepositoryPresetByNameResponses, GetRepositoryPresetLiveData, GetRepositoryPresetLiveErrors, GetRepositoryPresetLiveResponses, GetRepositoryTagsData, GetRepositoryTagsErrors, GetRepositoryTagsResponses, GetResolvedEnvironmentVariablesData, GetResolvedEnvironmentVariablesErrors, GetResolvedEnvironmentVariablesResponses, GetResolvedEnvironmentVariableValueData, GetResolvedEnvironmentVariableValueErrors, GetResolvedEnvironmentVariableValueResponses, GetRestoreCapabilitiesData, GetRestoreCapabilitiesErrors, GetRestoreCapabilitiesResponses, GetRestoreRunData, GetRestoreRunErrors, GetRestoreRunResponses, GetRouteData, GetRouteErrors, GetRouteResponses, GetRunData, GetRunErrors, GetRunResponses, GetRunWithLogsData, GetRunWithLogsErrors, GetRunWithLogsResponses, GetS3CredentialsData, GetS3CredentialsErrors, GetS3CredentialsResponses, GetS3SourceData, GetS3SourceErrors, GetS3SourceResponses, GetSandboxData, GetSandboxErrors, GetSandboxResponses, GetSandboxStatusData, GetSandboxStatusErrors, GetSandboxStatusResponses, GetScanByDeploymentData, GetScanByDeploymentErrors, GetScanByDeploymentResponses, GetScanData, GetScanErrors, GetScanResponses, GetScanVulnerabilitiesData, GetScanVulnerabilitiesErrors, GetScanVulnerabilitiesResponses, GetServiceBySlugData, GetServiceBySlugErrors, GetServiceBySlugResponses, GetServiceData, GetServiceEnvironmentVariableData, GetServiceEnvironmentVariableErrors, GetServiceEnvironmentVariableResponses, GetServiceEnvironmentVariablesData, GetServiceEnvironmentVariablesErrors, GetServiceEnvironmentVariablesResponses, GetServiceErrors, GetServiceHealthStatusData, GetServiceHealthStatusErrors, GetServiceHealthStatusResponses, GetServicePreviewEnvironmentVariableNamesData, GetServicePreviewEnvironmentVariableNamesErrors, GetServicePreviewEnvironmentVariableNamesResponses, GetServicePreviewEnvironmentVariablesMaskedData, GetServicePreviewEnvironmentVariablesMaskedErrors, GetServicePreviewEnvironmentVariablesMaskedResponses, GetServiceResponses, GetServiceRuntimeData, GetServiceRuntimeErrors, GetServiceRuntimeResponses, GetServiceStatsData, GetServiceStatsErrors, GetServiceStatsResponses, GetServiceTypeParametersData, GetServiceTypeParametersErrors, GetServiceTypeParametersResponses, GetServiceTypesData, GetServiceTypesErrors, GetServiceTypesResponses, GetSessionDetailsData, GetSessionDetailsErrors, GetSessionDetailsResponses, GetSessionEventsData, GetSessionEventsErrors, GetSessionEventsResponses, GetSessionLogsData, GetSessionLogsErrors, GetSessionLogsResponses, GetSessionReplayData, GetSessionReplayErrors, GetSessionReplayEventsData, GetSessionReplayEventsErrors, GetSessionReplayEventsResponses, GetSessionReplayResponses, GetSettingsData, GetSettingsErrors, GetSettingsResponses, GetSkillData, GetSkillErrors, GetSkillResponses, GetSlowQueriesData, GetSlowQueriesErrors, GetSlowQueriesResponses, GetStaticBundleData, GetStaticBundleErrors, GetStaticBundleResponses, GetStatusOverviewData, GetStatusOverviewErrors, GetStatusOverviewResponses, GetTagsByRepositoryIdData, GetTagsByRepositoryIdErrors, GetTagsByRepositoryIdResponses, GetTeamData, GetTeamErrors, GetTeamResponses, GetTimeBucketStatsData, GetTimeBucketStatsErrors, GetTimeBucketStatsResponses, GetTodayStatsData, GetTodayStatsErrors, GetTodayStatsResponses, GetTraceData, GetTraceErrors, GetTraceResponses, GetUnifiedTraceData, GetUnifiedTraceErrors, GetUnifiedTraceResponses, GetUniqueCountsData, GetUniqueCountsErrors, GetUniqueCountsResponses, GetUniqueEventsData, GetUniqueEventsErrors, GetUniqueEventsResponses, GetUpdateStatusData, GetUpdateStatusErrors, GetUpdateStatusResponses, GetUptimeHistoryData, GetUptimeHistoryErrors, GetUptimeHistoryResponses, GetUsageByProviderData, GetUsageByProviderErrors, GetUsageByProviderResponses, GetUsageRecentData, GetUsageRecentErrors, GetUsageRecentResponses, GetUsageSummaryData, GetUsageSummaryErrors, GetUsageSummaryResponses, GetUsageTimeseriesData, GetUsageTimeseriesErrors, GetUsageTimeseriesResponses, GetUsageTopModelsData, GetUsageTopModelsErrors, GetUsageTopModelsResponses, GetVisitorByGuidData, GetVisitorByGuidErrors, GetVisitorByGuidResponses, GetVisitorByIdData, GetVisitorByIdErrors, GetVisitorByIdResponses, GetVisitorDetailsData, GetVisitorDetailsErrors, GetVisitorDetailsResponses, GetVisitorFacetsData, GetVisitorFacetsErrors, GetVisitorFacetsResponses, GetVisitorInfoData, GetVisitorInfoErrors, GetVisitorInfoResponses, GetVisitorJourneyData, GetVisitorJourneyErrors, GetVisitorJourneyResponses, GetVisitorsData, GetVisitorsErrors, GetVisitorSessionsData, GetVisitorSessionsErrors, GetVisitorSessionsResponses, GetVisitorsResponses, GetVisitorStatsData, GetVisitorStatsErrors, GetVisitorStatsResponses, GetWebhookData, GetWebhookErrors, GetWebhookResponses, GrantProjectAccessData, GrantProjectAccessErrors, GrantProjectAccessResponses, HandleGitProviderOauthCallbackData, HandleGitProviderOauthCallbackErrors, HasAnalyticsEventsData, HasAnalyticsEventsErrors, HasAnalyticsEventsResponses, HasErrorGroupsData, HasErrorGroupsErrors, HasErrorGroupsResponses, HasPerformanceMetricsData, HasPerformanceMetricsErrors, HasPerformanceMetricsResponses, ImportExternalServiceData, ImportExternalServiceErrors, ImportExternalServiceResponses, IngestLogsByPathData, IngestLogsByPathErrors, IngestLogsByPathResponses, IngestLogsData, IngestLogsErrors, IngestLogsResponses, IngestMetricsByPathData, IngestMetricsByPathErrors, IngestMetricsByPathResponses, IngestMetricsData, IngestMetricsErrors, IngestMetricsResponses, IngestSentryEnvelopeData, IngestSentryEnvelopeErrors, IngestSentryEnvelopeResponses, IngestSentryEventData, IngestSentryEventErrors, IngestSentryEventResponses, IngestTracesByPathData, IngestTracesByPathErrors, IngestTracesByPathResponses, IngestTracesData, IngestTracesErrors, IngestTracesResponses, InitSessionReplayData, InitSessionReplayErrors, InitSessionReplayResponses, InspectDropArchiveData, InspectDropArchiveErrors, InspectDropArchiveResponses, JobLogsData, JobLogsErrors, JobLogsResponses, JobStatusData, JobStatusErrors, JobStatusResponses, KillJobData, KillJobErrors, KillJobResponses, KvDelData, KvDelErrors, KvDelResponses, KvDisableData, KvDisableErrors, KvDisableResponses, KvEnableData, KvEnableErrors, KvEnableResponses, KvExpireData, KvExpireErrors, KvExpireResponses, KvGetData, KvGetErrors, KvGetResponses, KvIncrData, KvIncrErrors, KvIncrResponses, KvKeysData, KvKeysErrors, KvKeysResponses, KvSetData, KvSetErrors, KvSetResponses, KvStatusData, KvStatusErrors, KvStatusResponses, KvTtlData, KvTtlErrors, KvTtlResponses, KvUpdateData, KvUpdateErrors, KvUpdateResponses, LatestRunForSourceData, LatestRunForSourceErrors, LatestRunForSourceResponses, LinkCustomDomainToCertificateData, LinkCustomDomainToCertificateErrors, LinkCustomDomainToCertificateResponses, LinkServiceToProjectData, LinkServiceToProjectErrors, LinkServiceToProjectResponses, ListAgentRunsData, ListAgentRunsErrors, ListAgentRunsResponses, ListAgentsData, ListAgentsErrors, ListAgentsResponses, ListAiProvidersData, ListAiProvidersErrors, ListAiProvidersResponses, ListAlertRulesData, ListAlertRulesErrors, ListAlertRulesResponses, ListAlertsData, ListAlertsErrors, ListAlertsResponses, ListAllConversationsData, ListAllConversationsErrors, ListAllConversationsResponses, ListAllRunsData, ListAllRunsErrors, ListAllRunsResponses, ListApiKeysData, ListApiKeysErrors, ListApiKeysResponses, ListAuditLogsData, ListAuditLogsErrors, ListAuditLogsResponses, ListAvailableContainersData, ListAvailableContainersErrors, ListAvailableContainersResponses, ListBackupAlertsData, ListBackupAlertsErrors, ListBackupAlertsResponses, ListBackupChildrenData, ListBackupChildrenErrors, ListBackupChildrenResponses, ListBackupSchedulesData, ListBackupSchedulesErrors, ListBackupSchedulesResponses, ListBackupsForScheduleData, ListBackupsForScheduleErrors, ListBackupsForScheduleResponses, ListCommitsByRepositoryIdData, ListCommitsByRepositoryIdErrors, ListCommitsByRepositoryIdResponses, ListConnectionsData, ListConnectionsErrors, ListConnectionsResponses, ListContainersAtPathData, ListContainersAtPathErrors, ListContainersAtPathResponses, ListContainersData, ListContainersErrors, ListContainersResponses, ListConversationsData, ListConversationsErrors, ListConversationsResponses, ListCustomDomainsForProjectData, ListCustomDomainsForProjectErrors, ListCustomDomainsForProjectResponses, ListDashboardsData, ListDashboardsErrors, ListDashboardsResponses, ListDeliveriesData, ListDeliveriesErrors, ListDeliveriesResponses, ListDeploymentContainerLogsData, ListDeploymentContainerLogsErrors, ListDeploymentContainerLogsResponses, ListDeploymentTokensData, ListDeploymentTokensErrors, ListDeploymentTokensResponses, ListDnsProvidersData, ListDnsProvidersErrors, ListDnsProvidersResponses, ListDomainsData, ListDomainsErrors, ListDomainsResponses, ListDsnsData, ListDsnsErrors, ListDsnsResponses, ListEmailDomainsData, ListEmailDomainsErrors, ListEmailDomainsResponses, ListEmailProvidersData, ListEmailProvidersErrors, ListEmailProvidersResponses, ListEmailsData, ListEmailsErrors, ListEmailsResponses, ListEnrollmentTokensData, ListEnrollmentTokensErrors, ListEnrollmentTokensResponses, ListEntitiesData, ListEntitiesErrors, ListEntitiesResponses, ListErrorEventsData, ListErrorEventsErrors, ListErrorEventsResponses, ListErrorGroupsData, ListErrorGroupsErrors, ListErrorGroupsResponses, ListEventsData, ListEventsResponses, ListEventTypesData, ListEventTypesResponses, ListExternalImagesData, ListExternalImagesErrors, ListExternalImagesResponses, ListExternalPluginsData, ListExternalPluginsErrors, ListExternalPluginsResponses, ListExternalServiceBackupsData, ListExternalServiceBackupsErrors, ListExternalServiceBackupsResponses, ListFlagsData, ListFlagsErrors, ListFlagsResponses, ListFunnelsData, ListFunnelsErrors, ListFunnelsResponses, ListGitProvidersData, ListGitProvidersErrors, ListGitProvidersResponses, ListGlobalMcpsData, ListGlobalMcpsErrors, ListGlobalMcpsResponses, ListGlobalSkillsData, ListGlobalSkillsErrors, ListGlobalSkillsResponses, ListIncidentsData, ListIncidentsErrors, ListIncidentsResponses, ListInsightsData, ListInsightsErrors, ListInsightsResponses, ListIpAccessControlData, ListIpAccessControlErrors, ListIpAccessControlResponses, ListJobsData, ListJobsErrors, ListJobsResponses, ListKnownAiAgentsData, ListKnownAiAgentsErrors, ListKnownAiAgentsResponses, ListManagedDomainsData, ListManagedDomainsErrors, ListManagedDomainsResponses, ListMcpsData, ListMcpsErrors, ListMcpsResponses, ListMetricLabelKeysData, ListMetricLabelKeysErrors, ListMetricLabelKeysResponses, ListMetricLabelValuesData, ListMetricLabelValuesErrors, ListMetricLabelValuesResponses, ListMetricNamesData, ListMetricNamesErrors, ListMetricNamesResponses, ListModelsData, ListModelsErrors, ListModelsResponses, ListMonitorsData, ListMonitorsErrors, ListMonitorsResponses, ListNotificationProvidersData, ListNotificationProvidersErrors, ListNotificationProvidersResponses, ListOidcProvidersData, ListOidcProvidersResponses, ListOidcProviderUsersData, ListOidcProviderUsersErrors, ListOidcProviderUsersResponses, ListOidcRoleMappingsData, ListOidcRoleMappingsResponses, ListOnDemandCertsData, ListOnDemandCertsErrors, ListOnDemandCertsResponses, ListOrdersData, ListOrdersErrors, ListOrdersResponses, ListPeersData, ListPeersErrors, ListPeersResponses, ListPendingActionsData, ListPendingActionsErrors, ListPendingActionsResponses, ListPgUpgradesData, ListPgUpgradesErrors, ListPgUpgradesResponses, ListPresetsData, ListPresetsErrors, ListPresetsResponses, ListProjectAccessData, ListProjectAccessErrors, ListProjectAccessResponses, ListProjectAlarmsData, ListProjectAlarmsErrors, ListProjectAlarmsResponses, ListProjectScansData, ListProjectScansErrors, ListProjectScansResponses, ListProjectSecretsData, ListProjectSecretsErrors, ListProjectSecretsResponses, ListProjectServicesData, ListProjectServicesErrors, ListProjectServicesResponses, ListProjectTemplatesData, ListProjectTemplatesErrors, ListProjectTemplatesResponses, ListProjectTemplateTagsData, ListProjectTemplateTagsErrors, ListProjectTemplateTagsResponses, ListProviderKeysData, ListProviderKeysErrors, ListProviderKeysResponses, ListProviderZonesData, ListProviderZonesErrors, ListProviderZonesResponses, ListPublicProvidersData, ListPublicProvidersResponses, ListReleaseFilesData, ListReleaseFilesErrors, ListReleaseFilesResponses, ListReleasesData, ListReleasesErrors, ListReleasesResponses, ListRemoteExternalImagesData, ListRemoteExternalImagesErrors, ListRemoteExternalImagesResponses, ListRepositoriesByConnectionData, ListRepositoriesByConnectionErrors, ListRepositoriesByConnectionResponses, ListRepositoriesByProviderData, ListRepositoriesByProviderErrors, ListRepositoriesByProviderResponses, ListRestoreRunsForServiceData, ListRestoreRunsForServiceResponses, ListRootContainersData, ListRootContainersErrors, ListRootContainersResponses, ListRoutesData, ListRoutesErrors, ListRoutesResponses, ListS3SourcesData, ListS3SourcesErrors, ListS3SourcesResponses, ListSandboxesData, ListSandboxesResponses, ListScheduleRunJobsData, ListScheduleRunJobsErrors, ListScheduleRunJobsResponses, ListScheduleRunsData, ListScheduleRunsErrors, ListScheduleRunsResponses, ListScheduleServicesData, ListScheduleServicesErrors, ListScheduleServicesResponses, ListSecretsData, ListSecretsErrors, ListSecretsResponses, ListServiceHealthStatusesData, ListServiceHealthStatusesErrors, ListServiceHealthStatusesResponses, ListServiceProjectsData, ListServiceProjectsErrors, ListServiceProjectsResponses, ListServiceSchedulesData, ListServiceSchedulesErrors, ListServiceSchedulesResponses, ListServicesData, ListServicesErrors, ListServicesResponses, ListSkillsData, ListSkillsErrors, ListSkillsResponses, ListSourceBackupsData, ListSourceBackupsErrors, ListSourceBackupsResponses, ListSourceFilesData, ListSourceFilesErrors, ListSourceFilesResponses, ListSourceMapsData, ListSourceMapsErrors, ListSourceMapsResponses, ListSourcesData, ListSourcesErrors, ListSourcesResponses, ListStaticBundlesData, ListStaticBundlesErrors, ListStaticBundlesResponses, ListSyncedRepositoriesData, ListSyncedRepositoriesErrors, ListSyncedRepositoriesResponses, ListTeamMembersData, ListTeamMembersErrors, ListTeamMembersResponses, ListTeamProjectsData, ListTeamProjectsErrors, ListTeamProjectsResponses, ListTeamsData, ListTeamsErrors, ListTeamsResponses, ListUsersData, ListUsersErrors, ListUsersResponses, ListWebhooksData, ListWebhooksErrors, ListWebhooksResponses, LoginData, LoginErrors, LoginResponses, LogoutData, LogoutErrors, LogoutResponses, LookupDnsARecordsData, LookupDnsARecordsErrors, LookupDnsARecordsResponses, MintEnrollmentTokenData, MintEnrollmentTokenErrors, MintEnrollmentTokenResponses, MkdirData, MkdirErrors, MkdirResponses, NodeHeartbeatData, NodeHeartbeatErrors, NodeHeartbeatResponses, NodeMetricsGetRangeData, NodeMetricsGetRangeErrors, NodeMetricsGetRangeResponses, ObservabilityFullEventData, ObservabilityFullEventErrors, ObservabilityFullEventResponses, ObservabilityListEventsData, ObservabilityListEventsErrors, ObservabilityListEventsResponses, OidcCallbackData, PatchAdminGateData, PatchAdminGateErrors, PatchAdminGateResponses, PatchPreviewGatewaySettingsData, PatchPreviewGatewaySettingsResponses, PauseDeploymentData, PauseDeploymentErrors, PauseDeploymentResponses, PauseSandboxData, PauseSandboxErrors, PauseSandboxResponses, PlanRestoreData, PlanRestoreErrors, PlanRestoreResponses, PostDnsAckData, PostDnsAckErrors, PostDnsAckResponses, PreviewAlertData, PreviewAlertErrors, PreviewAlertResponses, PreviewFunnelMetricsData, PreviewFunnelMetricsErrors, PreviewFunnelMetricsResponses, PreviewHostnameModeData, PreviewHostnameModeErrors, PreviewHostnameModeResponses, PromoteClusterMemberData, PromoteClusterMemberErrors, PromoteClusterMemberResponses, PromoteDeploymentData, PromoteDeploymentErrors, PromoteDeploymentResponses, ProvisionDomainData, ProvisionDomainErrors, ProvisionDomainResponses, PurgeProjectLogsData, PurgeProjectLogsErrors, PurgeProjectLogsResponses, PushExternalImageData, PushExternalImageErrors, PushExternalImageResponses, QueryDataData, QueryDataErrors, QueryDataResponses, QueryGenaiTracesData, QueryGenaiTracesErrors, QueryGenaiTracesResponses, QueryLogsData, QueryLogsErrors, QueryLogsResponses, QueryMetricsData, QueryMetricsErrors, QueryMetricsResponses, QueryTracesData, QueryTracesErrors, QueryTracesResponses, QueryTraceSummariesData, QueryTraceSummariesErrors, QueryTraceSummariesResponses, ReadFileData, ReadFileErrors, ReadFileResponses, ReAnalyzeData, ReAnalyzeErrors, ReAnalyzeResponses, RecordConsoleEventData, RecordConsoleEventErrors, RecordConsoleEventResponses, RecordEventMetricsData, RecordEventMetricsErrors, RecordEventMetricsResponses, RecordFlagExposureData, RecordFlagExposureErrors, RecordFlagExposureResponses, RecordSpeedMetricsData, RecordSpeedMetricsErrors, RecordSpeedMetricsResponses, RefreshRouteTableData, RefreshRouteTableErrors, RefreshRouteTableResponses, RegenerateDsnData, RegenerateDsnErrors, RegenerateDsnResponses, RegisterExternalImageData, RegisterExternalImageErrors, RegisterExternalImageResponses, RegisterNodeData, RegisterNodeErrors, RegisterNodeResponses, ReinstallGitlabWebhookData, ReinstallGitlabWebhookErrors, ReinstallGitlabWebhookResponses, RejectPendingActionData, RejectPendingActionErrors, RejectPendingActionResponses, ReloadPluginsData, ReloadPluginsErrors, ReloadPluginsResponses, RemoveClusterMemberData, RemoveClusterMemberErrors, RemoveClusterMemberResponses, RemoveManagedDomainData, RemoveManagedDomainErrors, RemoveManagedDomainResponses, RemoveRoleData, RemoveRoleErrors, RemoveRoleResponses, RemoveTeamMemberData, RemoveTeamMemberErrors, RemoveTeamMemberResponses, RenameConversationData, RenameConversationErrors, RenameConversationResponses, RenewDomainData, RenewDomainErrors, RenewDomainResponses, RequestPasswordResetData, RequestPasswordResetErrors, RequestPasswordResetResponses, ResetPasswordData, ResetPasswordErrors, ResetPasswordResponses, ResizeSandboxData, ResizeSandboxErrors, ResizeSandboxResponses, ResolveAlarmData, ResolveAlarmErrors, ResolveAlarmResponses, RestartContainerData, RestartContainerErrors, RestartContainerResponses, RestartPreviewGatewayData, RestartPreviewGatewayResponses, RestartSandboxData, RestartSandboxErrors, RestartSandboxResponses, RestoreFlagData, RestoreFlagErrors, RestoreFlagResponses, RestoreUserData, RestoreUserErrors, RestoreUserResponses, ResumeDeploymentData, ResumeDeploymentErrors, ResumeDeploymentResponses, ResumeSandboxData, ResumeSandboxErrors, ResumeSandboxResponses, RetryClusterData, RetryClusterErrors, RetryClusterResponses, RetryDeliveryData, RetryDeliveryErrors, RetryDeliveryResponses, RetryPgUpgradeData, RetryPgUpgradeErrors, RetryPgUpgradeResponses, RetryRunData, RetryRunErrors, RetryRunResponses, RevealGlobalMcpConfigData, RevealGlobalMcpConfigErrors, RevealGlobalMcpConfigResponses, RevealMcpConfigData, RevealMcpConfigErrors, RevealMcpConfigResponses, RevealNotificationProviderConfigData, RevealNotificationProviderConfigErrors, RevealNotificationProviderConfigResponses, RevealServiceParameterData, RevealServiceParameterErrors, RevealServiceParameterResponses, RevenueCreateIntegrationData, RevenueCreateIntegrationErrors, RevenueCreateIntegrationResponses, RevenueDeleteIntegrationData, RevenueDeleteIntegrationResponses, RevenueGlobalEventsData, RevenueGlobalEventsResponses, RevenueImportInvoicesCsvData, RevenueImportInvoicesCsvErrors, RevenueImportInvoicesCsvResponses, RevenueImportSubscriptionsCsvData, RevenueImportSubscriptionsCsvErrors, RevenueImportSubscriptionsCsvResponses, RevenueListIntegrationsData, RevenueListIntegrationsResponses, RevenueListProvidersData, RevenueListProvidersResponses, RevenueMetricsCustomersData, RevenueMetricsCustomersResponses, RevenueMetricsGlobalMrrData, RevenueMetricsGlobalMrrResponses, RevenueMetricsGlobalSummaryData, RevenueMetricsGlobalSummaryResponses, RevenueMetricsMrrData, RevenueMetricsMrrResponses, RevenueMetricsSummaryData, RevenueMetricsSummaryResponses, RevenueRecentEventsData, RevenueRecentEventsResponses, RevenueRotateTokenData, RevenueRotateTokenResponses, RevenueUpdateConfigData, RevenueUpdateConfigErrors, RevenueUpdateConfigResponses, RevenueUpdateSecretData, RevenueUpdateSecretErrors, RevenueUpdateSecretResponses, RevokeDsnData, RevokeDsnErrors, RevokeDsnResponses, RevokeEnrollmentTokenData, RevokeEnrollmentTokenErrors, RevokeEnrollmentTokenResponses, RevokeJoinTokenData, RevokeJoinTokenErrors, RevokeJoinTokenResponses, RevokeProjectAccessData, RevokeProjectAccessErrors, RevokeProjectAccessResponses, RollbackPgUpgradeData, RollbackPgUpgradeErrors, RollbackPgUpgradeResponses, RollbackToDeploymentData, RollbackToDeploymentErrors, RollbackToDeploymentResponses, RootfsGcData, RootfsGcResponses, RootfsReportData, RootfsReportResponses, RotateApiKeyData, RotateApiKeyErrors, RotateApiKeyResponses, RotateDeploymentTokenData, RotateDeploymentTokenErrors, RotateDeploymentTokenResponses, RunBackupForSourceData, RunBackupForSourceErrors, RunBackupForSourceResponses, RunConnectionHealthCheckData, RunConnectionHealthCheckErrors, RunConnectionHealthCheckResponses, RunExternalServiceBackupData, RunExternalServiceBackupErrors, RunExternalServiceBackupResponses, RunScheduleNowData, RunScheduleNowErrors, RunScheduleNowResponses, SandboxCreatePreviewLinkData, SandboxCreatePreviewLinkErrors, SandboxCreatePreviewLinkResponses, SaveAgentTokenData, SaveAgentTokenErrors, SaveAgentTokenResponses, SaveAiProviderCredentialData, SaveAiProviderCredentialErrors, SaveAiProviderCredentialResponses, SearchLogsData, SearchLogsErrors, SearchLogsResponses, SendEmailData, SendEmailErrors, SendEmailResponses, SetDefaultS3SourceData, SetDefaultS3SourceErrors, SetDefaultS3SourceResponses, SetFlagEnvironmentData, SetFlagEnvironmentErrors, SetFlagEnvironmentResponses, SetPreviewPasswordData, SetPreviewPasswordErrors, SetPreviewPasswordResponses, SetupDnsChallengeData, SetupDnsChallengeErrors, SetupDnsChallengeResponses, SetupDnsData, SetupDnsErrors, SetupDnsResponses, SetupEmailTrackingData, SetupEmailTrackingErrors, SetupEmailTrackingResponses, SetupMfaData, SetupMfaErrors, SetupMfaResponses, SleepEnvironmentData, SleepEnvironmentErrors, SleepEnvironmentResponses, SmokeTestAgentData, SmokeTestAgentErrors, SmokeTestAgentResponses, SourceSandboxData, SourceSandboxErrors, SourceSandboxResponses, StartAnalysisData, StartAnalysisErrors, StartAnalysisResponses, StartContainerData, StartContainerErrors, StartContainerResponses, StartFixData, StartFixErrors, StartFixResponses, StartGitProviderOauthData, StartGitProviderOauthErrors, StartOidcLoginBySlugData, StartOidcLoginBySlugErrors, StartPgUpgradeData, StartPgUpgradeErrors, StartPgUpgradeResponses, StartRestoreData, StartRestoreErrors, StartRestoreResponses, StartServiceData, StartServiceErrors, StartServiceResponses, StatPathData, StatPathErrors, StatPathResponses, StopContainerData, StopContainerErrors, StopContainerResponses, StopSandboxData, StopSandboxErrors, StopSandboxResponses, StopServiceData, StopServiceErrors, StopServiceResponses, StreamContainerMetricsData, StreamContainerMetricsErrors, StreamContainerMetricsResponses, StreamEventsData, StreamEventsErrors, StreamEventsResponses, StreamRunEventsData, StreamRunEventsErrors, StreamRunEventsResponses, SyncRepositoriesData, SyncRepositoriesErrors, SyncRepositoriesResponses, TailDeploymentJobLogsData, TailDeploymentJobLogsErrors, TailLogsData, TailLogsErrors, TailLogsResponses, TeardownDeploymentData, TeardownDeploymentErrors, TeardownDeploymentResponses, TeardownEnvironmentData, TeardownEnvironmentErrors, TeardownEnvironmentResponses, TestNotificationProviderData, TestNotificationProviderErrors, TestNotificationProviderResponses, TestOidcProviderData, TestOidcProviderResponses, TestProviderConnectionData, TestProviderConnectionErrors, TestProviderConnectionResponses, TestProviderData, TestProviderErrors, TestProviderKeyByIdData, TestProviderKeyByIdErrors, TestProviderKeyByIdResponses, TestProviderKeyInlineData, TestProviderKeyInlineErrors, TestProviderKeyInlineResponses, TestProviderResponses, TestS3ConnectionPreviewData, TestS3ConnectionPreviewErrors, TestS3ConnectionPreviewResponses, TestS3SourceConnectionData, TestS3SourceConnectionErrors, TestS3SourceConnectionResponses, TrackClickData, TrackClickErrors, TrackOpenData, TrackOpenErrors, TrackOpenResponses, TriggerAgentData, TriggerAgentErrors, TriggerAgentResponses, TriggerProjectPipelineData, TriggerProjectPipelineErrors, TriggerProjectPipelineResponses, TriggerScanData, TriggerScanErrors, TriggerScanResponses, TriggerServiceHealthCheckData, TriggerServiceHealthCheckErrors, TriggerServiceHealthCheckResponses, TriggerWeeklyDigestData, TriggerWeeklyDigestErrors, TriggerWeeklyDigestResponses, UnlinkServiceFromProjectData, UnlinkServiceFromProjectErrors, UnlinkServiceFromProjectResponses, UpdateAgentData, UpdateAgentErrors, UpdateAgentResponses, UpdateAiProviderData, UpdateAiProviderErrors, UpdateAiProviderResponses, UpdateAlertData, UpdateAlertErrors, UpdateAlertResponses, UpdateAlertRuleData, UpdateAlertRuleErrors, UpdateAlertRuleResponses, UpdateApiKeyData, UpdateApiKeyErrors, UpdateApiKeyResponses, UpdateAutomaticDeployData, UpdateAutomaticDeployErrors, UpdateAutomaticDeployResponses, UpdateBackupScheduleData, UpdateBackupScheduleErrors, UpdateBackupScheduleResponses, UpdateCloudflareProviderData, UpdateCloudflareProviderErrors, UpdateCloudflareProviderResponses, UpdateConnectionTokenData, UpdateConnectionTokenErrors, UpdateConnectionTokenResponses, UpdateCustomDomainData, UpdateCustomDomainErrors, UpdateCustomDomainResponses, UpdateDashboardData, UpdateDashboardErrors, UpdateDashboardResponses, UpdateDeploymentTokenData, UpdateDeploymentTokenErrors, UpdateDeploymentTokenResponses, UpdateEmailProviderData, UpdateEmailProviderErrors, UpdateEmailProviderResponses, UpdateEnvironmentSettingsData, UpdateEnvironmentSettingsErrors, UpdateEnvironmentSettingsResponses, UpdateEnvironmentSubdomainData, UpdateEnvironmentSubdomainErrors, UpdateEnvironmentSubdomainResponses, UpdateEnvironmentVariableData, UpdateEnvironmentVariableErrors, UpdateEnvironmentVariableResponses, UpdateErrorGroupData, UpdateErrorGroupErrors, UpdateErrorGroupResponses, UpdateFlagData, UpdateFlagErrors, UpdateFlagResponses, UpdateFunnelData, UpdateFunnelErrors, UpdateFunnelResponses, UpdateGitProviderCredentialsData, UpdateGitProviderCredentialsErrors, UpdateGitProviderCredentialsResponses, UpdateGitSettingsData, UpdateGitSettingsErrors, UpdateGitSettingsResponses, UpdateGlobalMcpData, UpdateGlobalMcpErrors, UpdateGlobalMcpResponses, UpdateGlobalSkillData, UpdateGlobalSkillErrors, UpdateGlobalSkillResponses, UpdateIncidentStatusData, UpdateIncidentStatusErrors, UpdateIncidentStatusResponses, UpdateIpAccessControlData, UpdateIpAccessControlErrors, UpdateIpAccessControlResponses, UpdateManagedDomainData, UpdateManagedDomainErrors, UpdateManagedDomainResponses, UpdateMcpData, UpdateMcpErrors, UpdateMcpResponses, UpdateNotificationEmailProviderData, UpdateNotificationEmailProviderErrors, UpdateNotificationEmailProviderResponses, UpdateNotificationProviderData, UpdateNotificationProviderErrors, UpdateNotificationProviderResponses, UpdateOidcProviderData, UpdateOidcProviderResponses, UpdatePreferencesData, UpdatePreferencesErrors, UpdatePreferencesResponses, UpdateProjectData, UpdateProjectDeploymentConfigData, UpdateProjectDeploymentConfigErrors, UpdateProjectDeploymentConfigResponses, UpdateProjectErrors, UpdateProjectResponses, UpdateProjectSecretData, UpdateProjectSecretErrors, UpdateProjectSecretResponses, UpdateProjectSettingsData, UpdateProjectSettingsErrors, UpdateProjectSettingsResponses, UpdateProviderData, UpdateProviderErrors, UpdateProviderKeyData, UpdateProviderKeyErrors, UpdateProviderKeyResponses, UpdateProviderResponses, UpdateRouteData, UpdateRouteErrors, UpdateRouteResponses, UpdateS3SourceData, UpdateS3SourceErrors, UpdateS3SourceResponses, UpdateSelfData, UpdateSelfErrors, UpdateSelfResponses, UpdateServiceData, UpdateServiceErrors, UpdateServiceResourcesData, UpdateServiceResourcesErrors, UpdateServiceResourcesResponses, UpdateServiceResponses, UpdateSessionDurationData, UpdateSessionDurationErrors, UpdateSessionDurationResponses, UpdateSettingsData, UpdateSettingsErrors, UpdateSettingsResponses, UpdateSkillData, UpdateSkillErrors, UpdateSkillResponses, UpdateSlackProviderData, UpdateSlackProviderErrors, UpdateSlackProviderResponses, UpdateSpeedMetricsData, UpdateSpeedMetricsErrors, UpdateSpeedMetricsResponses, UpdateTeamData, UpdateTeamErrors, UpdateTeamMemberRoleData, UpdateTeamMemberRoleErrors, UpdateTeamMemberRoleResponses, UpdateTeamResponses, UpdateUserData, UpdateUserErrors, UpdateUserResponses, UpdateWebhookData, UpdateWebhookErrors, UpdateWebhookProviderData, UpdateWebhookProviderErrors, UpdateWebhookProviderResponses, UpdateWebhookResponses, UpgradePreviewGatewayData, UpgradePreviewGatewayResponses, UpgradeServiceData, UpgradeServiceErrors, UpgradeServiceResponses, UploadGlobalSkillData, UploadGlobalSkillErrors, UploadGlobalSkillResponses, UploadReleaseFileData, UploadReleaseFileErrors, UploadReleaseFileResponses, UploadSkillData, UploadSkillErrors, UploadSkillResponses, UploadSourceFileData, UploadSourceFileErrors, UploadSourceFileResponses, UploadSourceMapData, UploadSourceMapErrors, UploadSourceMapResponses, UploadStaticBundleData, UploadStaticBundleErrors, UploadStaticBundleResponses, UpsertSecretData, UpsertSecretErrors, UpsertSecretResponses, ValidateConnectionData, ValidateConnectionErrors, ValidateConnectionResponses, ValidateEmailData, ValidateEmailErrors, ValidateEmailResponses, VerifyAndEnableMfaData, VerifyAndEnableMfaErrors, VerifyAndEnableMfaResponses, VerifyDomainData, VerifyDomainErrors, VerifyDomainResponses, VerifyEmailData, VerifyEmailErrors, VerifyEmailResponses, VerifyManagedDomainData, VerifyManagedDomainErrors, VerifyManagedDomainResponses, VerifyMfaChallengeData, VerifyMfaChallengeErrors, VerifyMfaChallengeResponses, VerifyStepUpData, VerifyStepUpErrors, VerifyStepUpResponses, WakeEnvironmentData, WakeEnvironmentErrors, WakeEnvironmentResponses, WebhookTriggerData, WebhookTriggerErrors, WebhookTriggerResponses, WorkflowDryRunData, WorkflowDryRunErrors, WorkflowDryRunResponses, WriteFileData, WriteFileErrors, WriteFileResponses, WriteFilesData, WriteFilesErrors, WriteFilesResponses } from './types.gen'; +import type { AcknowledgeAlarmData, AcknowledgeAlarmErrors, AcknowledgeAlarmResponses, ActivateAiProviderData, ActivateAiProviderErrors, ActivateAiProviderResponses, ActivateApiKeyData, ActivateApiKeyErrors, ActivateApiKeyResponses, ActivateConnectionData, ActivateConnectionErrors, ActivateConnectionResponses, ActivateProviderData, ActivateProviderErrors, ActivateProviderResponses, AddClusterMemberData, AddClusterMemberErrors, AddClusterMemberResponses, AddContextData, AddContextErrors, AddContextResponses, AddEnvironmentDomainData, AddEnvironmentDomainErrors, AddEnvironmentDomainResponses, AddEventsData, AddEventsErrors, AddEventsResponses, AddManagedDomainData, AddManagedDomainErrors, AddManagedDomainResponses, AddSessionReplayEventsData, AddSessionReplayEventsErrors, AddSessionReplayEventsResponses, AddTeamMemberData, AddTeamMemberErrors, AddTeamMemberResponses, AdminDrainNodeData, AdminDrainNodeErrors, AdminDrainNodeResponses, AdminDrainStatusData, AdminDrainStatusErrors, AdminDrainStatusResponses, AdminGetNodeData, AdminGetNodeErrors, AdminGetNodeResponses, AdminListNodeContainersData, AdminListNodeContainersErrors, AdminListNodeContainersResponses, AdminListNodesData, AdminListNodesErrors, AdminListNodesResponses, AdminRemoveNodeData, AdminRemoveNodeErrors, AdminRemoveNodeResponses, AdminUndrainNodeData, AdminUndrainNodeErrors, AdminUndrainNodeResponses, ApplyHostnameModeData, ApplyHostnameModeErrors, ApplyHostnameModeResponses, ArchiveConversationData, ArchiveConversationErrors, ArchiveConversationResponses, ArchiveFlagData, ArchiveFlagErrors, ArchiveFlagResponses, AssignRoleData, AssignRoleErrors, AssignRoleResponses, AttachScheduleServicesData, AttachScheduleServicesErrors, AttachScheduleServicesResponses, BlobCopyData, BlobCopyErrors, BlobCopyResponses, BlobDeleteData, BlobDeleteErrors, BlobDeleteResponses, BlobDisableData, BlobDisableErrors, BlobDisableResponses, BlobDownloadData, BlobDownloadErrors, BlobDownloadResponses, BlobEnableData, BlobEnableErrors, BlobEnableResponses, BlobHeadData, BlobHeadErrors, BlobHeadResponses, BlobListData, BlobListErrors, BlobListResponses, BlobPutData, BlobPutErrors, BlobPutResponses, BlobStatusData, BlobStatusErrors, BlobStatusResponses, BlobUpdateData, BlobUpdateErrors, BlobUpdateResponses, CancelBackupData, CancelBackupErrors, CancelBackupResponses, CancelData, CancelDeploymentData, CancelDeploymentErrors, CancelDeploymentResponses, CancelDomainOrderData, CancelDomainOrderErrors, CancelDomainOrderResponses, CancelErrors, CancelPgUpgradeData, CancelPgUpgradeErrors, CancelPgUpgradeResponses, CancelResponses, CancelRunData, CancelRunErrors, CancelRunResponses, CancelScheduleRunData, CancelScheduleRunErrors, CancelScheduleRunResponses, ChangePasswordSelfData, ChangePasswordSelfErrors, ChangePasswordSelfResponses, ChangeProjectSourceData, ChangeProjectSourceErrors, ChangeProjectSourceResponses, ChatCompletionsData, ChatCompletionsErrors, ChatCompletionsResponses, CheckAnalyticsHasEventsData, CheckAnalyticsHasEventsErrors, CheckAnalyticsHasEventsResponses, CheckCommitExistsData, CheckCommitExistsErrors, CheckCommitExistsResponses, CheckDomainStatusData, CheckDomainStatusErrors, CheckDomainStatusResponses, CheckExplorerSupportData, CheckExplorerSupportErrors, CheckExplorerSupportResponses, CheckIpBlockedData, CheckIpBlockedErrors, CheckIpBlockedResponses, CheckProviderDeletionSafetyData, CheckProviderDeletionSafetyErrors, CheckProviderDeletionSafetyResponses, ChunkUploadOptionsData, ChunkUploadOptionsResponses, CleanupExpiredBackupsData, CleanupExpiredBackupsErrors, CleanupExpiredBackupsResponses, ClearPreviewPasswordData, ClearPreviewPasswordErrors, ClearPreviewPasswordResponses, CliDeviceApproveData, CliDeviceApproveErrors, CliDeviceApproveResponses, CliDeviceDenyData, CliDeviceDenyErrors, CliDeviceDenyResponses, CliDeviceLookupData, CliDeviceLookupErrors, CliDeviceLookupResponses, CliDevicePollData, CliDevicePollErrors, CliDevicePollResponses, CliDeviceStartData, CliDeviceStartErrors, CliDeviceStartResponses, CliLogoutData, CliLogoutErrors, CliLogoutResponses, CmdData, CmdErrors, CmdKillData, CmdKillErrors, CmdKillResponses, CmdLogsData, CmdLogsErrors, CmdLogsResponses, CmdResponses, ConfirmPendingActionData, ConfirmPendingActionErrors, ConfirmPendingActionResponses, ContainerMetricsGetHistoryData, ContainerMetricsGetHistoryErrors, ContainerMetricsGetHistoryResponses, CreateAgentData, CreateAgentErrors, CreateAgentResponses, CreateAlertData, CreateAlertErrors, CreateAlertResponses, CreateAlertRuleData, CreateAlertRuleErrors, CreateAlertRuleResponses, CreateApiKeyData, CreateApiKeyErrors, CreateApiKeyResponses, CreateBackupScheduleData, CreateBackupScheduleErrors, CreateBackupScheduleResponses, CreateBitbucketProviderData, CreateBitbucketProviderErrors, CreateBitbucketProviderResponses, CreateCloudflareProviderData, CreateCloudflareProviderErrors, CreateCloudflareProviderResponses, CreateConversationData, CreateConversationErrors, CreateConversationResponses, CreateCustomDomainData, CreateCustomDomainErrors, CreateCustomDomainResponses, CreateDashboardData, CreateDashboardErrors, CreateDashboardResponses, CreateDeploymentTokenData, CreateDeploymentTokenErrors, CreateDeploymentTokenResponses, CreateDnsProviderData, CreateDnsProviderErrors, CreateDnsProviderResponses, CreateDomainData, CreateDomainErrors, CreateDomainResponses, CreateDsnData, CreateDsnErrors, CreateDsnResponses, CreateEmailDomainData, CreateEmailDomainErrors, CreateEmailDomainResponses, CreateEmailProviderData, CreateEmailProviderErrors, CreateEmailProviderResponses, CreateEnvironmentData, CreateEnvironmentErrors, CreateEnvironmentResponses, CreateEnvironmentVariableData, CreateEnvironmentVariableErrors, CreateEnvironmentVariableResponses, CreateFlagData, CreateFlagErrors, CreateFlagResponses, CreateFunnelData, CreateFunnelErrors, CreateFunnelResponses, CreateGenericProviderData, CreateGenericProviderErrors, CreateGenericProviderResponses, CreateGiteaPatProviderData, CreateGiteaPatProviderErrors, CreateGiteaPatProviderResponses, CreateGithubPatProviderData, CreateGithubPatProviderErrors, CreateGithubPatProviderResponses, CreateGitlabOauthProviderData, CreateGitlabOauthProviderErrors, CreateGitlabOauthProviderResponses, CreateGitlabPatProviderData, CreateGitlabPatProviderErrors, CreateGitlabPatProviderResponses, CreateGitProviderData, CreateGitProviderErrors, CreateGitProviderResponses, CreateGlobalMcpData, CreateGlobalMcpErrors, CreateGlobalMcpResponses, CreateGlobalSkillData, CreateGlobalSkillErrors, CreateGlobalSkillResponses, CreateIncidentData, CreateIncidentErrors, CreateIncidentResponses, CreateIpAccessControlData, CreateIpAccessControlErrors, CreateIpAccessControlResponses, CreateMcpData, CreateMcpErrors, CreateMcpResponses, CreateMonitorData, CreateMonitorErrors, CreateMonitorResponses, CreateNotificationEmailProviderData, CreateNotificationEmailProviderErrors, CreateNotificationEmailProviderResponses, CreateNotificationProviderData, CreateNotificationProviderErrors, CreateNotificationProviderResponses, CreateOidcProviderData, CreateOidcProviderErrors, CreateOidcProviderResponses, CreateOidcRoleMappingData, CreateOidcRoleMappingResponses, CreateOrRecreateOrderData, CreateOrRecreateOrderErrors, CreateOrRecreateOrderResponses, CreatePlanData, CreatePlanErrors, CreatePlanResponses, CreatePrData, CreatePrErrors, CreateProjectData, CreateProjectErrors, CreateProjectFromTemplateData, CreateProjectFromTemplateErrors, CreateProjectFromTemplateResponses, CreateProjectReleaseData, CreateProjectReleaseErrors, CreateProjectReleaseResponses, CreateProjectResponses, CreateProjectSecretData, CreateProjectSecretErrors, CreateProjectSecretResponses, CreateProviderKeyData, CreateProviderKeyErrors, CreateProviderKeyResponses, CreatePrResponses, CreateReleaseData, CreateReleaseErrors, CreateReleaseResponses, CreateRouteData, CreateRouteErrors, CreateRouteResponses, CreateS3SourceData, CreateS3SourceErrors, CreateS3SourceResponses, CreateSandboxData, CreateSandboxErrors, CreateSandboxResponses, CreateServiceData, CreateServiceErrors, CreateServiceResponses, CreateSkillData, CreateSkillErrors, CreateSkillResponses, CreateSlackProviderData, CreateSlackProviderErrors, CreateSlackProviderResponses, CreateTeamData, CreateTeamErrors, CreateTeamResponses, CreateUserData, CreateUserErrors, CreateUserResponses, CreateWebhookData, CreateWebhookErrors, CreateWebhookProviderData, CreateWebhookProviderErrors, CreateWebhookProviderResponses, CreateWebhookResponses, DeactivateApiKeyData, DeactivateApiKeyErrors, DeactivateApiKeyResponses, DeactivateConnectionData, DeactivateConnectionErrors, DeactivateConnectionResponses, DeactivateProviderData, DeactivateProviderErrors, DeactivateProviderResponses, DeleteAgentData, DeleteAgentErrors, DeleteAgentResponses, DeleteAlertData, DeleteAlertErrors, DeleteAlertResponses, DeleteAlertRuleData, DeleteAlertRuleErrors, DeleteAlertRuleResponses, DeleteApiKeyData, DeleteApiKeyErrors, DeleteApiKeyResponses, DeleteBackupData, DeleteBackupErrors, DeleteBackupResponses, DeleteBackupScheduleData, DeleteBackupScheduleErrors, DeleteBackupScheduleResponses, DeleteConnectionData, DeleteConnectionErrors, DeleteConnectionResponses, DeleteCustomDomainData, DeleteCustomDomainErrors, DeleteCustomDomainResponses, DeleteDashboardData, DeleteDashboardErrors, DeleteDashboardResponses, DeleteDeploymentTokenData, DeleteDeploymentTokenErrors, DeleteDeploymentTokenResponses, DeleteDnsProviderData, DeleteDnsProviderErrors, DeleteDnsProviderResponses, DeleteDomainData, DeleteDomainErrors, DeleteDomainResponses, DeleteEmailDomainData, DeleteEmailDomainErrors, DeleteEmailDomainResponses, DeleteEmailProviderData, DeleteEmailProviderErrors, DeleteEmailProviderResponses, DeleteEnvironmentData, DeleteEnvironmentDomainData, DeleteEnvironmentDomainErrors, DeleteEnvironmentDomainResponses, DeleteEnvironmentErrors, DeleteEnvironmentResponses, DeleteEnvironmentVariableData, DeleteEnvironmentVariableErrors, DeleteEnvironmentVariableResponses, DeleteExternalImageData, DeleteExternalImageErrors, DeleteExternalImageResponses, DeleteFunnelData, DeleteFunnelErrors, DeleteFunnelResponses, DeleteGitProviderData, DeleteGitProviderErrors, DeleteGitProviderResponses, DeleteGlobalMcpData, DeleteGlobalMcpErrors, DeleteGlobalMcpResponses, DeleteGlobalSkillData, DeleteGlobalSkillErrors, DeleteGlobalSkillResponses, DeleteIpAccessControlData, DeleteIpAccessControlErrors, DeleteIpAccessControlResponses, DeleteMcpData, DeleteMcpErrors, DeleteMcpResponses, DeleteMonitorData, DeleteMonitorErrors, DeleteMonitorResponses, DeleteNotificationProviderData, DeleteNotificationProviderErrors, DeleteNotificationProviderResponses, DeleteOidcProviderData, DeleteOidcProviderResponses, DeleteOidcRoleMappingData, DeleteOidcRoleMappingResponses, DeletePreferencesData, DeletePreferencesErrors, DeletePreferencesResponses, DeleteProjectData, DeleteProjectErrors, DeleteProjectResponses, DeleteProjectSecretData, DeleteProjectSecretErrors, DeleteProjectSecretResponses, DeleteProviderKeyData, DeleteProviderKeyErrors, DeleteProviderKeyResponses, DeleteProviderSafelyData, DeleteProviderSafelyErrors, DeleteProviderSafelyResponses, DeleteReleaseSourceFilesData, DeleteReleaseSourceFilesErrors, DeleteReleaseSourceFilesResponses, DeleteReleaseSourceMapsData, DeleteReleaseSourceMapsErrors, DeleteReleaseSourceMapsResponses, DeleteRouteData, DeleteRouteErrors, DeleteRouteResponses, DeleteS3SourceData, DeleteS3SourceErrors, DeleteS3SourceResponses, DeleteScanData, DeleteScanErrors, DeleteScanResponses, DeleteSecretData, DeleteSecretErrors, DeleteSecretResponses, DeleteServiceData, DeleteServiceErrors, DeleteServiceResponses, DeleteSessionReplayData, DeleteSessionReplayErrors, DeleteSessionReplayResponses, DeleteSkillData, DeleteSkillErrors, DeleteSkillResponses, DeleteSourceMapData, DeleteSourceMapErrors, DeleteSourceMapResponses, DeleteStaticBundleData, DeleteStaticBundleErrors, DeleteStaticBundleResponses, DeleteTeamData, DeleteTeamErrors, DeleteTeamResponses, DeleteUserData, DeleteUserErrors, DeleteUserResponses, DeleteWebhookData, DeleteWebhookErrors, DeleteWebhookResponses, DeployFromImageData, DeployFromImageErrors, DeployFromImageResponses, DeployFromImageUploadData, DeployFromImageUploadErrors, DeployFromImageUploadResponses, DeployFromStaticData, DeployFromStaticErrors, DeployFromStaticResponses, DeployFromUploadedSourceData, DeployFromUploadedSourceErrors, DeployFromUploadedSourceResponses, DeploymentMetricsGetLatestData, DeploymentMetricsGetLatestErrors, DeploymentMetricsGetLatestResponses, DeploymentMetricsGetRangeData, DeploymentMetricsGetRangeErrors, DeploymentMetricsGetRangeResponses, DeploymentMetricsToggleData, DeploymentMetricsToggleErrors, DeploymentMetricsToggleResponses, DestroySandboxData, DestroySandboxErrors, DestroySandboxResponses, DetachScheduleServiceData, DetachScheduleServiceErrors, DetachScheduleServiceResponses, DetectPublicPresetsData, DetectPublicPresetsErrors, DetectPublicPresetsResponses, DisableBackupScheduleData, DisableBackupScheduleErrors, DisableBackupScheduleResponses, DisableMfaData, DisableMfaErrors, DisableMfaResponses, DisconnectCloudData, DisconnectCloudResponses, DiscoverWorkloadsData, DiscoverWorkloadsErrors, DiscoverWorkloadsResponses, DomainData, DomainErrors, DomainResponses, DownloadGlobalSkillArchiveData, DownloadGlobalSkillArchiveErrors, DownloadGlobalSkillArchiveResponses, DownloadObjectData, DownloadObjectErrors, DownloadObjectResponses, DownloadSkillArchiveData, DownloadSkillArchiveErrors, DownloadSkillArchiveResponses, EmailStatusData, EmailStatusErrors, EmailStatusResponses, EmbeddingsData, EmbeddingsErrors, EmbeddingsResponses, EnableBackupScheduleData, EnableBackupScheduleErrors, EnableBackupScheduleResponses, EnrichVisitorData, EnrichVisitorErrors, EnrichVisitorResponses, EnrollCloudData, EnrollCloudResponses, ExecData, ExecDetachedData, ExecDetachedErrors, ExecDetachedResponses, ExecErrors, ExecResponses, ExecuteDeploymentOperationData, ExecuteDeploymentOperationErrors, ExecuteDeploymentOperationResponses, ExecuteImportData, ExecuteImportErrors, ExecuteImportResponses, ExtendTimeoutData, ExtendTimeoutErrors, ExtendTimeoutResponses, ExternalServiceEnablePgStatStatementsData, ExternalServiceEnablePgStatStatementsErrors, ExternalServiceEnablePgStatStatementsResponses, ExternalServiceMetricsByDatabaseData, ExternalServiceMetricsByDatabaseErrors, ExternalServiceMetricsByDatabaseResponses, ExternalServiceMetricsCreateAlertRuleData, ExternalServiceMetricsCreateAlertRuleErrors, ExternalServiceMetricsCreateAlertRuleResponses, ExternalServiceMetricsDeleteAlertRuleData, ExternalServiceMetricsDeleteAlertRuleErrors, ExternalServiceMetricsDeleteAlertRuleResponses, ExternalServiceMetricsGetAlertRulesData, ExternalServiceMetricsGetAlertRulesErrors, ExternalServiceMetricsGetAlertRulesResponses, ExternalServiceMetricsGetLatestData, ExternalServiceMetricsGetLatestErrors, ExternalServiceMetricsGetLatestResponses, ExternalServiceMetricsGetRangeData, ExternalServiceMetricsGetRangeErrors, ExternalServiceMetricsGetRangeResponses, ExternalServiceMetricsStatusData, ExternalServiceMetricsStatusErrors, ExternalServiceMetricsStatusResponses, ExternalServiceMetricsToggleData, ExternalServiceMetricsToggleErrors, ExternalServiceMetricsToggleResponses, ExternalServiceMetricsUpdateAlertRuleData, ExternalServiceMetricsUpdateAlertRuleErrors, ExternalServiceMetricsUpdateAlertRuleResponses, ExternalServiceResetPgStatStatementsData, ExternalServiceResetPgStatStatementsErrors, ExternalServiceResetPgStatStatementsResponses, FinalizeOrderData, FinalizeOrderErrors, FinalizeOrderResponses, FinalizeProjectReleaseData, FinalizeProjectReleaseErrors, FinalizeProjectReleaseResponses, FindConversationData, FindConversationErrors, FindConversationResponses, GenerateJoinTokenData, GenerateJoinTokenErrors, GenerateJoinTokenResponses, GeneratePresetDockerfileData, GeneratePresetDockerfileErrors, GeneratePresetDockerfileResponses, GetAccessInfoData, GetAccessInfoErrors, GetAccessInfoResponses, GetActiveVisitorsData, GetActiveVisitorsErrors, GetActiveVisitorsResponses, GetActivityGraphData, GetActivityGraphErrors, GetActivityGraphResponses, GetAdminGateData, GetAdminGateErrors, GetAdminGateResponses, GetAgentData, GetAgentErrors, GetAgentResponses, GetAggregatedBucketsData, GetAggregatedBucketsErrors, GetAggregatedBucketsResponses, GetAiAgentBreakdownData, GetAiAgentBreakdownErrors, GetAiAgentBreakdownResponses, GetAiAgentPagesData, GetAiAgentPagesErrors, GetAiAgentPagesResponses, GetAiAgentTimelineData, GetAiAgentTimelineErrors, GetAiAgentTimelineResponses, GetAiPageBreakdownData, GetAiPageBreakdownErrors, GetAiPageBreakdownResponses, GetAiStatusBreakdownData, GetAiStatusBreakdownErrors, GetAiStatusBreakdownResponses, GetAlertData, GetAlertErrors, GetAlertResponses, GetAlertRuleData, GetAlertRuleErrors, GetAlertRuleResponses, GetAllRepositoriesByNameData, GetAllRepositoriesByNameErrors, GetAllRepositoriesByNameResponses, GetAnalyticsActiveVisitorsData, GetAnalyticsActiveVisitorsErrors, GetAnalyticsActiveVisitorsResponses, GetAnalyticsEventsCountData, GetAnalyticsEventsCountErrors, GetAnalyticsEventsCountResponses, GetAnalyticsSessionEventsData, GetAnalyticsSessionEventsErrors, GetAnalyticsSessionEventsResponses, GetAnalyticsVisitorSessionsData, GetAnalyticsVisitorSessionsErrors, GetAnalyticsVisitorSessionsResponses, GetApiKeyData, GetApiKeyErrors, GetApiKeyPermissionsData, GetApiKeyPermissionsErrors, GetApiKeyPermissionsResponses, GetApiKeyResponses, GetAuditLogData, GetAuditLogErrors, GetAuditLogResponses, GetBackupData, GetBackupErrors, GetBackupResponses, GetBackupScheduleData, GetBackupScheduleErrors, GetBackupScheduleResponses, GetBranchesByRepositoryIdData, GetBranchesByRepositoryIdErrors, GetBranchesByRepositoryIdResponses, GetBucketedIncidentsData, GetBucketedIncidentsErrors, GetBucketedIncidentsResponses, GetBucketedStatusData, GetBucketedStatusErrors, GetBucketedStatusResponses, GetChallengeTokenData, GetChallengeTokenErrors, GetChallengeTokenResponses, GetChatReadinessData, GetChatReadinessErrors, GetChatReadinessResponses, GetCliStatusData, GetCliStatusErrors, GetCliStatusResponses, GetCloudCapabilityData, GetCloudCapabilityResponses, GetCloudStatusData, GetCloudStatusResponses, GetClusterHealthData, GetClusterHealthErrors, GetClusterHealthResponses, GetClusterMemberData, GetClusterMemberErrors, GetClusterMemberResponses, GetCmdData, GetCmdErrors, GetCmdResponses, GetContainerDetailData, GetContainerDetailErrors, GetContainerDetailResponses, GetContainerEnvironmentVariableData, GetContainerEnvironmentVariableErrors, GetContainerEnvironmentVariableResponses, GetContainerInfoData, GetContainerInfoErrors, GetContainerInfoResponses, GetContainerLogsByIdData, GetContainerLogsByIdErrors, GetContainerLogsData, GetContainerLogsErrors, GetContainerMetricsData, GetContainerMetricsErrors, GetContainerMetricsResponses, GetConversationData, GetConversationDetailData, GetConversationDetailErrors, GetConversationDetailResponses, GetConversationErrors, GetConversationResponses, GetConversationsData, GetConversationsErrors, GetConversationsResponses, GetCronByIdData, GetCronByIdErrors, GetCronByIdResponses, GetCronExecutionsData, GetCronExecutionsErrors, GetCronExecutionsResponses, GetCrossProjectTraceSiblingsData, GetCrossProjectTraceSiblingsErrors, GetCrossProjectTraceSiblingsResponses, GetCurrentMonitorStatusData, GetCurrentMonitorStatusErrors, GetCurrentMonitorStatusResponses, GetCurrentUserData, GetCurrentUserErrors, GetCurrentUserResponses, GetCustomDomainData, GetCustomDomainErrors, GetCustomDomainResponses, GetDashboardData, GetDashboardErrors, GetDashboardProjectsAnalyticsData, GetDashboardProjectsAnalyticsErrors, GetDashboardProjectsAnalyticsResponses, GetDashboardResponses, GetDeliveryData, GetDeliveryErrors, GetDeliveryResponses, GetDeploymentContainerLogContentData, GetDeploymentContainerLogContentErrors, GetDeploymentContainerLogContentResponses, GetDeploymentData, GetDeploymentErrors, GetDeploymentJobLogsData, GetDeploymentJobLogsErrors, GetDeploymentJobLogsResponses, GetDeploymentJobsData, GetDeploymentJobsErrors, GetDeploymentJobsResponses, GetDeploymentOperationsData, GetDeploymentOperationsErrors, GetDeploymentOperationsResponses, GetDeploymentOperationStatusData, GetDeploymentOperationStatusErrors, GetDeploymentOperationStatusResponses, GetDeploymentResponses, GetDeploymentTokenData, GetDeploymentTokenErrors, GetDeploymentTokenResponses, GetDiskStatusData, GetDiskStatusErrors, GetDiskStatusResponses, GetDnsChangesData, GetDnsChangesErrors, GetDnsChangesResponses, GetDnsProviderData, GetDnsProviderErrors, GetDnsProviderResponses, GetDomainByHostData, GetDomainByHostErrors, GetDomainByHostResponses, GetDomainByIdData, GetDomainByIdErrors, GetDomainByIdResponses, GetDomainByNameData, GetDomainByNameErrors, GetDomainByNameResponses, GetDomainData, GetDomainDnsRecordsData, GetDomainDnsRecordsErrors, GetDomainDnsRecordsResponses, GetDomainErrors, GetDomainOrderData, GetDomainOrderErrors, GetDomainOrderResponses, GetDomainResponses, GetEmailData, GetEmailErrors, GetEmailEventsData, GetEmailEventsErrors, GetEmailEventsResponses, GetEmailLinksData, GetEmailLinksErrors, GetEmailLinksResponses, GetEmailProviderData, GetEmailProviderErrors, GetEmailProviderResponses, GetEmailResponses, GetEmailStatsData, GetEmailStatsErrors, GetEmailStatsResponses, GetEmailTrackingData, GetEmailTrackingErrors, GetEmailTrackingResponses, GetEmailTrackingStatusData, GetEmailTrackingStatusErrors, GetEmailTrackingStatusResponses, GetEntityInfoData, GetEntityInfoErrors, GetEntityInfoResponses, GetEnvironmentCronsData, GetEnvironmentCronsErrors, GetEnvironmentCronsResponses, GetEnvironmentData, GetEnvironmentDomainsData, GetEnvironmentDomainsErrors, GetEnvironmentDomainsResponses, GetEnvironmentErrors, GetEnvironmentResponses, GetEnvironmentsData, GetEnvironmentsErrors, GetEnvironmentsResponses, GetEnvironmentVariablesData, GetEnvironmentVariablesErrors, GetEnvironmentVariablesResponses, GetEnvironmentVariableValueData, GetEnvironmentVariableValueErrors, GetEnvironmentVariableValueResponses, GetErrorDashboardStatsData, GetErrorDashboardStatsErrors, GetErrorDashboardStatsResponses, GetErrorEventData, GetErrorEventErrors, GetErrorEventResponses, GetErrorGroupData, GetErrorGroupErrors, GetErrorGroupResponses, GetErrorStatsData, GetErrorStatsErrors, GetErrorStatsResponses, GetErrorTimeSeriesData, GetErrorTimeSeriesErrors, GetErrorTimeSeriesResponses, GetEventDetailData, GetEventDetailErrors, GetEventDetailResponses, GetEventEntriesData, GetEventEntriesErrors, GetEventEntriesResponses, GetEventsCountData, GetEventsCountErrors, GetEventsCountResponses, GetEventsTimelineData, GetEventsTimelineErrors, GetEventsTimelineResponses, GetEventTypeBreakdownData, GetEventTypeBreakdownErrors, GetEventTypeBreakdownResponses, GetEventVisitorsData, GetEventVisitorsErrors, GetEventVisitorsResponses, GetExternalImageData, GetExternalImageErrors, GetExternalImageResponses, GetFileData, GetFileErrors, GetFileResponses, GetFlagData, GetFlagErrors, GetFlagResponses, GetFlagSnapshotData, GetFlagSnapshotErrors, GetFlagSnapshotResponses, GetFunnelMetricsData, GetFunnelMetricsErrors, GetFunnelMetricsResponses, GetGenaiTraceData, GetGenaiTraceErrors, GetGenaiTraceResponses, GetGeneralStatsData, GetGeneralStatsErrors, GetGeneralStatsResponses, GetGitProviderData, GetGitProviderErrors, GetGitProviderResponses, GetGlobalEventsData, GetGlobalEventsErrors, GetGlobalEventsResponses, GetGlobalEventStatsData, GetGlobalEventStatsErrors, GetGlobalEventStatsResponses, GetGlobalMcpData, GetGlobalMcpErrors, GetGlobalMcpResponses, GetGlobalSandboxStatusData, GetGlobalSandboxStatusErrors, GetGlobalSandboxStatusResponses, GetGlobalSkillData, GetGlobalSkillErrors, GetGlobalSkillResponses, GetGroupedPageMetricsData, GetGroupedPageMetricsErrors, GetGroupedPageMetricsResponses, GetHealthData, GetHealthErrors, GetHealthResponses, GetHourlyVisitsData, GetHourlyVisitsErrors, GetHourlyVisitsResponses, GetHttpChallengeDebugData, GetHttpChallengeDebugErrors, GetHttpChallengeDebugResponses, GetImportStatusData, GetImportStatusErrors, GetImportStatusResponses, GetIncidentData, GetIncidentErrors, GetIncidentResponses, GetIncidentUpdatesData, GetIncidentUpdatesErrors, GetIncidentUpdatesResponses, GetIpAccessControlData, GetIpAccessControlErrors, GetIpAccessControlResponses, GetIpGeolocationData, GetIpGeolocationErrors, GetIpGeolocationResponses, GetJoinTokenStatusData, GetJoinTokenStatusErrors, GetJoinTokenStatusResponses, GetLastDeploymentData, GetLastDeploymentErrors, GetLastDeploymentResponses, GetLatestScanData, GetLatestScanErrors, GetLatestScanResponses, GetLatestScansPerEnvironmentData, GetLatestScansPerEnvironmentErrors, GetLatestScansPerEnvironmentResponses, GetLiveVisitorsListData, GetLiveVisitorsListErrors, GetLiveVisitorsListResponses, GetLogContextData, GetLogContextErrors, GetLogContextResponses, GetMcpData, GetMcpErrors, GetMcpResponses, GetMetricsOverTimeData, GetMetricsOverTimeErrors, GetMetricsOverTimeResponses, GetMonitorData, GetMonitorErrors, GetMonitorResponses, GetNotificationProviderData, GetNotificationProviderErrors, GetNotificationProviderResponses, GetOnDemandCertStatusData, GetOnDemandCertStatusErrors, GetOnDemandCertStatusResponses, GetOrCreateDsnData, GetOrCreateDsnErrors, GetOrCreateDsnResponses, GetPageFlowData, GetPageFlowErrors, GetPageFlowResponses, GetPageHourlySessionsData, GetPageHourlySessionsErrors, GetPageHourlySessionsResponses, GetPagePathDetailData, GetPagePathDetailErrors, GetPagePathDetailResponses, GetPagePathsData, GetPagePathsErrors, GetPagePathsResponses, GetPagePathsSparklinesData, GetPagePathsSparklinesErrors, GetPagePathsSparklinesResponses, GetPagePathVisitorsData, GetPagePathVisitorsErrors, GetPagePathVisitorsResponses, GetPendingActionData, GetPendingActionErrors, GetPendingActionResponses, GetPerformanceMetricsData, GetPerformanceMetricsErrors, GetPerformanceMetricsResponses, GetPgUpgradeData, GetPgUpgradeErrors, GetPgUpgradeLogsData, GetPgUpgradeLogsErrors, GetPgUpgradeLogsResponses, GetPgUpgradeResponses, GetPipelineStatsData, GetPipelineStatsErrors, GetPipelineStatsResponses, GetPlatformInfoData, GetPlatformInfoErrors, GetPlatformInfoResponses, GetPostgresWalHealthData, GetPostgresWalHealthErrors, GetPostgresWalHealthResponses, GetPreferencesData, GetPreferencesErrors, GetPreferencesResponses, GetPreviewGatewayLogsData, GetPreviewGatewayLogsResponses, GetPreviewGatewaySettingsData, GetPreviewGatewaySettingsResponses, GetPreviewGatewayStatusData, GetPreviewGatewayStatusResponses, GetPricingData, GetPricingErrors, GetPricingResponses, GetPrivateIpData, GetPrivateIpErrors, GetPrivateIpResponses, GetProjectAlarmsSummaryData, GetProjectAlarmsSummaryErrors, GetProjectAlarmsSummaryResponses, GetProjectBySlugData, GetProjectBySlugErrors, GetProjectBySlugResponses, GetProjectData, GetProjectDeploymentsData, GetProjectDeploymentsErrors, GetProjectDeploymentsResponses, GetProjectErrors, GetProjectResponses, GetProjectsData, GetProjectsErrors, GetProjectServiceEnvironmentVariablesData, GetProjectServiceEnvironmentVariablesErrors, GetProjectServiceEnvironmentVariablesResponses, GetProjectSessionReplaysData, GetProjectSessionReplaysErrors, GetProjectSessionReplaysResponses, GetProjectsHealthData, GetProjectsHealthErrors, GetProjectsHealthResponses, GetProjectsMonitorHealthData, GetProjectsMonitorHealthErrors, GetProjectsMonitorHealthResponses, GetProjectsResponses, GetProjectStatisticsData, GetProjectStatisticsErrors, GetProjectStatisticsResponses, GetProjectTemplateData, GetProjectTemplateErrors, GetProjectTemplateResponses, GetPropertyBreakdownData, GetPropertyBreakdownErrors, GetPropertyBreakdownResponses, GetPropertyTimelineData, GetPropertyTimelineErrors, GetPropertyTimelineResponses, GetProviderConnectionsData, GetProviderConnectionsErrors, GetProviderConnectionsResponses, GetProviderMetadataData, GetProviderMetadataErrors, GetProviderMetadataResponses, GetProvidersMetadataData, GetProvidersMetadataErrors, GetProvidersMetadataResponses, GetProxyLogByIdData, GetProxyLogByIdErrors, GetProxyLogByIdResponses, GetProxyLogByRequestIdData, GetProxyLogByRequestIdErrors, GetProxyLogByRequestIdResponses, GetProxyLogsData, GetProxyLogsErrors, GetProxyLogsResponses, GetPublicBranchesData, GetPublicBranchesErrors, GetPublicBranchesResponses, GetPublicIpData, GetPublicIpErrors, GetPublicIpResponses, GetPublicRepositoryData, GetPublicRepositoryErrors, GetPublicRepositoryResponses, GetQuotaData, GetQuotaErrors, GetQuotaResponses, GetRecentActivityData, GetRecentActivityErrors, GetRecentActivityResponses, GetRemoteExternalImageData, GetRemoteExternalImageErrors, GetRemoteExternalImageResponses, GetRepositoryBranchesData, GetRepositoryBranchesErrors, GetRepositoryBranchesResponses, GetRepositoryByIdData, GetRepositoryByIdErrors, GetRepositoryByIdResponses, GetRepositoryByNameData, GetRepositoryByNameErrors, GetRepositoryByNameResponses, GetRepositoryPresetByNameData, GetRepositoryPresetByNameErrors, GetRepositoryPresetByNameResponses, GetRepositoryPresetLiveData, GetRepositoryPresetLiveErrors, GetRepositoryPresetLiveResponses, GetRepositoryTagsData, GetRepositoryTagsErrors, GetRepositoryTagsResponses, GetResolvedEnvironmentVariablesData, GetResolvedEnvironmentVariablesErrors, GetResolvedEnvironmentVariablesResponses, GetResolvedEnvironmentVariableValueData, GetResolvedEnvironmentVariableValueErrors, GetResolvedEnvironmentVariableValueResponses, GetRestoreCapabilitiesData, GetRestoreCapabilitiesErrors, GetRestoreCapabilitiesResponses, GetRestoreRunData, GetRestoreRunErrors, GetRestoreRunResponses, GetRouteData, GetRouteErrors, GetRouteResponses, GetRunData, GetRunErrors, GetRunResponses, GetRunWithLogsData, GetRunWithLogsErrors, GetRunWithLogsResponses, GetS3CredentialsData, GetS3CredentialsErrors, GetS3CredentialsResponses, GetS3SourceData, GetS3SourceErrors, GetS3SourceResponses, GetSandboxData, GetSandboxErrors, GetSandboxResponses, GetSandboxStatusData, GetSandboxStatusErrors, GetSandboxStatusResponses, GetScanByDeploymentData, GetScanByDeploymentErrors, GetScanByDeploymentResponses, GetScanData, GetScanErrors, GetScanResponses, GetScanVulnerabilitiesData, GetScanVulnerabilitiesErrors, GetScanVulnerabilitiesResponses, GetServiceBySlugData, GetServiceBySlugErrors, GetServiceBySlugResponses, GetServiceData, GetServiceEnvironmentVariableData, GetServiceEnvironmentVariableErrors, GetServiceEnvironmentVariableResponses, GetServiceEnvironmentVariablesData, GetServiceEnvironmentVariablesErrors, GetServiceEnvironmentVariablesResponses, GetServiceErrors, GetServiceHealthStatusData, GetServiceHealthStatusErrors, GetServiceHealthStatusResponses, GetServicePreviewEnvironmentVariableNamesData, GetServicePreviewEnvironmentVariableNamesErrors, GetServicePreviewEnvironmentVariableNamesResponses, GetServicePreviewEnvironmentVariablesMaskedData, GetServicePreviewEnvironmentVariablesMaskedErrors, GetServicePreviewEnvironmentVariablesMaskedResponses, GetServiceResponses, GetServiceRuntimeData, GetServiceRuntimeErrors, GetServiceRuntimeResponses, GetServiceStatsData, GetServiceStatsErrors, GetServiceStatsResponses, GetServiceTypeParametersData, GetServiceTypeParametersErrors, GetServiceTypeParametersResponses, GetServiceTypesData, GetServiceTypesErrors, GetServiceTypesResponses, GetSessionDetailsData, GetSessionDetailsErrors, GetSessionDetailsResponses, GetSessionEventsData, GetSessionEventsErrors, GetSessionEventsResponses, GetSessionLogsData, GetSessionLogsErrors, GetSessionLogsResponses, GetSessionReplayData, GetSessionReplayErrors, GetSessionReplayEventsData, GetSessionReplayEventsErrors, GetSessionReplayEventsResponses, GetSessionReplayResponses, GetSettingsData, GetSettingsErrors, GetSettingsResponses, GetSkillData, GetSkillErrors, GetSkillResponses, GetSlowQueriesData, GetSlowQueriesErrors, GetSlowQueriesResponses, GetStaticBundleData, GetStaticBundleErrors, GetStaticBundleResponses, GetStatusOverviewData, GetStatusOverviewErrors, GetStatusOverviewResponses, GetTagsByRepositoryIdData, GetTagsByRepositoryIdErrors, GetTagsByRepositoryIdResponses, GetTeamData, GetTeamErrors, GetTeamResponses, GetTimeBucketStatsData, GetTimeBucketStatsErrors, GetTimeBucketStatsResponses, GetTodayStatsData, GetTodayStatsErrors, GetTodayStatsResponses, GetTraceData, GetTraceErrors, GetTraceResponses, GetUnifiedTraceData, GetUnifiedTraceErrors, GetUnifiedTraceResponses, GetUniqueCountsData, GetUniqueCountsErrors, GetUniqueCountsResponses, GetUniqueEventsData, GetUniqueEventsErrors, GetUniqueEventsResponses, GetUpdateStatusData, GetUpdateStatusErrors, GetUpdateStatusResponses, GetUptimeHistoryData, GetUptimeHistoryErrors, GetUptimeHistoryResponses, GetUsageByProviderData, GetUsageByProviderErrors, GetUsageByProviderResponses, GetUsageRecentData, GetUsageRecentErrors, GetUsageRecentResponses, GetUsageSummaryData, GetUsageSummaryErrors, GetUsageSummaryResponses, GetUsageTimeseriesData, GetUsageTimeseriesErrors, GetUsageTimeseriesResponses, GetUsageTopModelsData, GetUsageTopModelsErrors, GetUsageTopModelsResponses, GetVisitorByGuidData, GetVisitorByGuidErrors, GetVisitorByGuidResponses, GetVisitorByIdData, GetVisitorByIdErrors, GetVisitorByIdResponses, GetVisitorDetailsData, GetVisitorDetailsErrors, GetVisitorDetailsResponses, GetVisitorFacetsData, GetVisitorFacetsErrors, GetVisitorFacetsResponses, GetVisitorInfoData, GetVisitorInfoErrors, GetVisitorInfoResponses, GetVisitorJourneyData, GetVisitorJourneyErrors, GetVisitorJourneyResponses, GetVisitorsData, GetVisitorsErrors, GetVisitorSessionsData, GetVisitorSessionsErrors, GetVisitorSessionsResponses, GetVisitorsResponses, GetVisitorStatsData, GetVisitorStatsErrors, GetVisitorStatsResponses, GetWebhookData, GetWebhookErrors, GetWebhookResponses, GrantProjectAccessData, GrantProjectAccessErrors, GrantProjectAccessResponses, HandleGitProviderOauthCallbackData, HandleGitProviderOauthCallbackErrors, HasAnalyticsEventsData, HasAnalyticsEventsErrors, HasAnalyticsEventsResponses, HasErrorGroupsData, HasErrorGroupsErrors, HasErrorGroupsResponses, HasPerformanceMetricsData, HasPerformanceMetricsErrors, HasPerformanceMetricsResponses, ImportExternalServiceData, ImportExternalServiceErrors, ImportExternalServiceResponses, IngestLogsByPathData, IngestLogsByPathErrors, IngestLogsByPathResponses, IngestLogsData, IngestLogsErrors, IngestLogsResponses, IngestMetricsByPathData, IngestMetricsByPathErrors, IngestMetricsByPathResponses, IngestMetricsData, IngestMetricsErrors, IngestMetricsResponses, IngestSentryEnvelopeData, IngestSentryEnvelopeErrors, IngestSentryEnvelopeResponses, IngestSentryEventData, IngestSentryEventErrors, IngestSentryEventResponses, IngestTracesByPathData, IngestTracesByPathErrors, IngestTracesByPathResponses, IngestTracesData, IngestTracesErrors, IngestTracesResponses, InitSessionReplayData, InitSessionReplayErrors, InitSessionReplayResponses, InspectDropArchiveData, InspectDropArchiveErrors, InspectDropArchiveResponses, JobLogsData, JobLogsErrors, JobLogsResponses, JobStatusData, JobStatusErrors, JobStatusResponses, KillJobData, KillJobErrors, KillJobResponses, KvDelData, KvDelErrors, KvDelResponses, KvDisableData, KvDisableErrors, KvDisableResponses, KvEnableData, KvEnableErrors, KvEnableResponses, KvExpireData, KvExpireErrors, KvExpireResponses, KvGetData, KvGetErrors, KvGetResponses, KvIncrData, KvIncrErrors, KvIncrResponses, KvKeysData, KvKeysErrors, KvKeysResponses, KvSetData, KvSetErrors, KvSetResponses, KvStatusData, KvStatusErrors, KvStatusResponses, KvTtlData, KvTtlErrors, KvTtlResponses, KvUpdateData, KvUpdateErrors, KvUpdateResponses, LatestRunForSourceData, LatestRunForSourceErrors, LatestRunForSourceResponses, LinkCustomDomainToCertificateData, LinkCustomDomainToCertificateErrors, LinkCustomDomainToCertificateResponses, LinkServiceToProjectData, LinkServiceToProjectErrors, LinkServiceToProjectResponses, ListAgentRunsData, ListAgentRunsErrors, ListAgentRunsResponses, ListAgentsData, ListAgentsErrors, ListAgentsResponses, ListAiProvidersData, ListAiProvidersErrors, ListAiProvidersResponses, ListAlertRulesData, ListAlertRulesErrors, ListAlertRulesResponses, ListAlertsData, ListAlertsErrors, ListAlertsResponses, ListAllConversationsData, ListAllConversationsErrors, ListAllConversationsResponses, ListAllRunsData, ListAllRunsErrors, ListAllRunsResponses, ListApiKeysData, ListApiKeysErrors, ListApiKeysResponses, ListAuditLogsData, ListAuditLogsErrors, ListAuditLogsResponses, ListAvailableContainersData, ListAvailableContainersErrors, ListAvailableContainersResponses, ListBackupAlertsData, ListBackupAlertsErrors, ListBackupAlertsResponses, ListBackupChildrenData, ListBackupChildrenErrors, ListBackupChildrenResponses, ListBackupSchedulesData, ListBackupSchedulesErrors, ListBackupSchedulesResponses, ListBackupsForScheduleData, ListBackupsForScheduleErrors, ListBackupsForScheduleResponses, ListCommitsByRepositoryIdData, ListCommitsByRepositoryIdErrors, ListCommitsByRepositoryIdResponses, ListConnectionsData, ListConnectionsErrors, ListConnectionsResponses, ListContainersAtPathData, ListContainersAtPathErrors, ListContainersAtPathResponses, ListContainersData, ListContainersErrors, ListContainersResponses, ListConversationsData, ListConversationsErrors, ListConversationsResponses, ListCustomDomainsForProjectData, ListCustomDomainsForProjectErrors, ListCustomDomainsForProjectResponses, ListDashboardsData, ListDashboardsErrors, ListDashboardsResponses, ListDeliveriesData, ListDeliveriesErrors, ListDeliveriesResponses, ListDeploymentContainerLogsData, ListDeploymentContainerLogsErrors, ListDeploymentContainerLogsResponses, ListDeploymentTokensData, ListDeploymentTokensErrors, ListDeploymentTokensResponses, ListDnsProvidersData, ListDnsProvidersErrors, ListDnsProvidersResponses, ListDomainsData, ListDomainsErrors, ListDomainsResponses, ListDsnsData, ListDsnsErrors, ListDsnsResponses, ListEmailDomainsData, ListEmailDomainsErrors, ListEmailDomainsResponses, ListEmailProvidersData, ListEmailProvidersErrors, ListEmailProvidersResponses, ListEmailsData, ListEmailsErrors, ListEmailsResponses, ListEnrollmentTokensData, ListEnrollmentTokensErrors, ListEnrollmentTokensResponses, ListEntitiesData, ListEntitiesErrors, ListEntitiesResponses, ListErrorEventsData, ListErrorEventsErrors, ListErrorEventsResponses, ListErrorGroupsData, ListErrorGroupsErrors, ListErrorGroupsResponses, ListEventsData, ListEventsResponses, ListEventTypesData, ListEventTypesResponses, ListExternalImagesData, ListExternalImagesErrors, ListExternalImagesResponses, ListExternalPluginsData, ListExternalPluginsErrors, ListExternalPluginsResponses, ListExternalServiceBackupsData, ListExternalServiceBackupsErrors, ListExternalServiceBackupsResponses, ListFlagsData, ListFlagsErrors, ListFlagsResponses, ListFunnelsData, ListFunnelsErrors, ListFunnelsResponses, ListGitProvidersData, ListGitProvidersErrors, ListGitProvidersResponses, ListGlobalMcpsData, ListGlobalMcpsErrors, ListGlobalMcpsResponses, ListGlobalSkillsData, ListGlobalSkillsErrors, ListGlobalSkillsResponses, ListIncidentsData, ListIncidentsErrors, ListIncidentsResponses, ListInsightsData, ListInsightsErrors, ListInsightsResponses, ListIpAccessControlData, ListIpAccessControlErrors, ListIpAccessControlResponses, ListJobsData, ListJobsErrors, ListJobsResponses, ListKnownAiAgentsData, ListKnownAiAgentsErrors, ListKnownAiAgentsResponses, ListManagedDomainsData, ListManagedDomainsErrors, ListManagedDomainsResponses, ListMcpsData, ListMcpsErrors, ListMcpsResponses, ListMetricLabelKeysData, ListMetricLabelKeysErrors, ListMetricLabelKeysResponses, ListMetricLabelValuesData, ListMetricLabelValuesErrors, ListMetricLabelValuesResponses, ListMetricNamesData, ListMetricNamesErrors, ListMetricNamesResponses, ListModelsData, ListModelsErrors, ListModelsResponses, ListMonitorsData, ListMonitorsErrors, ListMonitorsResponses, ListNotificationProvidersData, ListNotificationProvidersErrors, ListNotificationProvidersResponses, ListOidcProvidersData, ListOidcProvidersResponses, ListOidcProviderUsersData, ListOidcProviderUsersErrors, ListOidcProviderUsersResponses, ListOidcRoleMappingsData, ListOidcRoleMappingsResponses, ListOnDemandCertsData, ListOnDemandCertsErrors, ListOnDemandCertsResponses, ListOrdersData, ListOrdersErrors, ListOrdersResponses, ListPeersData, ListPeersErrors, ListPeersResponses, ListPendingActionsData, ListPendingActionsErrors, ListPendingActionsResponses, ListPgUpgradesData, ListPgUpgradesErrors, ListPgUpgradesResponses, ListPresetsData, ListPresetsErrors, ListPresetsResponses, ListProjectAccessData, ListProjectAccessErrors, ListProjectAccessResponses, ListProjectAlarmsData, ListProjectAlarmsErrors, ListProjectAlarmsResponses, ListProjectScansData, ListProjectScansErrors, ListProjectScansResponses, ListProjectSecretsData, ListProjectSecretsErrors, ListProjectSecretsResponses, ListProjectServicesData, ListProjectServicesErrors, ListProjectServicesResponses, ListProjectTemplatesData, ListProjectTemplatesErrors, ListProjectTemplatesResponses, ListProjectTemplateTagsData, ListProjectTemplateTagsErrors, ListProjectTemplateTagsResponses, ListProviderKeysData, ListProviderKeysErrors, ListProviderKeysResponses, ListProviderZonesData, ListProviderZonesErrors, ListProviderZonesResponses, ListPublicProvidersData, ListPublicProvidersResponses, ListReleaseFilesData, ListReleaseFilesErrors, ListReleaseFilesResponses, ListReleasesData, ListReleasesErrors, ListReleasesResponses, ListRemoteExternalImagesData, ListRemoteExternalImagesErrors, ListRemoteExternalImagesResponses, ListRepositoriesByConnectionData, ListRepositoriesByConnectionErrors, ListRepositoriesByConnectionResponses, ListRepositoriesByProviderData, ListRepositoriesByProviderErrors, ListRepositoriesByProviderResponses, ListRestoreRunsForServiceData, ListRestoreRunsForServiceResponses, ListRootContainersData, ListRootContainersErrors, ListRootContainersResponses, ListRoutesData, ListRoutesErrors, ListRoutesResponses, ListS3SourcesData, ListS3SourcesErrors, ListS3SourcesResponses, ListSandboxesData, ListSandboxesResponses, ListScheduleRunJobsData, ListScheduleRunJobsErrors, ListScheduleRunJobsResponses, ListScheduleRunsData, ListScheduleRunsErrors, ListScheduleRunsResponses, ListScheduleServicesData, ListScheduleServicesErrors, ListScheduleServicesResponses, ListSecretsData, ListSecretsErrors, ListSecretsResponses, ListServiceHealthStatusesData, ListServiceHealthStatusesErrors, ListServiceHealthStatusesResponses, ListServiceProjectsData, ListServiceProjectsErrors, ListServiceProjectsResponses, ListServiceSchedulesData, ListServiceSchedulesErrors, ListServiceSchedulesResponses, ListServicesData, ListServicesErrors, ListServicesResponses, ListSkillsData, ListSkillsErrors, ListSkillsResponses, ListSourceBackupsData, ListSourceBackupsErrors, ListSourceBackupsResponses, ListSourceFilesData, ListSourceFilesErrors, ListSourceFilesResponses, ListSourceMapsData, ListSourceMapsErrors, ListSourceMapsResponses, ListSourcesData, ListSourcesErrors, ListSourcesResponses, ListStaticBundlesData, ListStaticBundlesErrors, ListStaticBundlesResponses, ListSyncedRepositoriesData, ListSyncedRepositoriesErrors, ListSyncedRepositoriesResponses, ListTeamMembersData, ListTeamMembersErrors, ListTeamMembersResponses, ListTeamProjectsData, ListTeamProjectsErrors, ListTeamProjectsResponses, ListTeamsData, ListTeamsErrors, ListTeamsResponses, ListUsersData, ListUsersErrors, ListUsersResponses, ListWebhooksData, ListWebhooksErrors, ListWebhooksResponses, LoginData, LoginErrors, LoginResponses, LogoutData, LogoutErrors, LogoutResponses, LookupDnsARecordsData, LookupDnsARecordsErrors, LookupDnsARecordsResponses, MintEnrollmentTokenData, MintEnrollmentTokenErrors, MintEnrollmentTokenResponses, MkdirData, MkdirErrors, MkdirResponses, NodeHeartbeatData, NodeHeartbeatErrors, NodeHeartbeatResponses, NodeMetricsGetRangeData, NodeMetricsGetRangeErrors, NodeMetricsGetRangeResponses, ObservabilityFullEventData, ObservabilityFullEventErrors, ObservabilityFullEventResponses, ObservabilityListEventsData, ObservabilityListEventsErrors, ObservabilityListEventsResponses, OidcCallbackData, PatchAdminGateData, PatchAdminGateErrors, PatchAdminGateResponses, PatchPreviewGatewaySettingsData, PatchPreviewGatewaySettingsResponses, PauseDeploymentData, PauseDeploymentErrors, PauseDeploymentResponses, PauseSandboxData, PauseSandboxErrors, PauseSandboxResponses, PlanRestoreData, PlanRestoreErrors, PlanRestoreResponses, PostDnsAckData, PostDnsAckErrors, PostDnsAckResponses, PreviewAlertData, PreviewAlertErrors, PreviewAlertResponses, PreviewFunnelMetricsData, PreviewFunnelMetricsErrors, PreviewFunnelMetricsResponses, PreviewHostnameModeData, PreviewHostnameModeErrors, PreviewHostnameModeResponses, PromoteClusterMemberData, PromoteClusterMemberErrors, PromoteClusterMemberResponses, PromoteDeploymentData, PromoteDeploymentErrors, PromoteDeploymentResponses, ProvisionDomainData, ProvisionDomainErrors, ProvisionDomainResponses, PurgeProjectLogsData, PurgeProjectLogsErrors, PurgeProjectLogsResponses, PushExternalImageData, PushExternalImageErrors, PushExternalImageResponses, QueryDataData, QueryDataErrors, QueryDataResponses, QueryGenaiTracesData, QueryGenaiTracesErrors, QueryGenaiTracesResponses, QueryLogsData, QueryLogsErrors, QueryLogsResponses, QueryMetricsData, QueryMetricsErrors, QueryMetricsResponses, QueryTracesData, QueryTracesErrors, QueryTracesResponses, QueryTraceSummariesData, QueryTraceSummariesErrors, QueryTraceSummariesResponses, ReadFileData, ReadFileErrors, ReadFileResponses, ReAnalyzeData, ReAnalyzeErrors, ReAnalyzeResponses, RecordConsoleEventData, RecordConsoleEventErrors, RecordConsoleEventResponses, RecordEventMetricsData, RecordEventMetricsErrors, RecordEventMetricsResponses, RecordFlagExposureData, RecordFlagExposureErrors, RecordFlagExposureResponses, RecordSpeedMetricsData, RecordSpeedMetricsErrors, RecordSpeedMetricsResponses, RefreshRouteTableData, RefreshRouteTableErrors, RefreshRouteTableResponses, RegenerateDsnData, RegenerateDsnErrors, RegenerateDsnResponses, RegisterExternalImageData, RegisterExternalImageErrors, RegisterExternalImageResponses, RegisterNodeData, RegisterNodeErrors, RegisterNodeResponses, ReinstallGitlabWebhookData, ReinstallGitlabWebhookErrors, ReinstallGitlabWebhookResponses, RejectPendingActionData, RejectPendingActionErrors, RejectPendingActionResponses, ReloadPluginsData, ReloadPluginsErrors, ReloadPluginsResponses, RemoveClusterMemberData, RemoveClusterMemberErrors, RemoveClusterMemberResponses, RemoveManagedDomainData, RemoveManagedDomainErrors, RemoveManagedDomainResponses, RemoveRoleData, RemoveRoleErrors, RemoveRoleResponses, RemoveTeamMemberData, RemoveTeamMemberErrors, RemoveTeamMemberResponses, RenameConversationData, RenameConversationErrors, RenameConversationResponses, RenewDomainData, RenewDomainErrors, RenewDomainResponses, RequestPasswordResetData, RequestPasswordResetErrors, RequestPasswordResetResponses, ResetPasswordData, ResetPasswordErrors, ResetPasswordResponses, ResizeSandboxData, ResizeSandboxErrors, ResizeSandboxResponses, ResolveAlarmData, ResolveAlarmErrors, ResolveAlarmResponses, RestartContainerData, RestartContainerErrors, RestartContainerResponses, RestartPreviewGatewayData, RestartPreviewGatewayResponses, RestartSandboxData, RestartSandboxErrors, RestartSandboxResponses, RestoreFlagData, RestoreFlagErrors, RestoreFlagResponses, RestoreUserData, RestoreUserErrors, RestoreUserResponses, ResumeDeploymentData, ResumeDeploymentErrors, ResumeDeploymentResponses, ResumeSandboxData, ResumeSandboxErrors, ResumeSandboxResponses, RetryClusterData, RetryClusterErrors, RetryClusterResponses, RetryDeliveryData, RetryDeliveryErrors, RetryDeliveryResponses, RetryPgUpgradeData, RetryPgUpgradeErrors, RetryPgUpgradeResponses, RetryRunData, RetryRunErrors, RetryRunResponses, RevealGlobalMcpConfigData, RevealGlobalMcpConfigErrors, RevealGlobalMcpConfigResponses, RevealMcpConfigData, RevealMcpConfigErrors, RevealMcpConfigResponses, RevealNotificationProviderConfigData, RevealNotificationProviderConfigErrors, RevealNotificationProviderConfigResponses, RevealServiceParameterData, RevealServiceParameterErrors, RevealServiceParameterResponses, RevenueCreateIntegrationData, RevenueCreateIntegrationErrors, RevenueCreateIntegrationResponses, RevenueDeleteIntegrationData, RevenueDeleteIntegrationResponses, RevenueGlobalEventsData, RevenueGlobalEventsResponses, RevenueImportInvoicesCsvData, RevenueImportInvoicesCsvErrors, RevenueImportInvoicesCsvResponses, RevenueImportSubscriptionsCsvData, RevenueImportSubscriptionsCsvErrors, RevenueImportSubscriptionsCsvResponses, RevenueListIntegrationsData, RevenueListIntegrationsResponses, RevenueListProvidersData, RevenueListProvidersResponses, RevenueMetricsCustomersData, RevenueMetricsCustomersResponses, RevenueMetricsGlobalMrrData, RevenueMetricsGlobalMrrResponses, RevenueMetricsGlobalSummaryData, RevenueMetricsGlobalSummaryResponses, RevenueMetricsMrrData, RevenueMetricsMrrResponses, RevenueMetricsSummaryData, RevenueMetricsSummaryResponses, RevenueRecentEventsData, RevenueRecentEventsResponses, RevenueRotateTokenData, RevenueRotateTokenResponses, RevenueUpdateConfigData, RevenueUpdateConfigErrors, RevenueUpdateConfigResponses, RevenueUpdateSecretData, RevenueUpdateSecretErrors, RevenueUpdateSecretResponses, RevokeDsnData, RevokeDsnErrors, RevokeDsnResponses, RevokeEnrollmentTokenData, RevokeEnrollmentTokenErrors, RevokeEnrollmentTokenResponses, RevokeJoinTokenData, RevokeJoinTokenErrors, RevokeJoinTokenResponses, RevokeProjectAccessData, RevokeProjectAccessErrors, RevokeProjectAccessResponses, RollbackPgUpgradeData, RollbackPgUpgradeErrors, RollbackPgUpgradeResponses, RollbackToDeploymentData, RollbackToDeploymentErrors, RollbackToDeploymentResponses, RootfsGcData, RootfsGcResponses, RootfsReportData, RootfsReportResponses, RotateApiKeyData, RotateApiKeyErrors, RotateApiKeyResponses, RotateDeploymentTokenData, RotateDeploymentTokenErrors, RotateDeploymentTokenResponses, RunBackupForSourceData, RunBackupForSourceErrors, RunBackupForSourceResponses, RunConnectionHealthCheckData, RunConnectionHealthCheckErrors, RunConnectionHealthCheckResponses, RunExternalServiceBackupData, RunExternalServiceBackupErrors, RunExternalServiceBackupResponses, RunScheduleNowData, RunScheduleNowErrors, RunScheduleNowResponses, SandboxCreatePreviewLinkData, SandboxCreatePreviewLinkErrors, SandboxCreatePreviewLinkResponses, SaveAgentTokenData, SaveAgentTokenErrors, SaveAgentTokenResponses, SaveAiProviderCredentialData, SaveAiProviderCredentialErrors, SaveAiProviderCredentialResponses, SearchLogsData, SearchLogsErrors, SearchLogsResponses, SendEmailData, SendEmailErrors, SendEmailResponses, SetDefaultS3SourceData, SetDefaultS3SourceErrors, SetDefaultS3SourceResponses, SetFlagEnvironmentData, SetFlagEnvironmentErrors, SetFlagEnvironmentResponses, SetPreviewPasswordData, SetPreviewPasswordErrors, SetPreviewPasswordResponses, SetupDnsChallengeData, SetupDnsChallengeErrors, SetupDnsChallengeResponses, SetupDnsData, SetupDnsErrors, SetupDnsResponses, SetupEmailTrackingData, SetupEmailTrackingErrors, SetupEmailTrackingResponses, SetupMfaData, SetupMfaErrors, SetupMfaResponses, SleepEnvironmentData, SleepEnvironmentErrors, SleepEnvironmentResponses, SmokeTestAgentData, SmokeTestAgentErrors, SmokeTestAgentResponses, SourceSandboxData, SourceSandboxErrors, SourceSandboxResponses, StartAnalysisData, StartAnalysisErrors, StartAnalysisResponses, StartContainerData, StartContainerErrors, StartContainerResponses, StartFixData, StartFixErrors, StartFixResponses, StartGitProviderOauthData, StartGitProviderOauthErrors, StartOidcLoginBySlugData, StartOidcLoginBySlugErrors, StartPgUpgradeData, StartPgUpgradeErrors, StartPgUpgradeResponses, StartRestoreData, StartRestoreErrors, StartRestoreResponses, StartServiceData, StartServiceErrors, StartServiceResponses, StatPathData, StatPathErrors, StatPathResponses, StopContainerData, StopContainerErrors, StopContainerResponses, StopSandboxData, StopSandboxErrors, StopSandboxResponses, StopServiceData, StopServiceErrors, StopServiceResponses, StreamContainerMetricsData, StreamContainerMetricsErrors, StreamContainerMetricsResponses, StreamEventsData, StreamEventsErrors, StreamEventsResponses, StreamRunEventsData, StreamRunEventsErrors, StreamRunEventsResponses, SyncRepositoriesData, SyncRepositoriesErrors, SyncRepositoriesResponses, TailDeploymentJobLogsData, TailDeploymentJobLogsErrors, TailLogsData, TailLogsErrors, TailLogsResponses, TeardownDeploymentData, TeardownDeploymentErrors, TeardownDeploymentResponses, TeardownEnvironmentData, TeardownEnvironmentErrors, TeardownEnvironmentResponses, TestNotificationProviderData, TestNotificationProviderErrors, TestNotificationProviderResponses, TestOidcProviderData, TestOidcProviderResponses, TestProviderConnectionData, TestProviderConnectionErrors, TestProviderConnectionResponses, TestProviderData, TestProviderErrors, TestProviderKeyByIdData, TestProviderKeyByIdErrors, TestProviderKeyByIdResponses, TestProviderKeyInlineData, TestProviderKeyInlineErrors, TestProviderKeyInlineResponses, TestProviderResponses, TestS3ConnectionPreviewData, TestS3ConnectionPreviewErrors, TestS3ConnectionPreviewResponses, TestS3SourceConnectionData, TestS3SourceConnectionErrors, TestS3SourceConnectionResponses, TrackClickData, TrackClickErrors, TrackOpenData, TrackOpenErrors, TrackOpenResponses, TriggerAgentData, TriggerAgentErrors, TriggerAgentResponses, TriggerProjectPipelineData, TriggerProjectPipelineErrors, TriggerProjectPipelineResponses, TriggerScanData, TriggerScanErrors, TriggerScanResponses, TriggerServiceHealthCheckData, TriggerServiceHealthCheckErrors, TriggerServiceHealthCheckResponses, TriggerWeeklyDigestData, TriggerWeeklyDigestErrors, TriggerWeeklyDigestResponses, UnlinkServiceFromProjectData, UnlinkServiceFromProjectErrors, UnlinkServiceFromProjectResponses, UpdateAgentData, UpdateAgentErrors, UpdateAgentResponses, UpdateAiProviderData, UpdateAiProviderErrors, UpdateAiProviderResponses, UpdateAlertData, UpdateAlertErrors, UpdateAlertResponses, UpdateAlertRuleData, UpdateAlertRuleErrors, UpdateAlertRuleResponses, UpdateApiKeyData, UpdateApiKeyErrors, UpdateApiKeyResponses, UpdateAutomaticDeployData, UpdateAutomaticDeployErrors, UpdateAutomaticDeployResponses, UpdateBackupScheduleData, UpdateBackupScheduleErrors, UpdateBackupScheduleResponses, UpdateCloudflareProviderData, UpdateCloudflareProviderErrors, UpdateCloudflareProviderResponses, UpdateConnectionTokenData, UpdateConnectionTokenErrors, UpdateConnectionTokenResponses, UpdateCustomDomainData, UpdateCustomDomainErrors, UpdateCustomDomainResponses, UpdateDashboardData, UpdateDashboardErrors, UpdateDashboardResponses, UpdateDeploymentTokenData, UpdateDeploymentTokenErrors, UpdateDeploymentTokenResponses, UpdateEmailProviderData, UpdateEmailProviderErrors, UpdateEmailProviderResponses, UpdateEnvironmentSettingsData, UpdateEnvironmentSettingsErrors, UpdateEnvironmentSettingsResponses, UpdateEnvironmentSubdomainData, UpdateEnvironmentSubdomainErrors, UpdateEnvironmentSubdomainResponses, UpdateEnvironmentVariableData, UpdateEnvironmentVariableErrors, UpdateEnvironmentVariableResponses, UpdateErrorGroupData, UpdateErrorGroupErrors, UpdateErrorGroupResponses, UpdateFlagData, UpdateFlagErrors, UpdateFlagResponses, UpdateFunnelData, UpdateFunnelErrors, UpdateFunnelResponses, UpdateGitProviderCredentialsData, UpdateGitProviderCredentialsErrors, UpdateGitProviderCredentialsResponses, UpdateGitSettingsData, UpdateGitSettingsErrors, UpdateGitSettingsResponses, UpdateGlobalMcpData, UpdateGlobalMcpErrors, UpdateGlobalMcpResponses, UpdateGlobalSkillData, UpdateGlobalSkillErrors, UpdateGlobalSkillResponses, UpdateIncidentStatusData, UpdateIncidentStatusErrors, UpdateIncidentStatusResponses, UpdateIpAccessControlData, UpdateIpAccessControlErrors, UpdateIpAccessControlResponses, UpdateManagedDomainData, UpdateManagedDomainErrors, UpdateManagedDomainResponses, UpdateMcpData, UpdateMcpErrors, UpdateMcpResponses, UpdateNotificationEmailProviderData, UpdateNotificationEmailProviderErrors, UpdateNotificationEmailProviderResponses, UpdateNotificationProviderData, UpdateNotificationProviderErrors, UpdateNotificationProviderResponses, UpdateOidcProviderData, UpdateOidcProviderResponses, UpdatePreferencesData, UpdatePreferencesErrors, UpdatePreferencesResponses, UpdateProjectData, UpdateProjectDeploymentConfigData, UpdateProjectDeploymentConfigErrors, UpdateProjectDeploymentConfigResponses, UpdateProjectErrors, UpdateProjectResponses, UpdateProjectSecretData, UpdateProjectSecretErrors, UpdateProjectSecretResponses, UpdateProjectSettingsData, UpdateProjectSettingsErrors, UpdateProjectSettingsResponses, UpdateProviderData, UpdateProviderErrors, UpdateProviderKeyData, UpdateProviderKeyErrors, UpdateProviderKeyResponses, UpdateProviderResponses, UpdateRouteData, UpdateRouteErrors, UpdateRouteResponses, UpdateS3SourceData, UpdateS3SourceErrors, UpdateS3SourceResponses, UpdateSelfData, UpdateSelfErrors, UpdateSelfResponses, UpdateServiceData, UpdateServiceErrors, UpdateServiceResourcesData, UpdateServiceResourcesErrors, UpdateServiceResourcesResponses, UpdateServiceResponses, UpdateSessionDurationData, UpdateSessionDurationErrors, UpdateSessionDurationResponses, UpdateSettingsData, UpdateSettingsErrors, UpdateSettingsResponses, UpdateSkillData, UpdateSkillErrors, UpdateSkillResponses, UpdateSlackProviderData, UpdateSlackProviderErrors, UpdateSlackProviderResponses, UpdateSpeedMetricsData, UpdateSpeedMetricsErrors, UpdateSpeedMetricsResponses, UpdateTeamData, UpdateTeamErrors, UpdateTeamMemberRoleData, UpdateTeamMemberRoleErrors, UpdateTeamMemberRoleResponses, UpdateTeamResponses, UpdateUserData, UpdateUserErrors, UpdateUserResponses, UpdateWebhookData, UpdateWebhookErrors, UpdateWebhookProviderData, UpdateWebhookProviderErrors, UpdateWebhookProviderResponses, UpdateWebhookResponses, UpgradePreviewGatewayData, UpgradePreviewGatewayResponses, UpgradeServiceData, UpgradeServiceErrors, UpgradeServiceResponses, UploadGlobalSkillData, UploadGlobalSkillErrors, UploadGlobalSkillResponses, UploadReleaseFileData, UploadReleaseFileErrors, UploadReleaseFileResponses, UploadSkillData, UploadSkillErrors, UploadSkillResponses, UploadSourceFileData, UploadSourceFileErrors, UploadSourceFileResponses, UploadSourceMapData, UploadSourceMapErrors, UploadSourceMapResponses, UploadStaticBundleData, UploadStaticBundleErrors, UploadStaticBundleResponses, UpsertSecretData, UpsertSecretErrors, UpsertSecretResponses, ValidateConnectionData, ValidateConnectionErrors, ValidateConnectionResponses, ValidateEmailData, ValidateEmailErrors, ValidateEmailResponses, VerifyAndEnableMfaData, VerifyAndEnableMfaErrors, VerifyAndEnableMfaResponses, VerifyDomainData, VerifyDomainErrors, VerifyDomainResponses, VerifyEmailData, VerifyEmailErrors, VerifyEmailResponses, VerifyManagedDomainData, VerifyManagedDomainErrors, VerifyManagedDomainResponses, VerifyMfaChallengeData, VerifyMfaChallengeErrors, VerifyMfaChallengeResponses, VerifyStepUpData, VerifyStepUpErrors, VerifyStepUpResponses, WakeEnvironmentData, WakeEnvironmentErrors, WakeEnvironmentResponses, WebhookTriggerData, WebhookTriggerErrors, WebhookTriggerResponses, WorkflowDryRunData, WorkflowDryRunErrors, WorkflowDryRunResponses, WriteFileData, WriteFileErrors, WriteFileResponses, WriteFilesData, WriteFilesErrors, WriteFilesResponses } from './types.gen'; export type Options = Options2 & { /** @@ -1320,6 +1320,34 @@ export const blobHead = (options: Options< ...options }); +export const disconnectCloud = (options?: Options): RequestResult => (options?.client ?? client).delete({ + security: [{ scheme: 'bearer', type: 'http' }], + url: '/cloud', + ...options +}); + +export const getCloudCapability = (options?: Options): RequestResult => (options?.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }], + url: '/cloud/capability', + ...options +}); + +export const enrollCloud = (options: Options): RequestResult => (options.client ?? client).post({ + security: [{ scheme: 'bearer', type: 'http' }], + url: '/cloud/enroll', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +export const getCloudStatus = (options?: Options): RequestResult => (options?.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }], + url: '/cloud/status', + ...options +}); + /** * Get dashboard analytics for multiple projects in a single batch request * diff --git a/web/src/api/client/types.gen.ts b/web/src/api/client/types.gen.ts index 2e5a9e062..b95e0359f 100644 --- a/web/src/api/client/types.gen.ts +++ b/web/src/api/client/types.gen.ts @@ -1008,6 +1008,11 @@ export type AppSettings = { * hardware that already has its own per-host headroom). */ build_limits?: BuildLimitsSettings; + /** + * Managed control-plane connection. Credentials are deliberately not + * stored here; they live in the owner-only cloud-link state file. + */ + cloud?: CloudSettings; /** * Cluster-DNS resolver settings (ADR-024, experimental beta). Off by * default — see `ClusterDnsSettings` for the incident background and @@ -2121,11 +2126,37 @@ export type CliLoginRequest = { username: string; }; +export type CloudCapability = { + configured: boolean; + reason?: string | null; + setup_path: string; +}; + /** * Cloud provider detected from node metadata */ export type CloudProvider = 'aws' | 'gcp' | 'azure' | 'hetzner' | 'digitalocean' | 'other'; +/** + * Non-secret managed control-plane settings stored with application settings. + */ +export type CloudSettings = { + /** + * HTTPS origin used for enrollment and telemetry mirroring. + */ + backend_url?: string; +}; + +export type CloudStatus = { + backend_url: string; + health: string; + health_message: string; + instance_id?: string | null; + spooled_spans: number; + status: string; + status_message: string; +}; + /** * Configuration for a Cloudflare Email Sending notification provider. * @@ -4737,6 +4768,19 @@ export type DeploymentMetadata = { * ID of the deployment this was rolled back from (if applicable) */ rolledBackFromId?: number | null; + /** + * Uploaded source archive content type. + */ + sourceBundleContentType?: string | null; + /** + * Uploaded source archive ID. Source archives are extracted before the + * regular preset build pipeline and do not require Git metadata. + */ + sourceBundleId?: number | null; + /** + * Uploaded source archive path in the Temps data directory. + */ + sourceBundlePath?: string | null; /** * Static bundle content type (for proper extraction: application/gzip or application/zip) */ @@ -6001,6 +6045,10 @@ export type EnrichVisitorResponse = { visitor_id: string; }; +export type EnrollCloudRequest = { + enrollment_code: string; +}; + export type EnrollmentTokenInfo = { bound_node_name?: string | null; created_at: string; @@ -24072,6 +24120,58 @@ export type BlobHeadResponses = { 200: unknown; }; +export type DisconnectCloudData = { + body?: never; + path?: never; + query?: never; + url: '/cloud'; +}; + +export type DisconnectCloudResponses = { + 200: CloudStatus; +}; + +export type DisconnectCloudResponse = DisconnectCloudResponses[keyof DisconnectCloudResponses]; + +export type GetCloudCapabilityData = { + body?: never; + path?: never; + query?: never; + url: '/cloud/capability'; +}; + +export type GetCloudCapabilityResponses = { + 200: CloudCapability; +}; + +export type GetCloudCapabilityResponse = GetCloudCapabilityResponses[keyof GetCloudCapabilityResponses]; + +export type EnrollCloudData = { + body: EnrollCloudRequest; + path?: never; + query?: never; + url: '/cloud/enroll'; +}; + +export type EnrollCloudResponses = { + 200: CloudStatus; +}; + +export type EnrollCloudResponse = EnrollCloudResponses[keyof EnrollCloudResponses]; + +export type GetCloudStatusData = { + body?: never; + path?: never; + query?: never; + url: '/cloud/status'; +}; + +export type GetCloudStatusResponses = { + 200: CloudStatus; +}; + +export type GetCloudStatusResponse = GetCloudStatusResponses[keyof GetCloudStatusResponses]; + export type GetDashboardProjectsAnalyticsData = { body?: never; path?: never; diff --git a/web/src/components/ai/AiAssistantButton.tsx b/web/src/components/ai/AiAssistantButton.tsx index 2712c6df3..cd1aeb5b8 100644 --- a/web/src/components/ai/AiAssistantButton.tsx +++ b/web/src/components/ai/AiAssistantButton.tsx @@ -1,28 +1,15 @@ -import { listProviderKeys } from '@/api/client' import { useAiAssistant } from '@/components/ai/AiAssistantContext' import { Button } from '@/components/ui/button' -import { useQuery } from '@tanstack/react-query' import { Sparkles } from 'lucide-react' /** * Global top-bar entry point to the persistent AI assistant dock (ADR-023). - * Shown on every page whenever an AI provider is configured — the dock opens on - * the cross-project conversation list, so any chat can be resumed from anywhere - * (it lives in the app shell and stays open while you navigate). Starting new - * chats still happens from a failed deployment stage or a firing alert. + * Always shown. When no provider is configured, the dock explains both setup + * paths instead of hiding the feature: managed AI through Temps Cloud or a + * self-hosted provider key. */ export function AiAssistantButton() { const { open, close, isOpen } = useAiAssistant() - // Shared cache key with AiGateway / AiProvidersPage — no extra fetch. - const { data: keys } = useQuery({ - queryKey: ['providerKeys'], - queryFn: async () => (await listProviderKeys()).data ?? [], - staleTime: 60_000, - retry: false, - }) - - const aiConfigured = (keys ?? []).some((k) => k.is_active) - if (!aiConfigured) return null return ( + + ) +} + +function AiDockSkeleton({ onClose }: { onClose: () => void }) { + return ( +
+ +
+ + + +
+
+ ) +} + +export function CloudAiEmptyState({ onClose }: { onClose: () => void }) { + return ( +
+ +
+
+
+
+

+ Managed analysis +

+

+ Ask your stack. Keep the evidence attached. +

+

+ Connect Temps Cloud for evidence-backed explanations across + traces, errors, analytics, and deploys. Local ingest and primary + telemetry storage stay on this instance. +

+
+ +
+ } title="250 AI credits included monthly"> + Credits reset each billing period. Extra usage stays off until + you set a hard cap. + + } + title="Cited, read-only answers" + > + Conclusions link to the signals and time windows that support + them. + + } title="Optional control plane"> + Connect in two steps without putting Cloud in your request path. + +
+ +
+ + +
+
+
+
+ ) +} + +function AiCloudBenefit({ + icon, + title, + children, +}: { + icon: ReactNode + title: string + children: ReactNode +}) { + return ( +
+ + {icon} + +
+

{title}

+

{children}

+
+
+ ) +} diff --git a/web/src/components/dashboard/Sidebar.tsx b/web/src/components/dashboard/Sidebar.tsx index b1b5c4626..e80cd1c33 100644 --- a/web/src/components/dashboard/Sidebar.tsx +++ b/web/src/components/dashboard/Sidebar.tsx @@ -187,6 +187,7 @@ const settingsGroups: SettingsGroupDef[] = [ { title: 'Platform', url: '/settings', icon: Settings2 }, { title: 'AI Providers', url: '/settings/ai-providers', icon: Sparkles }, { title: 'Notifications', url: '/settings/notifications', icon: Bell }, + { title: 'Temps Cloud', url: '/settings/cloud', icon: Cloud }, ], }, { diff --git a/web/src/pages/settings/CloudSettingsPage.tsx b/web/src/pages/settings/CloudSettingsPage.tsx new file mode 100644 index 000000000..57833d6fe --- /dev/null +++ b/web/src/pages/settings/CloudSettingsPage.tsx @@ -0,0 +1,335 @@ +import { + disconnectCloudMutation, + enrollCloudMutation, + getCloudCapabilityOptions, + getCloudStatusOptions, +} from '@/api/client/@tanstack/react-query.gen' +import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' +import { Button } from '@/components/ui/button' +import { Card, CardContent } from '@/components/ui/card' +import { Input } from '@/components/ui/input' +import { Label } from '@/components/ui/label' +import { useBreadcrumbs } from '@/contexts/BreadcrumbContext' +import { usePageTitle } from '@/hooks/usePageTitle' +import { zodResolver } from '@hookform/resolvers/zod' +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' +import { + AlertCircle, + Check, + Cloud, + Loader2, + Radio, + ShieldCheck, + Unplug, +} from 'lucide-react' +import { useEffect } from 'react' +import type { ReactNode } from 'react' +import { useForm } from 'react-hook-form' +import { toast } from 'sonner' +import { z } from 'zod' + +const enrollmentSchema = z.object({ + enrollmentCode: z + .string() + .trim() + .min(1, 'Paste the enrollment code from Temps Cloud'), +}) + +type EnrollmentForm = z.infer + +export function CloudSettingsPage() { + const { setBreadcrumbs } = useBreadcrumbs() + const queryClient = useQueryClient() + const capability = useQuery(getCloudCapabilityOptions()) + const status = useQuery({ + ...getCloudStatusOptions(), + refetchInterval: 5_000, + }) + const enroll = useMutation(enrollCloudMutation()) + const disconnect = useMutation(disconnectCloudMutation()) + const form = useForm({ + resolver: zodResolver(enrollmentSchema), + defaultValues: { enrollmentCode: '' }, + }) + + useEffect(() => { + setBreadcrumbs([ + { label: 'Settings', href: '/settings' }, + { label: 'Temps Cloud' }, + ]) + }, [setBreadcrumbs]) + usePageTitle('Temps Cloud') + + const connected = status.data?.status === 'linked' + const cloudConsoleUrl = status.data?.backend_url ?? 'https://app.temps.sh' + const refresh = () => + Promise.all([ + queryClient.invalidateQueries({ + queryKey: getCloudStatusOptions().queryKey, + }), + queryClient.invalidateQueries({ + queryKey: getCloudCapabilityOptions().queryKey, + }), + ]) + + const submit = form.handleSubmit(async ({ enrollmentCode }) => { + try { + await enroll.mutateAsync({ body: { enrollment_code: enrollmentCode } }) + form.reset() + await refresh() + toast.success('Instance connected to Temps Cloud') + } catch (error) { + toast.error( + error instanceof Error + ? error.message + : 'Could not connect this instance' + ) + } + }) + + const remove = async () => { + try { + await disconnect.mutateAsync({}) + await refresh() + toast.success('Temps Cloud disconnected') + } catch (error) { + toast.error( + error instanceof Error + ? error.message + : 'Could not disconnect this instance' + ) + } + } + + if (status.isLoading || capability.isLoading) { + return ( +
+ +
+ ) + } + + if (status.error) { + return ( + + + Temps Cloud status unavailable + {status.error.message} + + ) + } + + return ( +
+
+
+ Optional control plane +
+

+ Temps Cloud +

+

+ See this instance alongside the rest of your fleet. Application + traffic and primary telemetry storage stay on this machine. +

+
+ + {!capability.data?.configured && ( + + + Cloud connection needs configuration + + {capability.data?.reason ?? + 'The managed backend is not configured.'} + + + )} + + {connected ? ( + +
+
+

+ Connection state +

+
+ + + +
+

Connected

+

+ {status.data?.status_message} +

+
+
+
+
+ +
+
+ + + + + +
+ ) : ( +
+ + +
+
+

+ Two-step setup +

+

+ Connect this instance +

+
+ + ~30 sec + +
+
+
+
+ + + Get a code + +
+ + {form.formState.errors.enrollmentCode && ( +

+ {form.formState.errors.enrollmentCode.message} +

+ )} +
+ +
+

+ The code is exchanged for an instance-only credential stored + with owner-only file permissions. Mirrored spans contain only + trace and span IDs, a neutral operation label, timestamp, and + duration. Application-controlled names and attributes are + stripped; source code, environment variables, secrets, and + application traffic never leave this instance. +

+
+
+ + +
+ )} +
+ ) +} + +function StatusCell({ + label, + value, + detail, + mono = false, +}: { + label: string + value: string + detail: string + mono?: boolean +}) { + return ( +
+

{label}

+

+ {value.split('_').join(' ')} +

+

+ {detail} +

+
+ ) +} + +function TrustItem({ + icon, + title, + children, +}: { + icon: ReactNode + title: string + children: ReactNode +}) { + return ( +
  • + + {icon} + +
    +

    {title}

    +

    + {children} +

    +
    +
  • + ) +} From d9d974b35414ae4c289cb7c498f831d19caa634f Mon Sep 17 00:00:00 2001 From: David Viejo Date: Wed, 5 Aug 2026 14:05:07 +0200 Subject: [PATCH 3/9] chore(merge): sync cloud funnel with main Conflicts, all in the console: - App.tsx: main reindented the settings routes under a new wrapper; took main's structure and re-added the cloud route. - api/client/{index,sdk.gen,@tanstack/react-query.gen}.ts: both sides added generated exports. Resolved by replaying each side's insertions onto the base list rather than re-sorting, so the generator's own ordering is kept. Regenerating against a live server is still the authority if these drift. --- .../scripts/test-nightly-release-workflows.sh | 8 +- .github/workflows/e2e-tests.yml | 5 + .../temps-agents/src/handlers/definitions.rs | 1 + crates/temps-ai-api-tools/src/caller.rs | 3 + .../src/integration_tests.rs | 1 + crates/temps-ai-chat/src/handlers.rs | 1 + crates/temps-ai-chat/src/pending_actions.rs | 1 + crates/temps-ai-chat/src/service.rs | 1 + .../src/handlers/events_handler.rs | 1 + crates/temps-audit/src/handlers/handlers.rs | 1 + crates/temps-auth/src/apikey_handler.rs | 1 + crates/temps-auth/src/apikey_types.rs | 42 +- crates/temps-auth/src/auth_service.rs | 568 ++++++++++-- crates/temps-auth/src/cli_device_handler.rs | 1 + crates/temps-auth/src/handlers.rs | 511 +++++++++-- crates/temps-auth/src/oidc_handler.rs | 64 ++ crates/temps-auth/src/oidc_service.rs | 2 +- crates/temps-auth/src/permission_guard.rs | 1 + crates/temps-auth/src/permissions.rs | 1 - crates/temps-auth/src/sensitive_action.rs | 1 + crates/temps-auth/src/types.rs | 7 +- crates/temps-auth/src/user_service.rs | 808 ++++++++++++++++-- crates/temps-auth/tests/context_tests.rs | 1 + crates/temps-blob/src/handlers/handler.rs | 1 + .../temps-cli/src/commands/serve/console.rs | 3 + crates/temps-cli/src/commands/setup.rs | 1 + .../src/handlers/deployments.rs | 1 + .../src/handlers/remote_deployments.rs | 1 + .../src/services/job_processor.rs | 20 +- .../src/handlers/tracking_tests.rs | 1 + crates/temps-entities/src/users.rs | 1 + .../src/handlers/handler.rs | 1 + .../src/sentry/dsn_handlers.rs | 1 + crates/temps-external-plugins/src/handler.rs | 1 + crates/temps-flags/src/handlers/handler.rs | 1 + crates/temps-geo/src/handlers.rs | 1 + crates/temps-git/src/handlers/base.rs | 5 +- .../src/services/git_provider_manager.rs | 214 ++++- crates/temps-kv/src/handlers/handler.rs | 1 + .../src/handlers/log_handler.rs | 2 + ...00001_add_must_change_password_to_users.rs | 49 ++ crates/temps-migrations/src/migration/mod.rs | 2 + crates/temps-notifications/src/handlers.rs | 1 + .../temps-providers/src/handlers/handlers.rs | 1 + .../src/handlers/metrics_handlers.rs | 1 + .../temps-sandbox/src/handlers/sandboxes.rs | 1 + .../src/handlers/project_access.rs | 1 + web/e2e/authenticated/drop-handoff.spec.ts | 141 +++ web/e2e/authenticated/user-creation.spec.ts | 107 +++ .../fixtures/drop-folder-site/assets/app.js | 1 + web/e2e/fixtures/drop-folder-site/index.html | 10 + web/src/App.tsx | 612 ++++++++----- .../api/client/@tanstack/react-query.gen.ts | 18 +- web/src/api/client/index.ts | 4 +- web/src/api/client/sdk.gen.ts | 18 +- web/src/api/client/types.gen.ts | 54 +- .../dashboard/FirstProjectOnboarding.tsx | 144 +++- web/src/components/dashboard/Sidebar.tsx | 119 +-- .../components/drop/DetectedPresetCard.tsx | 157 ++++ .../components/drop/DetectedPresetGrid.tsx | 88 ++ .../drop/DropEnvironmentVariables.tsx | 160 ++++ .../components/git/ConnectionsCompactList.tsx | 48 +- web/src/components/presets/PresetIcon.tsx | 40 + .../components/presets/preset-icon-paths.ts | 44 + .../components/templates/TemplateImage.tsx | 30 +- .../users/RolePermissionDetails.tsx | 132 +++ web/src/components/users/UsersManagement.tsx | 217 +---- web/src/hooks/useProjectSetup.test.ts | 50 ++ web/src/hooks/useProjectSetup.ts | 183 ++++ web/src/lib/drop-archive.ts | 36 +- .../lib/drop-environment-variables.test.ts | 37 + web/src/lib/drop-environment-variables.ts | 31 + web/src/lib/drop-handoff.test.ts | 14 + web/src/lib/drop-handoff.ts | 16 + web/src/lib/drop-preset-detection.test.ts | 66 ++ web/src/lib/drop-preset-detection.ts | 32 + web/src/lib/password-policy.test.ts | 44 + web/src/lib/password-policy.ts | 91 ++ web/src/lib/role-permissions.test.ts | 65 ++ web/src/lib/role-permissions.ts | 68 ++ web/src/pages/Account.tsx | 58 +- web/src/pages/CreateUser.tsx | 634 ++++++++++++++ web/src/pages/Drop.tsx | 510 +++++++---- web/src/pages/GitProviderDetail.tsx | 45 +- web/src/pages/Login.tsx | 48 +- web/src/pages/ProjectDetail.tsx | 2 + web/src/pages/ProjectDrop.tsx | 450 ++++++---- web/src/pages/ProjectSetup.tsx | 226 +++++ web/src/pages/RequiredPasswordChange.tsx | 300 +++++++ web/src/pages/ResetPassword.tsx | 17 +- web/src/pages/Users.tsx | 7 +- 91 files changed, 6236 insertions(+), 1281 deletions(-) create mode 100644 crates/temps-migrations/src/migration/m20260804_000001_add_must_change_password_to_users.rs create mode 100644 web/e2e/authenticated/drop-handoff.spec.ts create mode 100644 web/e2e/authenticated/user-creation.spec.ts create mode 100644 web/e2e/fixtures/drop-folder-site/assets/app.js create mode 100644 web/e2e/fixtures/drop-folder-site/index.html create mode 100644 web/src/components/drop/DetectedPresetCard.tsx create mode 100644 web/src/components/drop/DetectedPresetGrid.tsx create mode 100644 web/src/components/drop/DropEnvironmentVariables.tsx create mode 100644 web/src/components/presets/PresetIcon.tsx create mode 100644 web/src/components/presets/preset-icon-paths.ts create mode 100644 web/src/components/users/RolePermissionDetails.tsx create mode 100644 web/src/hooks/useProjectSetup.test.ts create mode 100644 web/src/hooks/useProjectSetup.ts create mode 100644 web/src/lib/drop-environment-variables.test.ts create mode 100644 web/src/lib/drop-environment-variables.ts create mode 100644 web/src/lib/drop-handoff.test.ts create mode 100644 web/src/lib/drop-handoff.ts create mode 100644 web/src/lib/drop-preset-detection.test.ts create mode 100644 web/src/lib/drop-preset-detection.ts create mode 100644 web/src/lib/password-policy.test.ts create mode 100644 web/src/lib/password-policy.ts create mode 100644 web/src/lib/role-permissions.test.ts create mode 100644 web/src/lib/role-permissions.ts create mode 100644 web/src/pages/CreateUser.tsx create mode 100644 web/src/pages/ProjectSetup.tsx create mode 100644 web/src/pages/RequiredPasswordChange.tsx diff --git a/.github/scripts/test-nightly-release-workflows.sh b/.github/scripts/test-nightly-release-workflows.sh index 02c4e1bed..6bb2a04e2 100755 --- a/.github/scripts/test-nightly-release-workflows.sh +++ b/.github/scripts/test-nightly-release-workflows.sh @@ -5,6 +5,7 @@ repository_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" nightly_workflow="$repository_root/.github/workflows/nightly-release.yml" release_workflow="$repository_root/.github/workflows/release.yml" sandbox_workflow="$repository_root/.github/workflows/sandbox-images-beta.yml" +e2e_workflow="$repository_root/.github/workflows/e2e-tests.yml" decision_script="$repository_root/.github/scripts/nightly-release-decision.sh" validation_script="$repository_root/.github/scripts/validate-release-ref.sh" @@ -43,13 +44,18 @@ if [[ "$tag_aware_dispatch_count" -ne 5 ]]; then fail "expected release channel and version logic to distinguish dry-runs from tag dispatches" fi -ruby - "$repository_root" "$nightly_workflow" "$release_workflow" "$sandbox_workflow" <<'RUBY' +ruby - "$repository_root" "$nightly_workflow" "$release_workflow" "$sandbox_workflow" "$e2e_workflow" <<'RUBY' require "yaml" repository_root = ARGV[0] nightly = YAML.safe_load(File.read(ARGV[1]), aliases: true) release = YAML.safe_load(File.read(ARGV[2]), aliases: true) sandbox = YAML.safe_load(File.read(ARGV[3]), aliases: true) +e2e = YAML.safe_load(File.read(ARGV[4]), aliases: true) + +e2e_sandbox_channel = e2e.dig("jobs", "e2e-test", "env", "TEMPS_SANDBOX_CHANNEL") +abort "E2E must pull the beta sandbox images published for main and PR builds" unless + e2e_sandbox_channel == "beta" check_permissions = nightly.dig("jobs", "check-and-tag", "permissions") abort "check-and-tag permissions are not read-actions/write-contents" unless diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index 8869c5dd3..23f665554 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -56,6 +56,11 @@ jobs: # 0/false/off/no/disabled — see temps-telemetry/src/service.rs.) TEMPS_TELEMETRY: "0" TEMPS_BIN: ./ci-prebuilt/temps + # Main and PR builds exercise the beta binary channel. Point sandbox + # pulls at the matching published image set; the default stable tag is + # only published by a stable release and otherwise forces a multi-minute + # local image build that exceeds Playwright's request timeout. + TEMPS_SANDBOX_CHANNEL: beta steps: - name: Free up disk space diff --git a/crates/temps-agents/src/handlers/definitions.rs b/crates/temps-agents/src/handlers/definitions.rs index a2e66e391..1297140af 100644 --- a/crates/temps-agents/src/handlers/definitions.rs +++ b/crates/temps-agents/src/handlers/definitions.rs @@ -1613,6 +1613,7 @@ mod tests { email_verification_expires: None, password_reset_token: None, password_reset_expires: None, + must_change_password: false, deleted_at: None, mfa_secret: None, mfa_enabled: false, diff --git a/crates/temps-ai-api-tools/src/caller.rs b/crates/temps-ai-api-tools/src/caller.rs index b7bf48548..1138c0e4d 100644 --- a/crates/temps-ai-api-tools/src/caller.rs +++ b/crates/temps-ai-api-tools/src/caller.rs @@ -2513,6 +2513,7 @@ mod tests { email_verification_expires: None, password_reset_token: None, password_reset_expires: None, + must_change_password: false, deleted_at: None, mfa_secret: None, mfa_enabled: false, @@ -2553,6 +2554,7 @@ mod tests { email_verification_expires: None, password_reset_token: None, password_reset_expires: None, + must_change_password: false, deleted_at: None, mfa_secret: None, mfa_enabled: false, @@ -2606,6 +2608,7 @@ mod tests { email_verification_expires: None, password_reset_token: None, password_reset_expires: None, + must_change_password: false, deleted_at: None, mfa_secret: None, mfa_enabled: false, diff --git a/crates/temps-ai-api-tools/src/integration_tests.rs b/crates/temps-ai-api-tools/src/integration_tests.rs index 884b46eca..63a3aa53a 100644 --- a/crates/temps-ai-api-tools/src/integration_tests.rs +++ b/crates/temps-ai-api-tools/src/integration_tests.rs @@ -44,6 +44,7 @@ mod tests { email_verification_expires: None, password_reset_token: None, password_reset_expires: None, + must_change_password: false, deleted_at: None, mfa_secret: None, mfa_enabled: false, diff --git a/crates/temps-ai-chat/src/handlers.rs b/crates/temps-ai-chat/src/handlers.rs index 59108f117..c3e3da102 100644 --- a/crates/temps-ai-chat/src/handlers.rs +++ b/crates/temps-ai-chat/src/handlers.rs @@ -1280,6 +1280,7 @@ mod tests { email_verification_expires: None, password_reset_token: None, password_reset_expires: None, + must_change_password: false, deleted_at: None, mfa_secret: None, mfa_enabled: false, diff --git a/crates/temps-ai-chat/src/pending_actions.rs b/crates/temps-ai-chat/src/pending_actions.rs index 1eba72d8d..701d614ad 100644 --- a/crates/temps-ai-chat/src/pending_actions.rs +++ b/crates/temps-ai-chat/src/pending_actions.rs @@ -590,6 +590,7 @@ mod tests { email_verification_expires: None, password_reset_token: None, password_reset_expires: None, + must_change_password: false, deleted_at: None, mfa_secret: None, mfa_enabled: false, diff --git a/crates/temps-ai-chat/src/service.rs b/crates/temps-ai-chat/src/service.rs index 5e1e244b0..197ac595f 100644 --- a/crates/temps-ai-chat/src/service.rs +++ b/crates/temps-ai-chat/src/service.rs @@ -2170,6 +2170,7 @@ mod tests { email_verification_expires: None, password_reset_token: None, password_reset_expires: None, + must_change_password: false, deleted_at: None, mfa_secret: None, mfa_enabled: false, diff --git a/crates/temps-analytics-events/src/handlers/events_handler.rs b/crates/temps-analytics-events/src/handlers/events_handler.rs index 444f48fb7..dc3587b66 100644 --- a/crates/temps-analytics-events/src/handlers/events_handler.rs +++ b/crates/temps-analytics-events/src/handlers/events_handler.rs @@ -1220,6 +1220,7 @@ mod tests { email_verification_expires: None, password_reset_token: None, password_reset_expires: None, + must_change_password: false, deleted_at: None, mfa_secret: None, mfa_enabled: false, diff --git a/crates/temps-audit/src/handlers/handlers.rs b/crates/temps-audit/src/handlers/handlers.rs index 935ea0adf..e9a33be51 100644 --- a/crates/temps-audit/src/handlers/handlers.rs +++ b/crates/temps-audit/src/handlers/handlers.rs @@ -154,6 +154,7 @@ mod tests { email_verification_expires: None, password_reset_token: None, password_reset_expires: None, + must_change_password: false, deleted_at: None, mfa_secret: None, mfa_enabled: false, diff --git a/crates/temps-auth/src/apikey_handler.rs b/crates/temps-auth/src/apikey_handler.rs index f14f3c4ee..81ddaa21c 100644 --- a/crates/temps-auth/src/apikey_handler.rs +++ b/crates/temps-auth/src/apikey_handler.rs @@ -582,6 +582,7 @@ mod tests { email_verification_expires: None, password_reset_token: None, password_reset_expires: None, + must_change_password: false, deleted_at: None, mfa_secret: None, mfa_enabled: false, diff --git a/crates/temps-auth/src/apikey_types.rs b/crates/temps-auth/src/apikey_types.rs index e68d7eb7e..3c6a7ab0a 100644 --- a/crates/temps-auth/src/apikey_types.rs +++ b/crates/temps-auth/src/apikey_types.rs @@ -94,7 +94,9 @@ impl RoleInfo { Role::PlatformAdmin => { "Platform administration (users, settings, system) without deploy access to projects or deployments" } - Role::User => "Standard user access with ability to manage own resources", + Role::User => { + "Manage every existing and future project without user or system administration" + } Role::Reader => "Read-only access to resources", Role::ApiReader => "Read-only API access", Role::Custom => "Custom role with specific permissions", @@ -123,3 +125,41 @@ pub fn get_available_permissions() -> AvailablePermissions { AvailablePermissions { permissions, roles } } + +#[cfg(test)] +mod tests { + use super::*; + use std::collections::HashSet; + + #[test] + fn role_catalog_exposes_the_exact_permission_set() { + let catalog = get_available_permissions(); + let user = catalog + .roles + .iter() + .find(|role| role.name == "user") + .expect("user role is present"); + let expected: Vec = Role::User + .permissions() + .iter() + .map(ToString::to_string) + .collect(); + + assert_eq!(user.permissions, expected); + assert!(user + .description + .contains("every existing and future project")); + } + + #[test] + fn predefined_roles_do_not_report_duplicate_permissions() { + for role in Role::all() { + let unique: HashSet<_> = role.permissions().iter().collect(); + assert_eq!( + unique.len(), + role.permissions().len(), + "role {role} contains duplicate permissions" + ); + } + } +} diff --git a/crates/temps-auth/src/auth_service.rs b/crates/temps-auth/src/auth_service.rs index eafcba6e9..84f67cd34 100644 --- a/crates/temps-auth/src/auth_service.rs +++ b/crates/temps-auth/src/auth_service.rs @@ -7,7 +7,7 @@ use cookie::Cookie; use rand::RngExt; use sea_orm::{ ActiveModelTrait, ColumnTrait, DatabaseConnection, EntityTrait, PaginatorTrait, QueryFilter, - Set, TransactionTrait, + QuerySelect, Set, TransactionTrait, }; use serde::Serialize; use std::sync::Arc; @@ -73,6 +73,8 @@ pub enum AuthError { WeakPassword(String), #[error("Account has no password set (likely an SSO-only user)")] NoPasswordSet, + #[error("User {user_id} must change their password before a session can be created")] + PasswordChangeRequired { user_id: i32 }, } #[derive(Error, Debug)] @@ -121,6 +123,15 @@ impl AuthService { } pub async fn create_session(&self, user_id: i32) -> Result { + let user = temps_entities::users::Entity::find_by_id(user_id) + .filter(temps_entities::users::Column::DeletedAt.is_null()) + .one(self.db.as_ref()) + .await? + .ok_or_else(|| AuthError::NotFound(format!("User {user_id} not found or deleted")))?; + if user.must_change_password { + return Err(AuthError::PasswordChangeRequired { user_id }); + } + let session_token = self.generate_session_token(); let expires_at = Utc::now() + Duration::days(7); @@ -289,55 +300,91 @@ impl AuthService { session_token: &str, code: &str, ) -> Result { - // Get the user from the temporary session. Require mfa_pending so a - // real (fully authenticated) session token can never be spent as an - // MFA challenge -- the discriminator cuts both ways. - let session = temps_entities::sessions::Entity::find() - .filter(temps_entities::sessions::Column::SessionToken.eq(session_token)) - .filter(temps_entities::sessions::Column::ExpiresAt.gt(Utc::now())) - .filter(temps_entities::sessions::Column::MfaPending.eq(true)) - .one(self.db.as_ref()) - .await - .map_err(|source| MfaChallengeError::Database { - operation: "load the pending session", - user_id: None, - source, - })? - .ok_or(MfaChallengeError::InvalidOrExpiredSession)?; + let session_token = session_token.to_owned(); + let code = code.to_owned(); + self.db + .transaction::<_, temps_entities::users::Model, MfaChallengeError>(|transaction| { + Box::pin(async move { + // Get the user from the temporary session. Require mfa_pending so a + // real (fully authenticated) session token can never be spent as an + // MFA challenge -- the discriminator cuts both ways. + let session = temps_entities::sessions::Entity::find() + .filter(temps_entities::sessions::Column::SessionToken.eq(&session_token)) + .filter(temps_entities::sessions::Column::ExpiresAt.gt(Utc::now())) + .filter(temps_entities::sessions::Column::MfaPending.eq(true)) + .one(transaction) + .await + .map_err(|source| MfaChallengeError::Database { + operation: "load the pending session", + user_id: None, + source, + })? + .ok_or(MfaChallengeError::InvalidOrExpiredSession)?; + + let user = temps_entities::users::Entity::find_by_id(session.user_id) + .lock_exclusive() + .one(transaction) + .await + .map_err(|source| MfaChallengeError::Database { + operation: "load the challenge user", + user_id: Some(session.user_id), + source, + })? + .ok_or(MfaChallengeError::UserNotFound { + user_id: session.user_id, + })?; + + // Verify the MFA code + if !Self::verify_totp_code(&user, &code)? { + return Err(MfaChallengeError::InvalidCode { user_id: user.id }); + } - let user = temps_entities::users::Entity::find_by_id(session.user_id) - .one(self.db.as_ref()) - .await - .map_err(|source| MfaChallengeError::Database { - operation: "load the challenge user", - user_id: Some(session.user_id), - source, - })? - .ok_or(MfaChallengeError::UserNotFound { - user_id: session.user_id, - })?; + let mut verified_user = user; + if !verified_user.mfa_enabled { + let mut user_update: temps_entities::users::ActiveModel = + verified_user.into(); + user_update.mfa_enabled = Set(true); + verified_user = + user_update.update(transaction).await.map_err(|source| { + MfaChallengeError::Database { + operation: "enable MFA for the challenge user", + user_id: Some(session.user_id), + source, + } + })?; + } - // Verify the MFA code - if !self.verify_totp_code(&user, code)? { - return Err(MfaChallengeError::InvalidCode { user_id: user.id }); - } + // Consume the challenge in the same transaction as enrollment so a + // failed update never strands the user without a retryable challenge. + let deletion = temps_entities::sessions::Entity::delete_many() + .filter(temps_entities::sessions::Column::SessionToken.eq(&session_token)) + .filter(temps_entities::sessions::Column::MfaPending.eq(true)) + .exec(transaction) + .await + .map_err(|source| MfaChallengeError::Database { + operation: "consume the verified pending session", + user_id: Some(verified_user.id), + source, + })?; + if deletion.rows_affected != 1 { + return Err(MfaChallengeError::InvalidOrExpiredSession); + } - // Delete the temporary session - temps_entities::sessions::Entity::delete_many() - .filter(temps_entities::sessions::Column::SessionToken.eq(session_token)) - .exec(self.db.as_ref()) + Ok(verified_user) + }) + }) .await - .map_err(|source| MfaChallengeError::Database { - operation: "consume the verified pending session", - user_id: Some(user.id), - source, - })?; - - Ok(user) + .map_err(|error| match error { + sea_orm::TransactionError::Transaction(error) => error, + sea_orm::TransactionError::Connection(source) => MfaChallengeError::Database { + operation: "run the MFA challenge transaction", + user_id: None, + source, + }, + }) } fn verify_totp_code( - &self, user: &temps_entities::users::Model, code: &str, ) -> Result { @@ -410,6 +457,7 @@ impl AuthService { email: Set(request.email.to_lowercase()), name: Set(request.name.clone()), password_hash: Set(Some(password_hash)), + must_change_password: Set(false), email_verified: Set(false), created_at: Set(Utc::now()), updated_at: Set(Utc::now()), @@ -499,6 +547,14 @@ impl AuthService { return Err(UserAuthError::InvalidCredentials); } + // A required password change is completed before role-based MFA + // enrollment. The password-change handler starts a pending MFA + // challenge when the policy applies, without issuing a full session. + if user.must_change_password { + debug!("Temporary password verified for user {}", user.id); + return Ok(user); + } + // SOC2 hardening (bherila/temps#32): operators can require MFA // enrollment for Admin-role accounts via the `require_mfa_for_admins` // setting. This check only runs in the password-login path -- SSO/OIDC @@ -541,6 +597,55 @@ impl AuthService { Ok(user) } + /// Create a short-lived reset credential after the user's temporary + /// password has been verified. No regular session is created while the + /// account is marked as requiring a password change. + pub async fn create_required_password_change_token( + &self, + user_id: i32, + ) -> Result { + let user = temps_entities::users::Entity::find_by_id(user_id) + .one(self.db.as_ref()) + .await? + .ok_or(UserAuthError::UserNotFound)?; + + if !user.must_change_password { + return Err(UserAuthError::PasswordChangeNotRequired { user_id }); + } + + let token = self.generate_token(); + let mut user_update: temps_entities::users::ActiveModel = user.into(); + user_update.password_reset_token = Set(Some(token.clone())); + user_update.password_reset_expires = Set(Some(Utc::now() + Duration::minutes(15))); + user_update.update(self.db.as_ref()).await?; + + Ok(token) + } + + /// Resolve a live first-login password-change credential without + /// consuming it. The handler uses this to evaluate post-change policy + /// before committing the password replacement. + pub async fn required_password_change_user( + &self, + token: &str, + ) -> Result { + let user = temps_entities::users::Entity::find() + .filter(temps_entities::users::Column::PasswordResetToken.eq(token)) + .one(self.db.as_ref()) + .await? + .ok_or(UserAuthError::InvalidToken)?; + + if !user.must_change_password + || user + .password_reset_expires + .is_none_or(|expires_at| expires_at < Utc::now()) + { + return Err(UserAuthError::InvalidToken); + } + + Ok(user) + } + // Request password reset pub async fn request_password_reset(&self, email: &str) -> Result<(), UserAuthError> { // Check if email service is configured @@ -582,41 +687,147 @@ impl AuthService { // Validate password complexity validate_password_complexity(&request.new_password)?; - // Find user by reset token - let user = temps_entities::users::Entity::find() - .filter(temps_entities::users::Column::PasswordResetToken.eq(&request.token)) - .one(self.db.as_ref()) - .await? - .ok_or(UserAuthError::InvalidToken)?; + self.db + .transaction::<_, temps_entities::users::Model, UserAuthError>(|transaction| { + Box::pin(async move { + // Find user by reset token. The transaction callback guarantees that + // every rejection path is rolled back before this method returns. + let user = temps_entities::users::Entity::find() + .filter( + temps_entities::users::Column::PasswordResetToken.eq(&request.token), + ) + .lock_exclusive() + .one(transaction) + .await? + .ok_or(UserAuthError::InvalidToken)?; + + // Check if token is expired + if user + .password_reset_expires + .is_none_or(|expires_at| expires_at < Utc::now()) + { + return Err(UserAuthError::InvalidToken); + } - // Check if token is expired - if let Some(expires_at) = user.password_reset_expires { - if expires_at < Utc::now() { - return Err(UserAuthError::InvalidToken); - } - } else { - return Err(UserAuthError::InvalidToken); - } + if user.must_change_password { + if let Some(current_hash) = user.password_hash.as_deref() { + let parsed_hash = + argon2::password_hash::PasswordHash::new(current_hash) + .map_err(|_| UserAuthError::PasswordHashError)?; + if argon2::Argon2::default() + .verify_password(request.new_password.as_bytes(), &parsed_hash) + .is_ok() + { + return Err(UserAuthError::SamePassword); + } + } + } - // Hash new password - use argon2::password_hash::{rand_core::OsRng, SaltString}; - let argon2 = argon2::Argon2::default(); - let salt = SaltString::generate(&mut OsRng); + // Hash new password + use argon2::password_hash::{rand_core::OsRng, SaltString}; + let argon2 = argon2::Argon2::default(); + let salt = SaltString::generate(&mut OsRng); + + let password_hash = argon2 + .hash_password(request.new_password.as_bytes(), &salt) + .map_err(|_| UserAuthError::PasswordHashError)? + .to_string(); + + // Update user password and clear reset token + let mut user_update: temps_entities::users::ActiveModel = user.into(); + user_update.password_hash = Set(Some(password_hash)); + user_update.password_reset_token = Set(None); + user_update.password_reset_expires = Set(None); + user_update.must_change_password = Set(false); + user_update.updated_at = Set(Utc::now()); + user_update.update(transaction).await.map_err(Into::into) + }) + }) + .await + .map_err(Into::into) + } - let password_hash = argon2 - .hash_password(request.new_password.as_bytes(), &salt) - .map_err(|_| UserAuthError::PasswordHashError)? - .to_string(); + /// Complete the first-login password change. Unlike an email reset, this + /// requires the account to still be flagged and rejects reuse of the + /// administrator-provided temporary password. + pub async fn reset_required_password( + &self, + request: ResetPasswordRequest, + ) -> Result { + validate_password_complexity(&request.new_password)?; - // Update user password and clear reset token - let mut user_update: temps_entities::users::ActiveModel = user.into(); - user_update.password_hash = Set(Some(password_hash)); - user_update.password_reset_token = Set(None); - user_update.password_reset_expires = Set(None); - user_update.updated_at = Set(Utc::now()); - let updated_user = user_update.update(self.db.as_ref()).await?; + self.db + .transaction::<_, temps_entities::users::Model, UserAuthError>(|transaction| { + Box::pin(async move { + let user = temps_entities::users::Entity::find() + .filter( + temps_entities::users::Column::PasswordResetToken.eq(&request.token), + ) + .lock_exclusive() + .one(transaction) + .await? + .ok_or(UserAuthError::InvalidToken)?; + + if !user.must_change_password + || user + .password_reset_expires + .is_none_or(|expires_at| expires_at < Utc::now()) + { + return Err(UserAuthError::InvalidToken); + } - Ok(updated_user) + if let Some(current_hash) = user.password_hash.as_deref() { + let parsed_hash = argon2::password_hash::PasswordHash::new(current_hash) + .map_err(|_| UserAuthError::PasswordHashError)?; + if argon2::Argon2::default() + .verify_password(request.new_password.as_bytes(), &parsed_hash) + .is_ok() + { + return Err(UserAuthError::SamePassword); + } + } + + use argon2::password_hash::{rand_core::OsRng, SaltString}; + let salt = SaltString::generate(&mut OsRng); + let password_hash = argon2::Argon2::default() + .hash_password(request.new_password.as_bytes(), &salt) + .map_err(|_| UserAuthError::PasswordHashError)? + .to_string(); + + let mut user_update: temps_entities::users::ActiveModel = user.into(); + user_update.password_hash = Set(Some(password_hash)); + user_update.password_reset_token = Set(None); + user_update.password_reset_expires = Set(None); + user_update.must_change_password = Set(false); + user_update.updated_at = Set(Utc::now()); + user_update.update(transaction).await.map_err(Into::into) + }) + }) + .await + .map_err(Into::into) + } + + pub async fn requires_mfa_enrollment(&self, user_id: i32) -> Result { + let settings = self.get_settings().await?; + if !settings.require_mfa_for_admins { + return Ok(false); + } + + let user = temps_entities::users::Entity::find_by_id(user_id) + .one(self.db.as_ref()) + .await? + .ok_or(UserAuthError::UserNotFound)?; + if user.mfa_enabled { + return Ok(false); + } + + crate::user_service::UserService::new(self.db.clone()) + .is_admin(user_id) + .await + .map_err(|error| UserAuthError::RoleLookup { + user_id, + reason: error.to_string(), + }) } /// In-app password change for an authenticated user. @@ -883,6 +1094,12 @@ pub enum UserAuthError { "MFA is required for the '{role}' role but user {user_id} has not enrolled multi-factor authentication" )] MfaRequiredForRole { user_id: i32, role: String }, + #[error("User {user_id} is not required to change their password")] + PasswordChangeNotRequired { user_id: i32 }, + #[error("New password must differ from the temporary password")] + SamePassword, + #[error("Failed to determine roles for user {user_id}: {reason}")] + RoleLookup { user_id: i32, reason: String }, } /// Detect a Postgres unique-constraint violation regardless of the specific @@ -915,6 +1132,15 @@ impl From for UserAuthError { } } +impl From> for UserAuthError { + fn from(error: sea_orm::TransactionError) -> Self { + match error { + sea_orm::TransactionError::Transaction(error) => error, + sea_orm::TransactionError::Connection(error) => error.into(), + } + } +} + // Request DTOs #[derive(Debug, serde::Serialize, serde::Deserialize)] pub struct RegisterRequest { @@ -1607,6 +1833,7 @@ mod tests { let mut user_update: users::ActiveModel = user.clone().into(); user_update.password_reset_token = Set(Some(reset_token.clone())); user_update.password_reset_expires = Set(Some(Utc::now() + Duration::hours(1))); + user_update.must_change_password = Set(true); user_update.update(db.db.as_ref()).await.unwrap(); // Reset password @@ -1626,6 +1853,7 @@ mod tests { assert!(updated_user.password_reset_token.is_none()); assert!(updated_user.password_reset_expires.is_none()); + assert!(!updated_user.must_change_password); // Verify new password works let login = LoginRequest { @@ -1635,6 +1863,198 @@ mod tests { auth_service.login(login).await.unwrap(); } + #[tokio::test] + async fn email_reset_rejects_temporary_password_reuse() { + let (db, auth_service, _) = setup_test_env().await; + let user = + create_test_user(&db.db, "forced-email-reset@example.com", "Temporary123!").await; + let reset_token = Uuid::new_v4().to_string(); + let mut user_update: users::ActiveModel = user.clone().into(); + user_update.password_reset_token = Set(Some(reset_token.clone())); + user_update.password_reset_expires = Set(Some(Utc::now() + Duration::hours(1))); + user_update.must_change_password = Set(true); + user_update.update(db.db.as_ref()).await.unwrap(); + + let result = auth_service + .reset_password(ResetPasswordRequest { + token: reset_token.clone(), + new_password: "Temporary123!".to_string(), + }) + .await; + + assert!(matches!(result, Err(UserAuthError::SamePassword))); + let unchanged = users::Entity::find_by_id(user.id) + .one(db.db.as_ref()) + .await + .unwrap() + .unwrap(); + assert!(unchanged.must_change_password); + assert_eq!( + unchanged.password_reset_token.as_deref(), + Some(reset_token.as_str()) + ); + } + + #[tokio::test] + async fn required_password_change_rejects_temporary_password_reuse() { + let (db, auth_service, _) = setup_test_env().await; + let user = create_test_user(&db.db, "forced-change@example.com", "Temporary123!").await; + let reset_token = Uuid::new_v4().to_string(); + let mut user_update: users::ActiveModel = user.clone().into(); + user_update.password_reset_token = Set(Some(reset_token.clone())); + user_update.password_reset_expires = Set(Some(Utc::now() + Duration::minutes(15))); + user_update.must_change_password = Set(true); + user_update.update(db.db.as_ref()).await.unwrap(); + + let result = auth_service + .reset_required_password(ResetPasswordRequest { + token: reset_token.clone(), + new_password: "Temporary123!".to_string(), + }) + .await; + + assert!(matches!(result, Err(UserAuthError::SamePassword))); + let unchanged = users::Entity::find_by_id(user.id) + .one(db.db.as_ref()) + .await + .unwrap() + .unwrap(); + assert!(unchanged.must_change_password); + assert_eq!( + unchanged.password_reset_token.as_deref(), + Some(reset_token.as_str()) + ); + } + + #[tokio::test] + async fn required_password_change_consumes_token_and_allows_session_creation() { + let (db, auth_service, _) = setup_test_env().await; + let user = + create_test_user(&db.db, "forced-change-success@example.com", "Temporary123!").await; + let reset_token = Uuid::new_v4().to_string(); + let mut user_update: users::ActiveModel = user.clone().into(); + user_update.password_reset_token = Set(Some(reset_token.clone())); + user_update.password_reset_expires = Set(Some(Utc::now() + Duration::minutes(15))); + user_update.must_change_password = Set(true); + user_update.update(db.db.as_ref()).await.unwrap(); + + let updated = auth_service + .reset_required_password(ResetPasswordRequest { + token: reset_token.clone(), + new_password: "DifferentPassword123!".to_string(), + }) + .await + .unwrap(); + + assert!(!updated.must_change_password); + assert!(updated.password_reset_token.is_none()); + assert!(auth_service.create_session(user.id).await.is_ok()); + assert!(matches!( + auth_service + .reset_required_password(ResetPasswordRequest { + token: reset_token, + new_password: "AnotherPassword123!".to_string(), + }) + .await, + Err(UserAuthError::InvalidToken) + )); + } + + #[tokio::test] + async fn required_password_change_token_is_single_use_under_concurrency() { + let (db, auth_service, _) = setup_test_env().await; + let user = + create_test_user(&db.db, "forced-change-race@example.com", "Temporary123!").await; + let reset_token = Uuid::new_v4().to_string(); + let mut user_update: users::ActiveModel = user.into(); + user_update.password_reset_token = Set(Some(reset_token.clone())); + user_update.password_reset_expires = Set(Some(Utc::now() + Duration::minutes(15))); + user_update.must_change_password = Set(true); + user_update.update(db.db.as_ref()).await.unwrap(); + + let first = auth_service.reset_required_password(ResetPasswordRequest { + token: reset_token.clone(), + new_password: "FirstReplacement123!".to_string(), + }); + let second = auth_service.reset_required_password(ResetPasswordRequest { + token: reset_token, + new_password: "SecondReplacement123!".to_string(), + }); + let (first_result, second_result) = tokio::join!(first, second); + + assert_ne!(first_result.is_ok(), second_result.is_ok()); + let rejected = if first_result.is_err() { + first_result + } else { + second_result + }; + assert!(matches!(rejected, Err(UserAuthError::InvalidToken))); + } + + #[tokio::test] + async fn full_session_is_rejected_while_password_change_is_required() { + let (db, auth_service, _) = setup_test_env().await; + let user = create_test_user(&db.db, "no-session@example.com", "Temporary123!").await; + let mut user_update: users::ActiveModel = user.clone().into(); + user_update.must_change_password = Set(true); + user_update.update(db.db.as_ref()).await.unwrap(); + + let result = auth_service.create_session(user.id).await; + + assert!(matches!( + result, + Err(AuthError::PasswordChangeRequired { user_id }) if user_id == user.id + )); + assert_eq!( + sessions::Entity::find() + .filter(sessions::Column::UserId.eq(user.id)) + .count(db.db.as_ref()) + .await + .unwrap(), + 0 + ); + } + + #[tokio::test] + async fn required_password_change_token_is_short_lived_and_only_for_flagged_users() { + let (db, auth_service, _) = setup_test_env().await; + let user = create_test_user(&db.db, "temporary@example.com", "Temporary1!").await; + + let result = auth_service + .create_required_password_change_token(user.id) + .await; + assert!(matches!( + result, + Err(UserAuthError::PasswordChangeNotRequired { user_id }) if user_id == user.id + )); + + let mut user_update: users::ActiveModel = user.clone().into(); + user_update.must_change_password = Set(true); + user_update.update(db.db.as_ref()).await.unwrap(); + + let issued_at = Utc::now(); + let token = auth_service + .create_required_password_change_token(user.id) + .await + .unwrap(); + let updated_user = users::Entity::find_by_id(user.id) + .one(db.db.as_ref()) + .await + .unwrap() + .unwrap(); + + assert_eq!( + updated_user.password_reset_token.as_deref(), + Some(token.as_str()) + ); + let expires_at = updated_user + .password_reset_expires + .expect("required password-change token has an expiry"); + assert!(expires_at > issued_at + Duration::minutes(14)); + assert!(expires_at <= issued_at + Duration::minutes(16)); + assert!(updated_user.must_change_password); + } + #[tokio::test] async fn test_reset_password_expired_token() { let (db, auth_service, _) = setup_test_env().await; @@ -1836,6 +2256,7 @@ mod tests { email_verification_expires: None, password_reset_token: None, password_reset_expires: None, + must_change_password: false, deleted_at: None, mfa_secret: Some("JBSWY3DPEHPK3PXPJBSWY3DPEHPK3PXP".to_string()), mfa_enabled: true, @@ -2366,6 +2787,7 @@ mod tests { email_verification_expires: None, password_reset_token: None, password_reset_expires: None, + must_change_password: false, deleted_at: None, mfa_secret: None, mfa_enabled: false, diff --git a/crates/temps-auth/src/cli_device_handler.rs b/crates/temps-auth/src/cli_device_handler.rs index ce140b82d..b7c2e9af7 100644 --- a/crates/temps-auth/src/cli_device_handler.rs +++ b/crates/temps-auth/src/cli_device_handler.rs @@ -834,6 +834,7 @@ mod tests { email_verification_expires: None, password_reset_token: None, password_reset_expires: None, + must_change_password: false, deleted_at: None, mfa_secret: None, mfa_enabled: false, diff --git a/crates/temps-auth/src/handlers.rs b/crates/temps-auth/src/handlers.rs index ea0d5d3a5..d27a845b8 100644 --- a/crates/temps-auth/src/handlers.rs +++ b/crates/temps-auth/src/handlers.rs @@ -8,7 +8,7 @@ use crate::audit::{ use crate::avatar::generate_avatar_data_url; use crate::context::AuthContext; use crate::permissions::Permission; -use crate::user_service::UserServiceError; +use crate::user_service::{normalize_user_email, UserServiceError}; use crate::{permission_guard, RequireAuth}; use axum::extract::Path; use axum::http::header::SET_COOKIE; @@ -58,27 +58,20 @@ fn bounded_audit_identity(identity: &str) -> String { } fn normalized_login_email(email: &str) -> Option { - let normalized = email.to_lowercase(); - if normalized.is_empty() - || normalized.len() > MAX_LOGIN_EMAIL_BYTES - || normalized.chars().any(char::is_whitespace) - || normalized.chars().any(char::is_control) - { - return None; - } - - let (local, domain) = normalized.split_once('@')?; - if local.is_empty() - || local.len() > 64 - || domain.is_empty() - || domain.contains('@') - || domain.starts_with('.') - || domain.ends_with('.') - { - return None; - } + normalize_user_email(email) +} - Some(normalized) +fn parse_user_roles(role_names: &[String]) -> Result, UserServiceError> { + role_names + .iter() + .map(|role| { + RoleType::from_str(role).map_err(|_| { + UserServiceError::Validation(format!( + "Unsupported role '{role}'. Expected one of: admin, user" + )) + }) + }) + .collect() } async fn record_login_failure( @@ -131,6 +124,32 @@ async fn record_mfa_rejection( } } +async fn record_pending_login( + state: &AuthState, + metadata: &RequestMetadata, + user_id: i32, + login_method: &'static str, +) { + if let Err(error) = state + .audit_service + .create_audit_log(&LoginAudit { + context: AuditContext { + user_id, + ip_address: Some(metadata.ip_address.to_string()), + user_agent: metadata.user_agent.as_str().to_string(), + }, + success: true, + login_method: login_method.to_string(), + }) + .await + { + error!( + user_id, + login_method, "Failed to record pending login audit event: {}", error + ); + } +} + fn invalid_mfa_problem() -> Problem { problem_new(StatusCode::UNAUTHORIZED) .with_title("MFA Verification Failed") @@ -629,6 +648,7 @@ pub async fn verify_step_up( email_status, request_password_reset, reset_password, + change_required_password, verify_email, list_users, create_user, @@ -663,6 +683,8 @@ pub async fn verify_step_up( LoginRequest, EmailRequest, ResetPasswordRequest, + RequiredPasswordChangeRequest, + RequiredPasswordChangeResponse, AuthResponse, EmailStatusResponse, crate::oidc_types::OidcProviderSummary, @@ -723,6 +745,10 @@ pub fn configure_routes() -> Router> { ) .route("/auth/password-reset/request", post(request_password_reset)) .route("/auth/password-reset/verify", post(reset_password)) + .route( + "/auth/password-change-required", + post(change_required_password), + ) .route( "/auth/oidc/login/{slug}", get(crate::oidc_handler::start_oidc_login_by_slug), @@ -800,6 +826,11 @@ pub struct ResetPasswordRequest { pub new_password: String, } +#[derive(Debug, Serialize, Deserialize, ToSchema)] +pub struct RequiredPasswordChangeRequest { + pub new_password: String, +} + // Implement From traits for conversions impl From for crate::auth_service::RegisterRequest { fn from(req: RegisterRequest) -> Self { @@ -835,6 +866,18 @@ pub struct AuthResponse { pub message: String, pub user_id: Option, pub mfa_required: bool, + pub mfa_enrollment_required: bool, + pub mfa_setup: Option, + pub password_change_required: bool, +} + +#[derive(Debug, Serialize, ToSchema)] +pub struct RequiredPasswordChangeResponse { + pub success: bool, + pub message: String, + pub user_id: i32, + pub mfa_enrollment_required: bool, + pub mfa_setup: Option, } #[derive(Debug, Serialize, Deserialize, ToSchema)] @@ -905,6 +948,9 @@ pub async fn register( message: "User created successfully".to_string(), user_id: Some(user.id), mfa_required: false, + mfa_enrollment_required: false, + mfa_setup: None, + password_change_required: false, }), )) } @@ -958,6 +1004,87 @@ pub async fn login( match state.auth_service.login(request.into()).await { Ok(user) => { + if user.must_change_password { + let reset_token = state + .auth_service + .create_required_password_change_token(user.id) + .await + .map_err(|error| { + error!( + user_id = user.id, + error = %error, + "Failed to create required password-change session" + ); + problem_new(StatusCode::INTERNAL_SERVER_ERROR) + .with_title("Authentication Error") + .with_detail( + "Could not start the required password change. Please try again.", + ) + })?; + + let encrypted_token = + state.cookie_crypto.encrypt(&reset_token).map_err(|error| { + error!( + user_id = user.id, + error = %error, + "Failed to encrypt required password-change session" + ); + problem_new(StatusCode::INTERNAL_SERVER_ERROR) + .with_title("Authentication Error") + .with_detail( + "Could not secure the required password change. Please try again.", + ) + })?; + + let password_change_cookie = + Cookie::build(("password_change_session", encrypted_token)) + .http_only(true) + .path("/") + .max_age(cookie::time::Duration::minutes(15)) + .same_site(cookie::SameSite::Strict) + .secure(metadata.is_secure) + .build(); + let cookie_header = + password_change_cookie + .to_string() + .parse() + .map_err(|error| { + error!( + user_id = user.id, + error = %error, + "Failed to create required password-change cookie header" + ); + problem_new(StatusCode::INTERNAL_SERVER_ERROR) + .with_title("Authentication Error") + .with_detail( + "Could not secure the required password change. Please try again.", + ) + })?; + let mut headers = HeaderMap::new(); + headers.insert(SET_COOKIE, cookie_header); + + record_pending_login( + state.as_ref(), + &metadata, + user.id, + "password-change-required", + ) + .await; + + return Ok(( + headers, + Json(AuthResponse { + success: false, + message: "Password change required".to_string(), + user_id: Some(user.id), + mfa_required: false, + mfa_enrollment_required: false, + mfa_setup: None, + password_change_required: true, + }), + )); + } + // Check if user has MFA enabled if user.mfa_enabled { // Create temporary MFA session @@ -1025,6 +1152,9 @@ pub async fn login( message: "MFA authentication required".to_string(), user_id: None, mfa_required: true, + mfa_enrollment_required: false, + mfa_setup: None, + password_change_required: false, }), )) } @@ -1131,6 +1261,9 @@ pub async fn login( message: "Login successful".to_string(), user_id: Some(user.id), mfa_required: false, + mfa_enrollment_required: false, + mfa_setup: None, + password_change_required: false, }), )) } @@ -1176,32 +1309,70 @@ pub async fn login( .with_detail("Invalid email or password.")) } crate::auth_service::UserAuthError::MfaRequiredForRole { user_id, role } => { - // Deliberately the *same* status/title/detail as - // InvalidCredentials above -- this error is only reachable - // after the password has already been verified correct, so - // a distinguishable response here would let an attacker use - // login attempts as an oracle to confirm a guessed admin - // password (and that the account holds the Admin role) - // without ever completing a login. The real reason is only - // ever surfaced server-side via this log line. warn!( user_id, role = %role, email = %login_email, - "Login blocked: MFA is required for this role but is not enrolled" + "Starting required MFA enrollment for role" ); - record_login_failure( + let setup = state.user_service.setup_mfa(user_id).await.map_err(|error| { + error!(user_id, error = %error, "Failed to prepare resumable MFA enrollment"); + problem_new(StatusCode::INTERNAL_SERVER_ERROR) + .with_title("MFA Enrollment Failed") + .with_detail("Could not start MFA enrollment. Please try again.") + })?; + let mfa_token = state.auth_service.create_mfa_session(user_id).await.map_err(|error| { + error!(user_id, error = %error, "Failed to create MFA enrollment challenge"); + problem_new(StatusCode::INTERNAL_SERVER_ERROR) + .with_title("MFA Enrollment Failed") + .with_detail("Could not start MFA enrollment. Please try again.") + })?; + let encrypted_token = state.cookie_crypto.encrypt(&mfa_token).map_err(|error| { + error!(user_id, error = %error, "Failed to encrypt MFA enrollment challenge"); + problem_new(StatusCode::INTERNAL_SERVER_ERROR) + .with_title("MFA Enrollment Failed") + .with_detail("Could not start MFA enrollment. Please try again.") + })?; + let mfa_cookie = Cookie::build(("mfa_session", encrypted_token)) + .http_only(true) + .path("/") + .max_age(cookie::time::Duration::minutes(5)) + .same_site(cookie::SameSite::Strict) + .secure(metadata.is_secure) + .build(); + let cookie_header = mfa_cookie.to_string().parse().map_err(|error| { + error!(user_id, error = %error, "Failed to create MFA enrollment cookie"); + problem_new(StatusCode::INTERNAL_SERVER_ERROR) + .with_title("MFA Enrollment Failed") + .with_detail("Could not start MFA enrollment. Please try again.") + })?; + let mut headers = HeaderMap::new(); + headers.insert(SET_COOKIE, cookie_header); + + record_pending_login( state.as_ref(), &metadata, - Some(user_id), - &login_email, - "password", - "mfa_required_for_role", + user_id, + "password-mfa-enrollment-pending", ) .await; - Err(problem_new(StatusCode::UNAUTHORIZED) - .with_title("Invalid Credentials") - .with_detail("Invalid email or password.")) + + Ok(( + headers, + Json(AuthResponse { + success: false, + message: "Multi-factor authentication setup required".to_string(), + user_id: Some(user_id), + mfa_required: false, + mfa_enrollment_required: true, + mfa_setup: Some(MfaSetupResponse { + secret_key: setup.secret_key, + qr_code: setup.qr_code, + recovery_codes: setup.recovery_codes, + }), + password_change_required: false, + }), + )) } _ => { // Log the real error server-side (email is PII but legitimate @@ -1284,6 +1455,9 @@ pub async fn request_password_reset( .to_string(), user_id: None, mfa_required: false, + mfa_enrollment_required: false, + mfa_setup: None, + password_change_required: false, })) } } @@ -1333,12 +1507,175 @@ pub async fn reset_password( .to_string(), user_id: None, mfa_required: false, + mfa_enrollment_required: false, + mfa_setup: None, + password_change_required: false, })) } - Err(e) => Err(problem_new(StatusCode::BAD_REQUEST) - .with_title("Password Reset Failed") - .with_detail(e.to_string())), + Err(crate::auth_service::UserAuthError::InvalidToken) => { + Err(problem_new(StatusCode::BAD_REQUEST) + .with_title("Password Reset Failed") + .with_detail("The password reset link is invalid or expired.")) + } + Err(crate::auth_service::UserAuthError::WeakPassword(message)) => { + Err(problem_new(StatusCode::BAD_REQUEST) + .with_title("Password Requirements Not Met") + .with_detail(message)) + } + Err(crate::auth_service::UserAuthError::SamePassword) => { + Err(problem_new(StatusCode::BAD_REQUEST) + .with_title("Choose a Different Password") + .with_detail("Your new password must differ from the temporary password.")) + } + Err(error) => { + error!(error = %error, "Password reset failed internally"); + Err(problem_new(StatusCode::INTERNAL_SERVER_ERROR) + .with_title("Password Reset Failed") + .with_detail("Could not reset the password. Please try again.")) + } + } +} + +#[utoipa::path( + post, + path = "/auth/password-change-required", + request_body = RequiredPasswordChangeRequest, + responses( + (status = 200, description = "Required password change completed", body = RequiredPasswordChangeResponse), + (status = 400, description = "Password does not meet requirements"), + (status = 401, description = "Password-change session is missing or expired"), + (status = 500, description = "Internal server error") + ), + tag = "Authentication" +)] +pub async fn change_required_password( + State(state): State>, + Extension(metadata): Extension, + headers: HeaderMap, + Json(request): Json, +) -> Result { + let encrypted_token = headers + .get_all("Cookie") + .iter() + .filter_map(|value| value.to_str().ok()) + .flat_map(|cookie_header| Cookie::split_parse(cookie_header).filter_map(Result::ok)) + .find_map(|cookie| { + (cookie.name() == "password_change_session").then(|| cookie.value().to_string()) + }) + .ok_or_else(|| { + problem_new(StatusCode::UNAUTHORIZED) + .with_title("Password Change Session Required") + .with_detail("Log in again to restart the required password change.") + })?; + + let token = state + .cookie_crypto + .decrypt(&encrypted_token) + .map_err(|error| { + warn!(error = %error, "Rejected invalid required password-change cookie"); + problem_new(StatusCode::UNAUTHORIZED) + .with_title("Password Change Session Expired") + .with_detail("Log in again to restart the required password change.") + })?; + + let pending_user = state + .auth_service + .required_password_change_user(&token) + .await + .map_err(|error| { + error!(error = %error, "Failed to resolve required password-change session"); + problem_new(StatusCode::UNAUTHORIZED) + .with_title("Password Change Session Expired") + .with_detail("Log in again to restart the required password change.") + })?; + + // Prepare the response cookie before changing the password. If header + // construction fails, the temporary credential remains usable and the + // user can safely retry instead of being locked out. + let clear_cookie = Cookie::build(("password_change_session", "")) + .http_only(true) + .path("/") + .max_age(cookie::time::Duration::seconds(0)) + .same_site(cookie::SameSite::Strict) + .secure(metadata.is_secure) + .build(); + let cookie_header = clear_cookie.to_string().parse().map_err(|error| { + error!(error = %error, "Failed to clear required password-change cookie"); + problem_new(StatusCode::INTERNAL_SERVER_ERROR) + .with_title("Password Change Failed") + .with_detail("Could not prepare the password change. Please try again.") + })?; + let mut response_headers = HeaderMap::new(); + response_headers.append(SET_COOKIE, cookie_header); + + let requires_mfa_enrollment = state + .auth_service + .requires_mfa_enrollment(pending_user.id) + .await + .map_err(|error| { + error!(user_id = pending_user.id, error = %error, "Failed to evaluate MFA enrollment policy"); + problem_new(StatusCode::INTERNAL_SERVER_ERROR) + .with_title("Password Change Failed") + .with_detail("Could not prepare required MFA enrollment. Please try again.") + })?; + + let user = state + .auth_service + .reset_required_password(crate::auth_service::ResetPasswordRequest { + token, + new_password: request.new_password, + }) + .await + .map_err(|error| match error { + crate::auth_service::UserAuthError::WeakPassword(message) => { + problem_new(StatusCode::BAD_REQUEST) + .with_title("Password Requirements Not Met") + .with_detail(message) + } + crate::auth_service::UserAuthError::SamePassword => { + problem_new(StatusCode::BAD_REQUEST) + .with_title("Choose a Different Password") + .with_detail("Your new password must differ from the temporary password.") + } + crate::auth_service::UserAuthError::InvalidToken => { + problem_new(StatusCode::UNAUTHORIZED) + .with_title("Password Change Session Expired") + .with_detail("Log in again to restart the required password change.") + } + internal_error => { + error!(error = %internal_error, "Required password change failed internally"); + problem_new(StatusCode::INTERNAL_SERVER_ERROR) + .with_title("Password Change Failed") + .with_detail("Could not change the password. Please try again.") + } + })?; + + let audit = PasswordResetAudit { + context: AuditContext { + user_id: user.id, + ip_address: Some(metadata.ip_address.to_string()), + user_agent: metadata.user_agent.as_str().to_string(), + }, + username: user.name, + }; + if let Err(error) = state.audit_service.create_audit_log(&audit).await { + error!(user_id = user.id, error = %error, "Failed to audit required password change"); } + + Ok(( + response_headers, + Json(RequiredPasswordChangeResponse { + success: true, + message: if requires_mfa_enrollment { + "Password changed. Log in to set up multi-factor authentication.".to_string() + } else { + "Password changed. Log in with your new password.".to_string() + }, + user_id: user.id, + mfa_enrollment_required: requires_mfa_enrollment, + mfa_setup: None, + }), + )) } #[utoipa::path( @@ -1387,6 +1724,9 @@ pub async fn verify_email( message: "Email verified successfully. You can now login.".to_string(), user_id: None, mfa_required: false, + mfa_enrollment_required: false, + mfa_setup: None, + password_change_required: false, })) } Err(e) => Err(problem_new(StatusCode::BAD_REQUEST) @@ -1422,6 +1762,12 @@ impl From for Problem { UserServiceError::MfaNotSetup(user_id) => problem_new(StatusCode::BAD_REQUEST) .with_title("MFA not setup") .with_detail(format!("MFA is not setup for user {}", user_id)), + UserServiceError::MfaAlreadyEnabled(user_id) => problem_new(StatusCode::CONFLICT) + .with_title("MFA already enabled") + .with_detail(format!( + "MFA is already enabled for user {}. Disable it with current MFA verification before setting it up again.", + user_id + )), UserServiceError::AlreadyDeleted(user_id) => problem_new(StatusCode::BAD_REQUEST) .with_title("User already deleted") .with_detail(format!("User {} is already deleted", user_id)), @@ -1746,12 +2092,9 @@ async fn create_user( warn!("No password provided for new user - user will not be able to login with password!"); } - // Convert role strings to RoleTypes - let roles: Vec = create_req - .roles - .iter() - .filter_map(|r| RoleType::from_str(r).ok()) - .collect(); + // Reject the entire request if any role is unknown. Silently discarding a + // role can create a different account than the administrator approved. + let roles = parse_user_roles(&create_req.roles)?; let user = app_state .user_service @@ -1760,6 +2103,7 @@ async fn create_user( create_req.email.clone().unwrap_or("".to_string()), create_req.password.clone(), roles.clone(), + create_req.must_change_password, ) .await?; @@ -1775,7 +2119,7 @@ async fn create_user( let user_audit = UserCreatedAudit { context: audit_context, target_user_id: user.user.id, - username: create_req.username.clone(), + username: user.user.name.clone(), assigned_roles: roles.iter().map(|r| r.to_string()).collect(), }; @@ -2155,6 +2499,7 @@ async fn restore_user( responses( (status = 200, description = "MFA setup data", body = MfaSetupResponse), (status = 401, description = "Unauthorized"), + (status = 409, description = "MFA is already enabled; verify and disable it before re-enrollment"), (status = 500, description = "Internal server error") ), security( @@ -2394,15 +2739,17 @@ async fn disable_mfa( mod tests { use super::{ assign_role, authorize_admin_target, authorize_role_assignment, bounded_audit_identity, - create_user, delete_user, login, normalized_login_email, remove_role, restore_user, - update_user, verify_mfa_challenge, AdminTargetDenied, AssignRoleRequest, CreateUserRequest, - LoginRequest, RoleChangeDenied, UpdateUserRequest, + create_user, delete_user, login, normalized_login_email, parse_user_roles, + record_pending_login, remove_role, restore_user, update_user, verify_mfa_challenge, + AdminTargetDenied, AssignRoleRequest, CreateUserRequest, LoginRequest, RoleChangeDenied, + UpdateUserRequest, }; use crate::auth_service::UserAuthError; use crate::context::AuthContext; use crate::permissions::{Permission, Role}; use crate::state::AuthState; use crate::types::MfaVerificationRequest; + use crate::user_service::UserServiceError; use crate::RequireAuth; use async_trait::async_trait; use axum::extract::{Path, State}; @@ -2416,6 +2763,7 @@ mod tests { EmailMessage, NotificationData, NotificationError, NotificationService, }; use temps_core::{AuditLogger, RequestMetadata}; + use temps_entities::types::RoleType; use temps_entities::{roles, sessions, user_roles, users}; // Regression tests for the user-management privilege-escalation hole. The @@ -2440,6 +2788,7 @@ mod tests { email_verification_expires: None, password_reset_token: None, password_reset_expires: None, + must_change_password: false, deleted_at: None, mfa_secret: None, mfa_enabled: false, @@ -2643,6 +2992,18 @@ mod tests { assert!(std::str::from_utf8(bounded.as_bytes()).is_ok()); } + #[test] + fn create_user_roles_are_strictly_validated() { + assert_eq!( + parse_user_roles(&["user".to_string(), "admin".to_string()]) + .expect("known roles should parse"), + vec![RoleType::User, RoleType::Admin] + ); + + let result = parse_user_roles(&["user".to_string(), "administrator".to_string()]); + assert!(matches!(result, Err(UserServiceError::Validation(_)))); + } + #[tokio::test] async fn invalid_login_identifier_is_audited_without_querying_the_database() { let audit = Arc::new(RecordingAuditLogger::default()); @@ -2706,6 +3067,53 @@ mod tests { ); } + #[tokio::test] + async fn pending_password_and_mfa_logins_are_durably_audited() { + let audit = Arc::new(RecordingAuditLogger::default()); + let state = auth_state_with_audit( + MockDatabase::new(DatabaseBackend::Postgres).into_connection(), + audit.clone(), + ); + let metadata = request_metadata(); + + record_pending_login(state.as_ref(), &metadata, 41, "password-change-required").await; + record_pending_login( + state.as_ref(), + &metadata, + 42, + "password-mfa-enrollment-pending", + ) + .await; + + let events = audit.events(); + assert_eq!(events.len(), 2); + assert_eq!(events[0].operation_type, "LOGIN_SUCCESS"); + assert_eq!(events[0].user_id, Some(41)); + assert_eq!(events[0].data["login_method"], "password-change-required"); + assert_eq!(events[1].operation_type, "LOGIN_SUCCESS"); + assert_eq!(events[1].user_id, Some(42)); + assert_eq!( + events[1].data["login_method"], + "password-mfa-enrollment-pending" + ); + } + + #[tokio::test] + async fn pending_login_audit_failure_does_not_block_authentication_progress() { + let state = auth_state_with_audit( + MockDatabase::new(DatabaseBackend::Postgres).into_connection(), + Arc::new(FailingAuditLogger), + ); + + record_pending_login( + state.as_ref(), + &request_metadata(), + 41, + "password-change-required", + ) + .await; + } + #[tokio::test] async fn invalid_credentials_are_audited_with_normalized_identity() { let audit = Arc::new(RecordingAuditLogger::default()); @@ -3063,6 +3471,7 @@ mod tests { // Requesting the admin role is the case the gate must stop a // restricted credential from performing. roles: vec!["admin".to_string()], + must_change_password: true, }), ) .await; diff --git a/crates/temps-auth/src/oidc_handler.rs b/crates/temps-auth/src/oidc_handler.rs index 2312ed4c9..05621d5a5 100644 --- a/crates/temps-auth/src/oidc_handler.rs +++ b/crates/temps-auth/src/oidc_handler.rs @@ -296,6 +296,70 @@ async fn complete_oidc_login( let return_to = OidcService::sanitize_return_to(login_state.return_to); + if user.must_change_password { + let reset_token = state + .auth_service + .create_required_password_change_token(user.id) + .await + .map_err(|error| OidcError::DiscoveryFailed { + issuer: provider.issuer_url.clone(), + reason: format!( + "failed to create required password-change session for user {}: {error}", + user.id + ), + })?; + let encrypted_token = state.cookie_crypto.encrypt(&reset_token).map_err(|error| { + OidcError::DiscoveryFailed { + issuer: provider.issuer_url.clone(), + reason: format!( + "failed to encrypt required password-change session for user {}: {error}", + user.id + ), + } + })?; + let password_change_cookie = Cookie::build(("password_change_session", encrypted_token)) + .http_only(true) + .path("/") + .max_age(cookie::time::Duration::minutes(15)) + .same_site(cookie::SameSite::Strict) + .secure(metadata.is_secure) + .build(); + let cookie_header = password_change_cookie + .to_string() + .parse() + .map_err(|error| OidcError::DiscoveryFailed { + issuer: provider.issuer_url.clone(), + reason: format!( + "failed to build required password-change cookie for user {}: {error}", + user.id + ), + })?; + let mut headers = HeaderMap::new(); + headers.insert(SET_COOKIE, cookie_header); + + if let Err(error) = state + .audit_service + .create_audit_log(&LoginAudit { + context: AuditContext { + user_id: user.id, + ip_address: Some(metadata.ip_address.to_string()), + user_agent: metadata.user_agent.as_str().to_string(), + }, + success: true, + login_method: "oidc-password-change-required".to_string(), + }) + .await + { + error!( + user_id = user.id, + error = %error, + "Failed to audit OIDC required password-change redirect" + ); + } + + return Ok((headers, Redirect::to("/auth/change-password")).into_response()); + } + if user.mfa_enabled { let mfa_token = state .auth_service diff --git a/crates/temps-auth/src/oidc_service.rs b/crates/temps-auth/src/oidc_service.rs index 1d27ffbf8..92ddbcf23 100644 --- a/crates/temps-auth/src/oidc_service.rs +++ b/crates/temps-auth/src/oidc_service.rs @@ -852,7 +852,7 @@ impl OidcService { let created = self .user_service - .create_user(display_name, email.clone(), None, vec![role.clone()]) + .create_user(display_name, email.clone(), None, vec![role.clone()], false) .await .map_err(|e| OidcError::DiscoveryFailed { issuer: provider.issuer_url.clone(), diff --git a/crates/temps-auth/src/permission_guard.rs b/crates/temps-auth/src/permission_guard.rs index ec962c748..beedb77f4 100644 --- a/crates/temps-auth/src/permission_guard.rs +++ b/crates/temps-auth/src/permission_guard.rs @@ -435,6 +435,7 @@ mod tests { email_verification_expires: None, password_reset_token: None, password_reset_expires: None, + must_change_password: false, deleted_at: None, mfa_secret: None, mfa_enabled: false, diff --git a/crates/temps-auth/src/permissions.rs b/crates/temps-auth/src/permissions.rs index 20165f6a0..058a94861 100644 --- a/crates/temps-auth/src/permissions.rs +++ b/crates/temps-auth/src/permissions.rs @@ -802,7 +802,6 @@ impl Role { Permission::PlatformInfoRead, Permission::ProjectsCreate, Permission::ProjectsDelete, - Permission::ProjectsDelete, Permission::ProjectsRead, Permission::ProjectsWrite, Permission::SessionMetricsRead, diff --git a/crates/temps-auth/src/sensitive_action.rs b/crates/temps-auth/src/sensitive_action.rs index 857c92ec3..448dd25a5 100644 --- a/crates/temps-auth/src/sensitive_action.rs +++ b/crates/temps-auth/src/sensitive_action.rs @@ -326,6 +326,7 @@ mod tests { email_verification_expires: None, password_reset_token: None, password_reset_expires: None, + must_change_password: false, deleted_at: None, mfa_secret: mfa_enabled.then(|| "JBSWY3DPEHPK3PXPJBSWY3DPEHPK3PXP".to_string()), mfa_enabled, diff --git a/crates/temps-auth/src/types.rs b/crates/temps-auth/src/types.rs index 25e33d5e8..c445be028 100644 --- a/crates/temps-auth/src/types.rs +++ b/crates/temps-auth/src/types.rs @@ -73,6 +73,7 @@ pub struct RouteUser { pub image: String, pub mfa_enabled: bool, pub email_verified: bool, + pub must_change_password: bool, #[schema(format = "int64", example = "1683900000000")] pub created_at: i64, #[schema(format = "int64", example = "1683900000000")] @@ -108,6 +109,8 @@ pub struct CreateUserRequest { pub email: Option, pub password: Option, pub roles: Vec, + #[serde(default)] + pub must_change_password: bool, } #[derive(Deserialize, utoipa::ToSchema)] @@ -167,7 +170,7 @@ pub struct StepUpResponse { pub expires_at: String, } -#[derive(Serialize, utoipa::ToSchema)] +#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)] pub struct MfaSetupResponse { pub secret_key: String, pub qr_code: String, @@ -190,6 +193,7 @@ impl From for RouteUser { image: generate_avatar_data_url(&db_user.name), mfa_enabled: db_user.mfa_enabled, email_verified: db_user.email_verified, + must_change_password: db_user.must_change_password, created_at: db_user.created_at.timestamp_millis(), updated_at: db_user.updated_at.timestamp_millis(), deleted_at: db_user.deleted_at.map(|d| d.timestamp_millis()), @@ -218,6 +222,7 @@ impl From for RouteUser { image: service_user.image, mfa_enabled: service_user.mfa_enabled, email_verified: service_user.email_verified, + must_change_password: service_user.must_change_password, created_at: service_user.created_at.timestamp_millis(), updated_at: service_user.updated_at.timestamp_millis(), deleted_at: service_user.deleted_at.map(|d| d.timestamp_millis()), diff --git a/crates/temps-auth/src/user_service.rs b/crates/temps-auth/src/user_service.rs index 6b74b5c2a..6cfbb46fe 100644 --- a/crates/temps-auth/src/user_service.rs +++ b/crates/temps-auth/src/user_service.rs @@ -8,14 +8,61 @@ use sea_orm::{ QueryFilter, QueryOrder, QuerySelect, Set, TransactionTrait, }; use serde::{Deserialize, Serialize}; +use std::collections::HashMap; use std::io::Cursor; use std::sync::Arc; use temps_core::UtcDateTime; use temps_entities::types::RoleType; use thiserror::Error; +use tokio::sync::{Mutex, OwnedMutexGuard, OwnedSemaphorePermit, Semaphore}; use totp_rs::{Algorithm, Secret, TOTP}; use tracing::{debug, error, info, warn}; +const MAX_USER_EMAIL_BYTES: usize = 254; +const MAX_USER_NAME_CHARS: usize = 100; +const MAX_CONCURRENT_MFA_SETUPS: usize = 2; + +pub(crate) fn normalize_user_email(email: &str) -> Option { + let normalized = email.trim().to_lowercase(); + if normalized.is_empty() + || normalized.len() > MAX_USER_EMAIL_BYTES + || normalized.chars().any(char::is_whitespace) + || normalized.chars().any(char::is_control) + { + return None; + } + + let (local, domain) = normalized.split_once('@')?; + if local.is_empty() + || local.len() > 64 + || local.starts_with('.') + || local.ends_with('.') + || local.contains("..") + || domain.is_empty() + || domain.contains('@') + || domain.starts_with('.') + || domain.ends_with('.') + { + return None; + } + + let labels: Vec<_> = domain.split('.').collect(); + if labels.len() < 2 + || labels.iter().any(|label| { + label.is_empty() + || label.starts_with('-') + || label.ends_with('-') + || !label + .chars() + .all(|character| character.is_ascii_alphanumeric() || character == '-') + }) + { + return None; + } + + Some(normalized) +} + // First add the custom error type at the top of the file #[derive(Error, Debug)] pub enum UserServiceError { @@ -40,6 +87,9 @@ pub enum UserServiceError { #[error("MFA not set up for user {0}")] MfaNotSetup(i32), + #[error("MFA is already enabled for user {0}")] + MfaAlreadyEnabled(i32), + #[error("User {0} is already deleted")] AlreadyDeleted(i32), @@ -89,6 +139,78 @@ pub struct MfaSetupData { pub recovery_codes: Vec, } +struct MfaSetupCandidate { + secret_key: String, + qr_code: String, + recovery_codes: Vec, + hashed_recovery_codes: Vec, +} + +fn generate_mfa_setup_candidate(email: &str) -> Result { + use argon2::password_hash::{rand_core::OsRng, PasswordHasher, SaltString}; + use argon2::Argon2; + + let secret: Vec = (0..20).map(|_| rand::rng().random::()).collect(); + let secret_key = base32::encode(base32::Alphabet::Rfc4648 { padding: true }, &secret); + let recovery_codes: Vec = (0..8) + .map(|_| { + (0..6) + .map(|_| rand::rng().random_range(0..10).to_string()) + .collect() + }) + .collect(); + + let argon2 = Argon2::default(); + let hashed_recovery_codes = recovery_codes + .iter() + .map(|code| { + let salt = SaltString::generate(&mut OsRng); + argon2 + .hash_password(code.as_bytes(), &salt) + .map(|hash| hash.to_string()) + .map_err(|error| { + UserServiceError::Mfa(format!("Failed to hash MFA recovery code: {}", error)) + }) + }) + .collect::, _>>()?; + + TOTP::new( + Algorithm::SHA1, + 6, + 1, + 30, + Secret::Raw(secret).to_bytes().map_err(|error| { + UserServiceError::Mfa(format!("Failed to create TOTP secret: {}", error)) + })?, + ) + .map_err(|error| UserServiceError::Mfa(format!("Failed to create TOTP: {}", error)))?; + + let otp_auth_url = format!( + "otpauth://totp/Temps:{}?secret={}&issuer=Temps&algorithm=SHA1&digits=6&period=30", + email, secret_key + ); + let qr = QrCode::new(otp_auth_url) + .map_err(|error| UserServiceError::Mfa(format!("Failed to generate QR code: {}", error)))?; + let qr_image = qr.render::>().quiet_zone(false).build(); + let mut bytes = Vec::new(); + qr_image + .write_to(&mut Cursor::new(&mut bytes), image::ImageFormat::Png) + .map_err(|error| { + UserServiceError::Mfa(format!("Failed to encode MFA QR code: {}", error)) + })?; + let qr_code = format!( + "data:image/png;base64,{}", + base64::engine::general_purpose::STANDARD.encode(bytes) + ); + + Ok(MfaSetupCandidate { + secret_key, + qr_code, + recovery_codes, + hashed_recovery_codes, + }) +} + #[derive(Debug, Serialize, Deserialize)] pub struct ServiceUser { pub id: i32, @@ -97,6 +219,7 @@ pub struct ServiceUser { pub image: String, pub mfa_enabled: bool, pub email_verified: bool, + pub must_change_password: bool, pub deleted_at: Option, pub created_at: UtcDateTime, pub updated_at: UtcDateTime, @@ -125,6 +248,7 @@ impl From for ServiceUser { image: generate_avatar_data_url(&db_user.name), mfa_enabled: db_user.mfa_enabled, email_verified: db_user.email_verified, + must_change_password: db_user.must_change_password, deleted_at: db_user.deleted_at, created_at: db_user.created_at, updated_at: db_user.updated_at, @@ -145,11 +269,64 @@ impl From for ServiceRole { pub struct UserService { db: Arc, + mfa_setup_global: Arc, + mfa_setup_users: Arc>>>>, +} + +struct MfaSetupPermit { + _user: OwnedMutexGuard<()>, + _global: OwnedSemaphorePermit, +} + +async fn run_mfa_setup_blocking( + permit: MfaSetupPermit, + work: F, +) -> Result<(MfaSetupPermit, T), UserServiceError> +where + T: Send + 'static, + F: FnOnce() -> Result + Send + 'static, +{ + let (permit, result) = tokio::task::spawn_blocking(move || (permit, work())) + .await + .map_err(|error| { + UserServiceError::Internal(format!("MFA setup worker failed: {}", error)) + })?; + Ok((permit, result?)) } impl UserService { pub fn new(db: Arc) -> Self { - Self { db } + Self { + db, + mfa_setup_global: Arc::new(Semaphore::new(MAX_CONCURRENT_MFA_SETUPS)), + mfa_setup_users: Arc::new(Mutex::new(HashMap::new())), + } + } + + async fn acquire_mfa_setup_permit( + &self, + user_id: i32, + ) -> Result { + let user_lock = { + let mut users = self.mfa_setup_users.lock().await; + users + .entry(user_id) + .or_insert_with(|| Arc::new(Mutex::new(()))) + .clone() + }; + let user = user_lock.lock_owned().await; + let global = self + .mfa_setup_global + .clone() + .acquire_owned() + .await + .map_err(|_| { + UserServiceError::Internal("MFA setup concurrency limiter closed".to_string()) + })?; + Ok(MfaSetupPermit { + _user: user, + _global: global, + }) } pub async fn initialize_roles(&self) -> Result<(), UserServiceError> { @@ -391,9 +568,44 @@ impl UserService { email: String, password: Option, roles: Vec, - ) -> anyhow::Result { + must_change_password: bool, + ) -> Result { let now = Utc::now(); + let username = username.trim().to_string(); + let username_chars = username.chars().count(); + if !(1..=MAX_USER_NAME_CHARS).contains(&username_chars) + || username.chars().any(char::is_control) + { + return Err(UserServiceError::Validation(format!( + "Name must contain between 1 and {MAX_USER_NAME_CHARS} characters" + ))); + } + + let email = normalize_user_email(&email).ok_or_else(|| { + UserServiceError::Validation("A valid email address is required".to_string()) + })?; + + if roles.is_empty() { + return Err(UserServiceError::Validation( + "At least one valid role is required".to_string(), + )); + } + + let mut role_names = std::collections::HashSet::new(); + if roles.iter().any(|role| !role_names.insert(role.as_str())) { + return Err(UserServiceError::Validation( + "Duplicate roles are not allowed".to_string(), + )); + } + + if must_change_password && password.is_none() { + return Err(UserServiceError::Validation( + "A temporary password is required when first-login password change is enabled" + .to_string(), + )); + } + // Hash password if provided using Argon2 (same as auth_service for consistency) let password_hash = if let Some(pwd) = password { // Validate password complexity @@ -423,7 +635,38 @@ impl UserService { None }; - // Create the user + let transaction = self.db.begin().await?; + + // Resolve every role before writing the user. This both produces a + // precise error and prevents a missing role from creating an account + // that cannot be administered as intended. + let mut resolved_roles = Vec::with_capacity(roles.len()); + for role_type in roles { + let role = temps_entities::roles::Entity::find() + .filter(temps_entities::roles::Column::Name.eq(role_type.as_str())) + .one(&transaction) + .await? + .ok_or_else(|| { + UserServiceError::RoleNotFound(format!("Role {} not found", role_type.as_str())) + }); + + match role { + Ok(role) => resolved_roles.push(role), + Err(error) => { + transaction.rollback().await.map_err(|rollback_error| { + UserServiceError::Database { + reason: format!( + "failed to roll back user creation after {error}: {rollback_error}" + ), + } + })?; + return Err(error); + } + } + } + + // Create the user and all role assignments atomically. If any write + // fails, dropping the uncommitted transaction rolls back every write. let new_user = temps_entities::users::ActiveModel { name: Set(username.clone()), email: Set(email.clone()), @@ -437,21 +680,23 @@ impl UserService { email_verification_expires: Set(None), password_reset_token: Set(None), password_reset_expires: Set(None), + must_change_password: Set(must_change_password), ..Default::default() }; - let user = new_user.insert(self.db.as_ref()).await?; + let user = new_user.insert(&transaction).await?; - // Assign roles - for role_type in roles { - let role = temps_entities::roles::Entity::find() - .filter(temps_entities::roles::Column::Name.eq(role_type.as_str())) - .one(self.db.as_ref()) - .await? - .ok_or_else(|| { - UserServiceError::RoleNotFound(format!("Role {} not found", role_type.as_str())) - })?; + // Build the response from the records already resolved inside this + // transaction. Once commit succeeds there must be no fallible read + // that can turn a successfully-created account into an HTTP 500. + let response_roles = resolved_roles + .iter() + .cloned() + .map(ServiceRole::from) + .collect(); + // Assign roles + for role in resolved_roles { let new_user_role = temps_entities::user_roles::ActiveModel { user_id: Set(user.id), role_id: Set(role.id), @@ -460,13 +705,16 @@ impl UserService { ..Default::default() }; - new_user_role.insert(self.db.as_ref()).await?; + new_user_role.insert(&transaction).await?; } - info!("Created new user with id: {}", user.id); + transaction.commit().await?; - // Fetch the user with roles to return - self.get_user_with_roles(user.id).await + info!("Created new user with id: {}", user.id); + Ok(UserWithRoles { + user: ServiceUser::from(user), + roles: response_roles, + }) } pub async fn delete_user( @@ -594,90 +842,60 @@ impl UserService { } pub async fn setup_mfa(&self, user_id: i32) -> Result { - let user = temps_entities::users::Entity::find_by_id(user_id) + // Serialize setup per user and cap total Argon2 work across accounts. + // This guard is acquired before any database or CPU work so repeated + // requests cannot amplify password hashing for one account. + let permit = self.acquire_mfa_setup_permit(user_id).await?; + + // Fetch the display identity before generating the candidate. The + // exclusive database lock below is only held for the final + // compare-and-write, never for Argon2 or QR rendering. + let initial_user = temps_entities::users::Entity::find_by_id(user_id) .one(self.db.as_ref()) .await? .ok_or_else(|| UserServiceError::NotFound(format!("User {} not found", user_id)))?; - // Generate random secret with explicit type - let secret: Vec = (0..20).map(|_| rand::rng().random::()).collect(); - let secret_b32 = base32::encode(base32::Alphabet::Rfc4648 { padding: true }, &secret); - - // Generate recovery codes - let recovery_codes: Vec = (0..8) - .map(|_| { - let code: String = (0..6) - .map(|_| rand::rng().random_range(0..10).to_string()) - .collect(); - code - }) - .collect(); - - // Hash recovery codes before storing using Argon2id - use argon2::password_hash::{rand_core::OsRng, PasswordHasher, SaltString}; - use argon2::Argon2; - - let argon2 = Argon2::default(); - let hashed_recovery_codes: Vec = recovery_codes - .iter() - .map(|code| { - let salt = SaltString::generate(&mut OsRng); - argon2 - .hash_password(code.as_bytes(), &salt) - .map(|hash| hash.to_string()) - .map_err(|e| { - UserServiceError::Mfa(format!("Failed to hash recovery code: {}", e)) - }) - }) - .collect::, UserServiceError>>()?; - - // Create TOTP with proper parameters & verify it - TOTP::new( - Algorithm::SHA1, - 6, - 1, - 30, - Secret::Raw(secret.clone()).to_bytes().map_err(|e| { - UserServiceError::Mfa(format!("Failed to create TOTP secret: {}", e)) - })?, - ) - .map_err(|e| UserServiceError::Mfa(format!("Failed to create TOTP: {}", e)))?; - - // Generate the otpauth URL manually - let otp_auth_url = format!( - "otpauth://totp/Temps:{}?secret={}&issuer=Temps&algorithm=SHA1&digits=6&period=30", - user.email, // Use email for MFA identifier - secret_b32 - ); - - // Generate QR code - let qr = QrCode::new(otp_auth_url) - .map_err(|e| UserServiceError::Mfa(format!("Failed to generate QR code: {}", e)))?; - let qr_image = qr.render::>().quiet_zone(false).build(); + if initial_user.mfa_enabled { + return Err(UserServiceError::MfaAlreadyEnabled(user_id)); + } - // Convert QR code to base64 PNG - let mut bytes: Vec = Vec::new(); - qr_image - .write_to(&mut Cursor::new(&mut bytes), image::ImageFormat::Png) - .map_err(|e| UserServiceError::Mfa(format!("Failed to encode QR code: {}", e)))?; - let qr_base64 = base64::engine::general_purpose::STANDARD.encode(&bytes); - let qr_data_url = format!("data:image/png;base64,{}", qr_base64); + // Argon2 and PNG encoding are intentionally kept off Tokio's async + // workers. An unverified enrollment is replaceable as one complete + // bundle, so every successful retry rotates all credentials together. + let email = initial_user.email; + // The permit moves into the non-cancellable blocking task. If the HTTP + // request is cancelled, Argon2 retains both guards until it actually + // exits instead of silently escaping the concurrency cap. + let (_permit, candidate) = + run_mfa_setup_blocking(permit, move || generate_mfa_setup_candidate(&email)).await?; + + // Lock only for the final state check and atomic bundle replacement. + // A concurrent request may have enabled MFA while the candidate was + // generated, so the condition must be checked again under the lock. + let transaction = self.db.begin().await?; + let user = temps_entities::users::Entity::find_by_id(user_id) + .lock_exclusive() + .one(&transaction) + .await? + .ok_or_else(|| UserServiceError::NotFound(format!("User {} not found", user_id)))?; + if user.mfa_enabled { + return Err(UserServiceError::MfaAlreadyEnabled(user_id)); + } - // Update user in database let mut user_update: temps_entities::users::ActiveModel = user.into(); - user_update.mfa_secret = Set(Some(secret_b32.clone())); + user_update.mfa_secret = Set(Some(candidate.secret_key.clone())); user_update.mfa_enabled = Set(false); user_update.mfa_recovery_codes = Set(Some( - serde_json::to_string(&hashed_recovery_codes) + serde_json::to_string(&candidate.hashed_recovery_codes) .map_err(UserServiceError::Serialization)?, )); - - user_update.update(self.db.as_ref()).await?; + user_update.update(&transaction).await?; + transaction.commit().await?; Ok(MfaSetupData { - secret_key: secret_b32, - qr_code: qr_data_url, - recovery_codes, + secret_key: candidate.secret_key, + qr_code: candidate.qr_code, + recovery_codes: candidate.recovery_codes, }) } @@ -827,7 +1045,7 @@ impl UserService { .map_err(|e| UserServiceError::Mfa(format!("Failed to verify TOTP code: {}", e))) } - pub async fn disable_mfa(&self, user_id: i32) -> Result<(), UserServiceError> { + async fn disable_mfa(&self, user_id: i32) -> Result<(), UserServiceError> { let transaction = self.db.begin().await?; let user = temps_entities::users::Entity::find_by_id(user_id) .lock_exclusive() @@ -859,7 +1077,7 @@ impl UserService { &self, user_id: i32, code: &str, - ) -> anyhow::Result<(), UserServiceError> { + ) -> Result<(), UserServiceError> { // First verify the code if !self.verify_mfa_code(user_id, code).await? { return Err(UserServiceError::Validation( @@ -876,7 +1094,7 @@ impl UserService { mod tests { use super::*; use argon2::password_hash::{rand_core::OsRng, PasswordHasher, SaltString}; - use sea_orm::{DatabaseBackend, MockDatabase, MockExecResult}; + use sea_orm::{DatabaseBackend, DbErr, MockDatabase, MockExecResult}; fn user(mfa_enabled: bool, recovery_codes: Option) -> temps_entities::users::Model { let now = Utc::now(); @@ -890,6 +1108,7 @@ mod tests { email_verification_expires: None, password_reset_token: None, password_reset_expires: None, + must_change_password: false, deleted_at: None, mfa_secret: mfa_enabled.then(|| "JBSWY3DPEHPK3PXPJBSWY3DPEHPK3PXP".to_string()), mfa_enabled, @@ -901,6 +1120,229 @@ mod tests { } } + fn role(role_type: RoleType) -> temps_entities::roles::Model { + let now = Utc::now(); + temps_entities::roles::Model { + id: match role_type { + RoleType::Admin => 1, + RoleType::User => 2, + }, + name: role_type.as_str().to_string(), + created_at: now, + updated_at: now, + } + } + + #[test] + fn user_email_is_normalized_and_strictly_validated() { + assert_eq!( + normalize_user_email(" Admin@Example.COM "), + Some("admin@example.com".to_string()) + ); + for invalid in ["", "missing-at.example.com", "@example.com", "user@"] { + assert_eq!(normalize_user_email(invalid), None, "accepted {invalid:?}"); + } + } + + #[tokio::test] + async fn create_user_rejects_invalid_identity_before_database_writes() { + let service = UserService::new(Arc::new( + MockDatabase::new(DatabaseBackend::Postgres).into_connection(), + )); + + let blank_name = service + .create_user( + " ".to_string(), + "valid@example.com".to_string(), + None, + vec![RoleType::User], + false, + ) + .await; + assert!(matches!(blank_name, Err(UserServiceError::Validation(_)))); + + let malformed_email = service + .create_user( + "Valid User".to_string(), + "not-an-email".to_string(), + None, + vec![RoleType::User], + false, + ) + .await; + assert!(matches!( + malformed_email, + Err(UserServiceError::Validation(_)) + )); + } + + #[tokio::test] + async fn create_user_requires_at_least_one_role() { + let service = UserService::new(Arc::new( + MockDatabase::new(DatabaseBackend::Postgres).into_connection(), + )); + + let result = service + .create_user( + "roleless".to_string(), + "roleless@example.com".to_string(), + None, + vec![], + false, + ) + .await; + + assert!(matches!(result, Err(UserServiceError::Validation(_)))); + } + + #[tokio::test] + async fn create_user_rejects_duplicate_roles() { + let service = UserService::new(Arc::new( + MockDatabase::new(DatabaseBackend::Postgres).into_connection(), + )); + + let result = service + .create_user( + "duplicate-role".to_string(), + "duplicate@example.com".to_string(), + None, + vec![RoleType::User, RoleType::User], + false, + ) + .await; + + assert!(matches!(result, Err(UserServiceError::Validation(_)))); + } + + #[tokio::test] + async fn create_user_does_not_insert_account_when_role_is_missing() { + let db = Arc::new( + MockDatabase::new(DatabaseBackend::Postgres) + .append_query_results([Vec::::new()]) + .into_connection(), + ); + let service = UserService::new(db.clone()); + + let result = service + .create_user( + "missing-role".to_string(), + "missing-role@example.com".to_string(), + None, + vec![RoleType::User], + false, + ) + .await; + + assert!(matches!(result, Err(UserServiceError::RoleNotFound(_)))); + drop(service); + let log = Arc::try_unwrap(db) + .expect("service released the database") + .into_transaction_log(); + let statements: Vec<_> = log + .iter() + .flat_map(|transaction| transaction.statements()) + .collect(); + assert!(statements + .iter() + .any(|statement| statement.sql.starts_with("SELECT"))); + assert!(!statements + .iter() + .any(|statement| statement.sql.starts_with("INSERT INTO \"users\""))); + } + + #[tokio::test] + async fn create_user_rolls_back_when_role_assignment_fails() { + let new_user = user(false, None); + let db = Arc::new( + MockDatabase::new(DatabaseBackend::Postgres) + .append_query_results([vec![role(RoleType::User)]]) + .append_query_results([vec![new_user]]) + .append_query_errors([DbErr::Custom( + "simulated role assignment failure".to_string(), + )]) + .into_connection(), + ); + let service = UserService::new(db.clone()); + + let result = service + .create_user( + "atomic-user".to_string(), + "atomic@example.com".to_string(), + None, + vec![RoleType::User], + false, + ) + .await; + + assert!(matches!(result, Err(UserServiceError::Database { .. }))); + drop(service); + let log = Arc::try_unwrap(db) + .expect("service released the database") + .into_transaction_log(); + assert_eq!( + log.len(), + 1, + "all provisioning writes share one transaction" + ); + let statements = log[0].statements(); + assert!(statements + .iter() + .any(|statement| statement.sql.starts_with("INSERT INTO \"users\""))); + assert!(statements + .iter() + .any(|statement| { statement.sql.starts_with("INSERT INTO \"user_roles\"") })); + } + + #[tokio::test] + async fn create_user_returns_committed_records_without_a_post_commit_read() { + let new_user = user(false, None); + let db = Arc::new( + MockDatabase::new(DatabaseBackend::Postgres) + .append_query_results([vec![role(RoleType::User)]]) + .append_query_results([vec![new_user.clone()]]) + .append_query_results([vec![temps_entities::user_roles::Model { + id: 1, + user_id: new_user.id, + role_id: 2, + created_at: Utc::now(), + updated_at: Utc::now(), + }]]) + .into_connection(), + ); + let service = UserService::new(db.clone()); + + let created = service + .create_user( + "Created User".to_string(), + "created@example.com".to_string(), + None, + vec![RoleType::User], + false, + ) + .await + .expect("committed user should be returned without another query"); + + assert_eq!(created.user.id, new_user.id); + assert_eq!(created.roles.len(), 1); + assert_eq!(created.roles[0].name, RoleType::User.as_str()); + drop(service); + let log = Arc::try_unwrap(db) + .expect("service released the database") + .into_transaction_log(); + let statements: Vec<_> = log + .iter() + .flat_map(|transaction| transaction.statements()) + .collect(); + assert_eq!( + statements + .iter() + .filter(|statement| statement.sql.starts_with("SELECT")) + .count(), + 1, + "only role resolution may read during account creation" + ); + } + #[tokio::test] async fn verification_fails_closed_when_mfa_is_disabled() { let db = Arc::new( @@ -914,6 +1356,190 @@ mod tests { assert!(matches!(result, Err(UserServiceError::MfaNotSetup(7)))); } + #[tokio::test] + async fn mfa_setup_limits_parallel_work_globally_and_per_user() { + use std::time::Duration; + + let service = UserService::new(Arc::new( + MockDatabase::new(DatabaseBackend::Postgres).into_connection(), + )); + let first_user = service + .acquire_mfa_setup_permit(7) + .await + .expect("first setup should acquire a permit"); + + let duplicate = tokio::time::timeout( + Duration::from_millis(25), + service.acquire_mfa_setup_permit(7), + ) + .await; + assert!( + duplicate.is_err(), + "a second setup for the same account must be serialized" + ); + + let second_user = service + .acquire_mfa_setup_permit(8) + .await + .expect("a second account may use the remaining global permit"); + let global_overflow = tokio::time::timeout( + Duration::from_millis(25), + service.acquire_mfa_setup_permit(9), + ) + .await; + assert!( + global_overflow.is_err(), + "MFA setup must cap total concurrent password hashing" + ); + + drop(first_user); + service + .acquire_mfa_setup_permit(9) + .await + .expect("a queued account should proceed after a permit is released"); + drop(second_user); + } + + #[tokio::test] + async fn cancelled_mfa_setup_holds_admission_until_blocking_work_exits() { + use std::sync::mpsc; + use std::time::Duration; + + let service = Arc::new(UserService::new(Arc::new( + MockDatabase::new(DatabaseBackend::Postgres).into_connection(), + ))); + let first = service + .acquire_mfa_setup_permit(7) + .await + .expect("first setup should acquire a permit"); + let second = service + .acquire_mfa_setup_permit(8) + .await + .expect("second setup should fill the global limit"); + let (started_tx, started_rx) = tokio::sync::oneshot::channel(); + let (release_tx, release_rx) = mpsc::channel(); + + let task = tokio::spawn(run_mfa_setup_blocking(first, move || { + let _ = started_tx.send(()); + release_rx.recv().map_err(|error| { + UserServiceError::Internal(format!( + "MFA cancellation test release failed: {}", + error + )) + })?; + Ok(()) + })); + started_rx + .await + .expect("blocking setup should report that it started"); + task.abort(); + let cancelled = task.await; + assert!(matches!(cancelled, Err(error) if error.is_cancelled())); + + assert!( + tokio::time::timeout( + Duration::from_millis(25), + service.acquire_mfa_setup_permit(7) + ) + .await + .is_err(), + "cancellation must not release the per-user guard while work continues" + ); + assert!( + tokio::time::timeout( + Duration::from_millis(25), + service.acquire_mfa_setup_permit(9) + ) + .await + .is_err(), + "cancellation must not release the global permit while work continues" + ); + + release_tx + .send(()) + .expect("blocking work should still own its release receiver"); + tokio::time::timeout(Duration::from_secs(1), service.acquire_mfa_setup_permit(9)) + .await + .expect("permit should be released after blocking work exits") + .expect("limiter should remain open"); + drop(second); + } + + #[tokio::test] + async fn setup_mfa_retry_rotates_complete_unverified_credential_bundle() { + let mut pending = user(false, Some("[\"existing-hash\"]".to_string())); + pending.mfa_secret = Some("JBSWY3DPEHPK3PXPJBSWY3DPEHPK3PXP".to_string()); + let updated = pending.clone(); + let db = Arc::new( + MockDatabase::new(DatabaseBackend::Postgres) + .append_query_results([vec![pending.clone()], vec![pending], vec![updated]]) + .into_connection(), + ); + let service = UserService::new(db.clone()); + + let setup = service + .setup_mfa(7) + .await + .expect("pending MFA setup should be resumable"); + + assert_ne!(setup.secret_key, "JBSWY3DPEHPK3PXPJBSWY3DPEHPK3PXP"); + assert_eq!(setup.recovery_codes.len(), 8); + assert!(setup.recovery_codes.iter().all( + |code| code.len() == 6 && code.chars().all(|character| character.is_ascii_digit()) + )); + assert!(setup.qr_code.starts_with("data:image/png;base64,")); + + drop(service); + let log = Arc::try_unwrap(db) + .expect("service released the database") + .into_transaction_log(); + let statements: Vec<_> = log + .iter() + .flat_map(|transaction| transaction.statements()) + .collect(); + assert!(statements + .iter() + .any(|statement| statement.sql.contains("FOR UPDATE"))); + assert!(statements + .iter() + .any(|statement| statement.sql.starts_with("UPDATE \"users\""))); + } + + #[tokio::test] + async fn setup_mfa_rechecks_enabled_state_under_the_write_lock() { + let pending = user(false, Some("[\"pending-hash\"]".to_string())); + let enabled = user(true, Some("[\"existing-hash\"]".to_string())); + let expected_secret = enabled.mfa_secret.clone(); + let db = Arc::new( + MockDatabase::new(DatabaseBackend::Postgres) + .append_query_results([vec![pending], vec![enabled]]) + .into_connection(), + ); + let service = UserService::new(db.clone()); + + let result = service.setup_mfa(7).await; + + assert!(matches!( + result, + Err(UserServiceError::MfaAlreadyEnabled(7)) + )); + drop(service); + let log = Arc::try_unwrap(db) + .expect("service released the database") + .into_transaction_log(); + let statements: Vec<_> = log + .iter() + .flat_map(|transaction| transaction.statements()) + .collect(); + assert!(statements + .iter() + .any(|statement| statement.sql.contains("FOR UPDATE"))); + assert!(!statements + .iter() + .any(|statement| statement.sql.starts_with("UPDATE \"users\""))); + assert!(expected_secret.is_some()); + } + #[tokio::test] async fn recovery_code_is_consumed_under_an_exclusive_row_lock() { let recovery_code = "RECOVERY-CODE"; diff --git a/crates/temps-auth/tests/context_tests.rs b/crates/temps-auth/tests/context_tests.rs index b903327fc..e85b0ef71 100644 --- a/crates/temps-auth/tests/context_tests.rs +++ b/crates/temps-auth/tests/context_tests.rs @@ -14,6 +14,7 @@ fn create_mock_user() -> users::Model { email_verification_expires: None, password_reset_token: None, password_reset_expires: None, + must_change_password: false, deleted_at: None, mfa_secret: None, mfa_enabled: false, diff --git a/crates/temps-blob/src/handlers/handler.rs b/crates/temps-blob/src/handlers/handler.rs index 504e21216..abb4ff04e 100644 --- a/crates/temps-blob/src/handlers/handler.rs +++ b/crates/temps-blob/src/handlers/handler.rs @@ -1033,6 +1033,7 @@ mod idor_tests { email_verification_expires: None, password_reset_token: None, password_reset_expires: None, + must_change_password: false, deleted_at: None, mfa_secret: None, mfa_enabled: false, diff --git a/crates/temps-cli/src/commands/serve/console.rs b/crates/temps-cli/src/commands/serve/console.rs index 1775d1614..29e9ee209 100644 --- a/crates/temps-cli/src/commands/serve/console.rs +++ b/crates/temps-cli/src/commands/serve/console.rs @@ -369,6 +369,7 @@ async fn ensure_system_user(db: &sea_orm::DatabaseConnection) -> anyhow::Result< email_verification_expires: Set(None), password_reset_token: Set(None), password_reset_expires: Set(None), + must_change_password: Set(false), deleted_at: Set(None), mfa_enabled: Set(false), mfa_secret: Set(None), @@ -3310,6 +3311,7 @@ mod initial_admin_tests { email_verification_expires: None, password_reset_token: None, password_reset_expires: None, + must_change_password: false, deleted_at: None, mfa_secret: None, mfa_enabled: false, @@ -3373,6 +3375,7 @@ mod ai_tool_allowlist_tests { email_verification_expires: None, password_reset_token: None, password_reset_expires: None, + must_change_password: false, deleted_at: None, mfa_secret: None, mfa_enabled: false, diff --git a/crates/temps-cli/src/commands/setup.rs b/crates/temps-cli/src/commands/setup.rs index 4b5137c31..2ab74a3ba 100644 --- a/crates/temps-cli/src/commands/setup.rs +++ b/crates/temps-cli/src/commands/setup.rs @@ -299,6 +299,7 @@ async fn ensure_system_user(db: &sea_orm::DatabaseConnection) -> anyhow::Result< email_verification_expires: Set(None), password_reset_token: Set(None), password_reset_expires: Set(None), + must_change_password: Set(false), deleted_at: Set(None), mfa_enabled: Set(false), mfa_secret: Set(None), diff --git a/crates/temps-deployments/src/handlers/deployments.rs b/crates/temps-deployments/src/handlers/deployments.rs index d7c288910..f307fcf82 100644 --- a/crates/temps-deployments/src/handlers/deployments.rs +++ b/crates/temps-deployments/src/handlers/deployments.rs @@ -2761,6 +2761,7 @@ mod tests { email_verification_expires: None, password_reset_token: None, password_reset_expires: None, + must_change_password: false, deleted_at: None, mfa_secret: None, mfa_enabled: false, diff --git a/crates/temps-deployments/src/handlers/remote_deployments.rs b/crates/temps-deployments/src/handlers/remote_deployments.rs index a1dd5844e..25f43fc05 100644 --- a/crates/temps-deployments/src/handlers/remote_deployments.rs +++ b/crates/temps-deployments/src/handlers/remote_deployments.rs @@ -1763,6 +1763,7 @@ pub async fn deploy_from_image_upload( post, tag = "Static Bundles", path = "/projects/{project_id}/upload/static", + request_body(content = SourceArchiveUpload, content_type = "multipart/form-data"), responses( (status = 201, description = "Bundle uploaded successfully", body = StaticBundleResponse), (status = 400, description = "Invalid request or unsupported format"), diff --git a/crates/temps-deployments/src/services/job_processor.rs b/crates/temps-deployments/src/services/job_processor.rs index eac3686ff..ed91a3fbc 100644 --- a/crates/temps-deployments/src/services/job_processor.rs +++ b/crates/temps-deployments/src/services/job_processor.rs @@ -90,13 +90,12 @@ impl JobProcessorService { .from(temps_entities::environments::Entity) .and_where(temps_entities::environments::Column::DeletedAt.is_null()) .to_owned(); + let admitted_at = chrono::Utc::now(); let admitted = deployments::Entity::update_many() .col_expr(deployments::Column::State, Expr::value("running")) - .col_expr( - deployments::Column::UpdatedAt, - Expr::value(chrono::Utc::now()), - ) + .col_expr(deployments::Column::StartedAt, Expr::value(admitted_at)) + .col_expr(deployments::Column::UpdatedAt, Expr::value(admitted_at)) .filter(deployments::Column::Id.eq(deployment_id)) .filter(deployments::Column::State.eq("pending")) .filter(deployments::Column::ProjectId.in_subquery(active_projects)) @@ -1719,6 +1718,15 @@ mod tests { .await? .expect("deployment should exist"); assert_eq!(deployment.state, "running"); + assert!( + deployment.started_at.is_some(), + "admitting a deployment must record when it started" + ); + assert_eq!( + deployment.started_at, + Some(deployment.updated_at), + "the running transition timestamps must come from the same atomic update" + ); let mut cancelled: deployments::ActiveModel = deployment.into(); cancelled.state = Set("cancelled".to_string()); @@ -1764,6 +1772,10 @@ mod tests { denied.cancelled_reason.as_deref(), Some("Deployment owner is being deleted") ); + assert!( + denied.started_at.is_none(), + "a deployment denied admission must not receive a start timestamp" + ); Ok(()) } diff --git a/crates/temps-email/src/handlers/tracking_tests.rs b/crates/temps-email/src/handlers/tracking_tests.rs index b6234579e..f386aee7d 100644 --- a/crates/temps-email/src/handlers/tracking_tests.rs +++ b/crates/temps-email/src/handlers/tracking_tests.rs @@ -71,6 +71,7 @@ mod tests { email_verification_expires: None, password_reset_token: None, password_reset_expires: None, + must_change_password: false, deleted_at: None, mfa_secret: None, mfa_enabled: false, diff --git a/crates/temps-entities/src/users.rs b/crates/temps-entities/src/users.rs index ee1ed8f0f..8150b8a4c 100644 --- a/crates/temps-entities/src/users.rs +++ b/crates/temps-entities/src/users.rs @@ -20,6 +20,7 @@ pub struct Model { #[serde(skip_serializing)] pub password_reset_token: Option, pub password_reset_expires: Option, + pub must_change_password: bool, // Common fields pub deleted_at: Option, #[serde(skip_serializing)] diff --git a/crates/temps-environments/src/handlers/handler.rs b/crates/temps-environments/src/handlers/handler.rs index b036fae07..db6668cb0 100644 --- a/crates/temps-environments/src/handlers/handler.rs +++ b/crates/temps-environments/src/handlers/handler.rs @@ -2311,6 +2311,7 @@ mod tests { email_verification_expires: None, password_reset_token: None, password_reset_expires: None, + must_change_password: false, deleted_at: None, mfa_secret: None, mfa_enabled: false, diff --git a/crates/temps-error-tracking/src/sentry/dsn_handlers.rs b/crates/temps-error-tracking/src/sentry/dsn_handlers.rs index 9b90d834b..d1fc6d4fc 100644 --- a/crates/temps-error-tracking/src/sentry/dsn_handlers.rs +++ b/crates/temps-error-tracking/src/sentry/dsn_handlers.rs @@ -401,6 +401,7 @@ mod tests { email_verification_expires: None, password_reset_token: None, password_reset_expires: None, + must_change_password: false, deleted_at: None, mfa_secret: None, mfa_enabled: false, diff --git a/crates/temps-external-plugins/src/handler.rs b/crates/temps-external-plugins/src/handler.rs index 709032325..0ed34a205 100644 --- a/crates/temps-external-plugins/src/handler.rs +++ b/crates/temps-external-plugins/src/handler.rs @@ -156,6 +156,7 @@ mod tests { email_verification_expires: None, password_reset_token: None, password_reset_expires: None, + must_change_password: false, deleted_at: None, mfa_secret: None, mfa_enabled: false, diff --git a/crates/temps-flags/src/handlers/handler.rs b/crates/temps-flags/src/handlers/handler.rs index 0e0bc9e3a..9d7da6f1b 100644 --- a/crates/temps-flags/src/handlers/handler.rs +++ b/crates/temps-flags/src/handlers/handler.rs @@ -817,6 +817,7 @@ mod tests { email_verification_expires: None, password_reset_token: None, password_reset_expires: None, + must_change_password: false, deleted_at: None, mfa_secret: None, mfa_enabled: false, diff --git a/crates/temps-geo/src/handlers.rs b/crates/temps-geo/src/handlers.rs index 3b714a950..02e7449fa 100644 --- a/crates/temps-geo/src/handlers.rs +++ b/crates/temps-geo/src/handlers.rs @@ -154,6 +154,7 @@ mod tests { email_verification_expires: None, password_reset_token: None, password_reset_expires: None, + must_change_password: false, deleted_at: None, mfa_secret: None, mfa_enabled: false, diff --git a/crates/temps-git/src/handlers/base.rs b/crates/temps-git/src/handlers/base.rs index 63651873f..6d89aeaab 100644 --- a/crates/temps-git/src/handlers/base.rs +++ b/crates/temps-git/src/handlers/base.rs @@ -2480,9 +2480,12 @@ pub async fn get_provider_connections( ) -> Result { permission_check!(auth, Permission::GitConnectionsRead); + // Every connection under this provider, not just the caller's active ones: + // this list is what tells the user why a provider cannot be deleted, so a + // connection it hides is a dead end. let connections = state .git_provider_manager - .get_provider_connections(provider_id) + .get_all_provider_connections(provider_id) .await?; let response: Vec = connections diff --git a/crates/temps-git/src/services/git_provider_manager.rs b/crates/temps-git/src/services/git_provider_manager.rs index e195ae5bb..cb4253deb 100644 --- a/crates/temps-git/src/services/git_provider_manager.rs +++ b/crates/temps-git/src/services/git_provider_manager.rs @@ -3886,7 +3886,27 @@ impl GitProviderManager { ))) } - /// Get all connections for a specific provider + /// Get every connection for a provider, regardless of owner or active state. + /// + /// Deletion checks must use this rather than [`Self::get_provider_connections`]: + /// a deactivated connection (or one owned by another user) still holds rows + /// that block or get cascaded by a provider delete, and counting only the + /// active ones produced errors referencing connections the caller could not + /// see anywhere in the UI. + pub async fn get_all_provider_connections( + &self, + provider_id: i32, + ) -> Result, GitProviderManagerError> { + let connections = git_provider_connections::Entity::find() + .filter(git_provider_connections::Column::ProviderId.eq(provider_id)) + .order_by_desc(git_provider_connections::Column::CreatedAt) + .all(self.db.as_ref()) + .await?; + + Ok(connections) + } + + /// Get the active connections for a specific provider pub async fn get_provider_connections( &self, provider_id: i32, @@ -4136,30 +4156,16 @@ impl GitProviderManager { Ok(()) } - /// Permanently delete a git provider (hard delete) + /// Permanently delete a git provider (hard delete). + /// + /// A provider is only blocked by *projects* that still depend on one of its + /// connections — never by the mere existence of a connection row. Connections + /// are listed per-user in the UI, so refusing on connection count made + /// providers permanently undeletable whenever the connection belonged to + /// another user, had no owner, or was deactivated: the error named a + /// connection the caller had no way to find or remove. pub async fn delete_provider(&self, provider_id: i32) -> Result<(), GitProviderManagerError> { - // Check if provider exists - let provider = self.get_provider(provider_id).await?; - - // Check if any connections exist for this provider - let connections = self.get_provider_connections(provider_id).await?; - if !connections.is_empty() { - return Err(GitProviderManagerError::InvalidConfiguration(format!( - "Cannot delete provider {} because it has {} connection(s)", - provider.name, - connections.len() - ))); - } - - // Delete the provider - git_providers::Entity::delete_by_id(provider_id) - .exec(self.db.as_ref()) - .await?; - - // Remove from cache - self.providers_cache.write().await.remove(&provider_id); - - Ok(()) + self.delete_provider_safely(provider_id).await } /// Check if a provider can be safely deleted and return detailed usage information @@ -4171,7 +4177,7 @@ impl GitProviderManager { let provider = self.get_provider(provider_id).await?; // Get all connections for this provider - let connections = self.get_provider_connections(provider_id).await?; + let connections = self.get_all_provider_connections(provider_id).await?; if connections.is_empty() { return Ok(ProviderDeletionCheck { @@ -4188,21 +4194,29 @@ impl GitProviderManager { // Check each connection for project usage for connection in &connections { - let projects: Vec = - temps_entities::projects::Entity::find() - .filter( - temps_entities::projects::Column::GitProviderConnectionId - .eq(Some(connection.id)), - ) - .order_by_desc(temps_entities::projects::Column::CreatedAt) - .all(self.db.as_ref()) - .await?; + // id/name/slug only — see delete_connection: deserializing full + // project models turns "used by project X" into an opaque + // "Database Error: unexpected value for Preset enum" the moment one + // blocking project has a column value this build can't decode. + let projects: Vec<(i32, String, String)> = temps_entities::projects::Entity::find() + .select_only() + .column(temps_entities::projects::Column::Id) + .column(temps_entities::projects::Column::Name) + .column(temps_entities::projects::Column::Slug) + .filter( + temps_entities::projects::Column::GitProviderConnectionId + .eq(Some(connection.id)), + ) + .order_by_desc(temps_entities::projects::Column::CreatedAt) + .into_tuple() + .all(self.db.as_ref()) + .await?; - for project in projects { + for (id, name, slug) in projects { projects_in_use.push(ProjectUsageInfo { - id: project.id, - name: project.name, - slug: project.slug, + id, + name, + slug, connection_id: connection.id, connection_name: connection.account_name.clone(), }); @@ -4251,7 +4265,7 @@ impl GitProviderManager { let provider = self.get_provider(provider_id).await?; // Get all connections to delete them along with the provider - let connections = self.get_provider_connections(provider_id).await?; + let connections = self.get_all_provider_connections(provider_id).await?; // Delete all repositories associated with these connections for connection in &connections { @@ -4293,18 +4307,35 @@ impl GitProviderManager { // Check if connection exists self.get_connection(connection_id).await?; - // Check if connection is in use by any projects - let project_count = temps_entities::projects::Entity::find() + // Check if connection is in use by any projects. Name them — "used by 2 + // project(s)" leaves the user hunting through every project to work out + // which ones to disconnect first. + // Select id + name only. Loading whole project models makes the check + // fail with an opaque "Database Error: unexpected value for Preset + // enum" if any blocking project carries a column value this build's + // enums don't know — and the user loses the real reason they can't + // delete, which is the whole point of this branch. + let projects: Vec<(i32, String)> = temps_entities::projects::Entity::find() + .select_only() + .column(temps_entities::projects::Column::Id) + .column(temps_entities::projects::Column::Name) .filter( temps_entities::projects::Column::GitProviderConnectionId.eq(Some(connection_id)), ) - .count(self.db.as_ref()) + .into_tuple() + .all(self.db.as_ref()) .await?; - if project_count > 0 { + if !projects.is_empty() { + let project_names: Vec = projects + .iter() + .map(|(id, name)| format!("'{}' (ID: {})", name, id)) + .collect(); return Err(GitProviderManagerError::InvalidConfiguration(format!( - "Cannot delete connection {} because it is used by {} project(s)", - connection_id, project_count + "Cannot delete connection {} because it is used by {} project(s): {}. Change the git source of those projects (or delete them) first.", + connection_id, + projects.len(), + project_names.join(", ") ))); } @@ -5677,6 +5708,99 @@ mod tests { // (actual verification would require querying the database) } + /// Regression: a provider whose only connection belongs to another user (or + /// to nobody, or is deactivated) used to be permanently undeletable — the + /// UI lists connections per-user, so the "it has 1 connection(s)" error + /// pointed at a row the caller could not see or remove anywhere. Only + /// projects actually deploying from the provider may block the delete. + #[tokio::test] + async fn delete_provider_removes_connections_the_caller_cannot_see() { + use chrono::Utc; + + let test_db = TestDatabase::with_migrations().await.unwrap(); + let db = test_db.connection_arc(); + + let provider = git_providers::ActiveModel { + name: Set("GitLab".to_string()), + provider_type: Set("gitlab".to_string()), + base_url: Set(None), + api_url: Set(None), + auth_method: Set("pat".to_string()), + auth_config: Set(serde_json::json!({})), + webhook_secret: Set(None), + is_active: Set(true), + is_default: Set(false), + ..Default::default() + } + .insert(db.as_ref()) + .await + .unwrap(); + + // Two rows the caller can never see: an active but ownerless one + // (user_id = NULL — invisible to the per-user list yet counted by the + // old guard) and a deactivated one (invisible to the active-only list + // but still cascaded on delete). + let now = Utc::now(); + for (account, active) in [("orphan-account", true), ("stale-account", false)] { + git_provider_connections::ActiveModel { + provider_id: Set(provider.id), + user_id: Set(None), + account_name: Set(account.to_string()), + account_type: Set("User".to_string()), + access_token: Set(None), + refresh_token: Set(None), + token_expires_at: Set(None), + refresh_token_expires_at: Set(None), + installation_id: Set(None), + metadata: Set(None), + is_active: Set(active), + is_expired: Set(false), + syncing: Set(false), + last_synced_at: Set(None), + created_at: Set(now), + updated_at: Set(now), + ..Default::default() + } + .insert(db.as_ref()) + .await + .unwrap(); + } + + let manager = GitProviderManager::new( + db.clone(), + Arc::new( + temps_core::EncryptionService::new( + "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", + ) + .unwrap(), + ), + Arc::new(MockJobQueue) as Arc, + create_test_config_service(db.clone()), + ); + + manager + .delete_provider(provider.id) + .await + .expect("provider with no project usage should delete"); + + assert!( + git_providers::Entity::find_by_id(provider.id) + .one(db.as_ref()) + .await + .unwrap() + .is_none(), + "provider row should be gone" + ); + assert!( + manager + .get_all_provider_connections(provider.id) + .await + .unwrap() + .is_empty(), + "the hidden connection should have been cascaded away" + ); + } + #[tokio::test] async fn test_delete_installation_with_nonexistent_installation() { // Create real test database with no data diff --git a/crates/temps-kv/src/handlers/handler.rs b/crates/temps-kv/src/handlers/handler.rs index 22ee09a42..26048da00 100644 --- a/crates/temps-kv/src/handlers/handler.rs +++ b/crates/temps-kv/src/handlers/handler.rs @@ -856,6 +856,7 @@ mod idor_tests { email_verification_expires: None, password_reset_token: None, password_reset_expires: None, + must_change_password: false, deleted_at: None, mfa_secret: None, mfa_enabled: false, diff --git a/crates/temps-log-aggregator/src/handlers/log_handler.rs b/crates/temps-log-aggregator/src/handlers/log_handler.rs index 23c0e7be9..2facf3c7b 100644 --- a/crates/temps-log-aggregator/src/handlers/log_handler.rs +++ b/crates/temps-log-aggregator/src/handlers/log_handler.rs @@ -758,6 +758,7 @@ mod tests { email_verification_expires: None, password_reset_token: None, password_reset_expires: None, + must_change_password: false, deleted_at: None, mfa_secret: None, mfa_enabled: false, @@ -794,6 +795,7 @@ mod tests { email_verification_expires: None, password_reset_token: None, password_reset_expires: None, + must_change_password: false, deleted_at: None, mfa_secret: None, mfa_enabled: false, diff --git a/crates/temps-migrations/src/migration/m20260804_000001_add_must_change_password_to_users.rs b/crates/temps-migrations/src/migration/m20260804_000001_add_must_change_password_to_users.rs new file mode 100644 index 000000000..3c114c081 --- /dev/null +++ b/crates/temps-migrations/src/migration/m20260804_000001_add_must_change_password_to_users.rs @@ -0,0 +1,49 @@ +//! Tracks accounts that must replace an administrator-issued temporary password. + +use sea_orm_migration::prelude::*; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .alter_table( + Table::alter() + .table(Alias::new("users")) + .add_column_if_not_exists( + ColumnDef::new(Alias::new("must_change_password")) + .boolean() + .not_null() + .default(false), + ) + .to_owned(), + ) + .await + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .alter_table( + Table::alter() + .table(Alias::new("users")) + .drop_column(Alias::new("must_change_password")) + .to_owned(), + ) + .await + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn migration_name_is_stable() { + assert_eq!( + Migration.name(), + "m20260804_000001_add_must_change_password_to_users" + ); + } +} diff --git a/crates/temps-migrations/src/migration/mod.rs b/crates/temps-migrations/src/migration/mod.rs index 5c25655c7..a01d3830d 100644 --- a/crates/temps-migrations/src/migration/mod.rs +++ b/crates/temps-migrations/src/migration/mod.rs @@ -172,6 +172,7 @@ mod m20260802_000002_create_feature_flags; mod m20260803_000001_add_flag_last_evaluated_at; mod m20260803_000001_add_template_slug_to_projects; mod m20260803_000002_add_step_up_expires_at_to_sessions; +mod m20260804_000001_add_must_change_password_to_users; pub struct Migrator; @@ -351,6 +352,7 @@ impl MigratorTrait for Migrator { Box::new(m20260803_000001_add_flag_last_evaluated_at::Migration), Box::new(m20260803_000001_add_template_slug_to_projects::Migration), Box::new(m20260803_000002_add_step_up_expires_at_to_sessions::Migration), + Box::new(m20260804_000001_add_must_change_password_to_users::Migration), ] } } diff --git a/crates/temps-notifications/src/handlers.rs b/crates/temps-notifications/src/handlers.rs index ceae942b3..43a350a8c 100644 --- a/crates/temps-notifications/src/handlers.rs +++ b/crates/temps-notifications/src/handlers.rs @@ -2002,6 +2002,7 @@ mod tests { email_verification_expires: None, password_reset_token: None, password_reset_expires: None, + must_change_password: false, deleted_at: None, mfa_secret: None, mfa_enabled: false, diff --git a/crates/temps-providers/src/handlers/handlers.rs b/crates/temps-providers/src/handlers/handlers.rs index bccb50e11..c515fcbab 100644 --- a/crates/temps-providers/src/handlers/handlers.rs +++ b/crates/temps-providers/src/handlers/handlers.rs @@ -2661,6 +2661,7 @@ mod tests { email_verification_expires: None, password_reset_token: None, password_reset_expires: None, + must_change_password: false, deleted_at: None, mfa_secret: None, mfa_enabled: false, diff --git a/crates/temps-providers/src/handlers/metrics_handlers.rs b/crates/temps-providers/src/handlers/metrics_handlers.rs index 6bf0596f5..d74316c53 100644 --- a/crates/temps-providers/src/handlers/metrics_handlers.rs +++ b/crates/temps-providers/src/handlers/metrics_handlers.rs @@ -1695,6 +1695,7 @@ mod tests { email_verification_expires: None, password_reset_token: None, password_reset_expires: None, + must_change_password: false, deleted_at: None, mfa_secret: None, mfa_enabled: false, diff --git a/crates/temps-sandbox/src/handlers/sandboxes.rs b/crates/temps-sandbox/src/handlers/sandboxes.rs index e12bab2e2..86a298252 100644 --- a/crates/temps-sandbox/src/handlers/sandboxes.rs +++ b/crates/temps-sandbox/src/handlers/sandboxes.rs @@ -2474,6 +2474,7 @@ mod tests { email_verification_expires: None, password_reset_token: None, password_reset_expires: None, + must_change_password: false, deleted_at: None, mfa_secret: None, mfa_enabled: false, diff --git a/crates/temps-teams/src/handlers/project_access.rs b/crates/temps-teams/src/handlers/project_access.rs index 8d64f365f..81f475861 100644 --- a/crates/temps-teams/src/handlers/project_access.rs +++ b/crates/temps-teams/src/handlers/project_access.rs @@ -250,6 +250,7 @@ mod tests { email_verification_expires: None, password_reset_token: None, password_reset_expires: None, + must_change_password: false, deleted_at: None, mfa_secret: None, mfa_enabled: false, diff --git a/web/e2e/authenticated/drop-handoff.spec.ts b/web/e2e/authenticated/drop-handoff.spec.ts new file mode 100644 index 000000000..1bc8c8a94 --- /dev/null +++ b/web/e2e/authenticated/drop-handoff.spec.ts @@ -0,0 +1,141 @@ +import { expect, test } from '../fixtures' +import path from 'node:path' + +test.describe('empty-state Drop handoff', () => { + test('uploads a ZIP from the project card and starts detection on /drop', async ({ + page, + }) => { + await page.route(/\/api\/projects(?:\?.*)?$/, async (route) => { + if (route.request().method() === 'GET') { + await route.fulfill({ + json: { projects: [], page: 1, per_page: 20, total: 0 }, + }) + return + } + await route.fulfill({ + status: 201, + json: { id: 42, name: 'browser-folder', slug: 'browser-folder' }, + }) + }) + await page.route('**/api/drop/inspect', async (route) => { + await route.fulfill({ + json: { + suggestedName: 'browser-folder', + candidates: [ + { + preset: 'static', + label: 'Static HTML', + directory: '.', + confidence: 'high', + reason: 'index.html found', + isStatic: true, + }, + ], + }, + }) + }) + await page.route('**/api/projects/42/environments', async (route) => { + await route.fulfill({ + json: [ + { + id: 7, + project_id: 42, + name: 'production', + slug: 'production', + main_url: 'https://browser-folder.example.test', + is_preview: false, + }, + ], + }) + }) + let staticUploadWasMultipart = false + await page.route('**/api/projects/42/upload/static', async (route) => { + const request = route.request() + staticUploadWasMultipart = + request + .headers() + ['content-type']?.startsWith('multipart/form-data;') === true && + request.postDataBuffer()?.includes(Buffer.from('name="file"')) === true + await route.fulfill({ + status: 201, + json: { id: 91, project_id: 42 }, + }) + }) + await page.route( + '**/api/projects/42/environments/7/deploy/static', + async (route) => { + await route.fulfill({ status: 201, json: { id: 301 } }) + } + ) + + await page.goto('/projects') + await expect( + page.getByRole('heading', { name: 'Drop project files' }) + ).toBeVisible() + + const chooserPromise = page.waitForEvent('filechooser') + await page.getByRole('button', { name: 'Upload ZIP' }).click() + const chooser = await chooserPromise + await chooser.setFiles({ + name: 'site.zip', + mimeType: 'application/zip', + buffer: Buffer.from('browser-test-archive'), + }) + + await page.waitForURL(/\/drop$/) + await expect( + page.getByText('Static HTML', { exact: true }).first() + ).toBeVisible() + await expect(page.getByLabel('Project name')).toHaveValue('browser-folder') + await page.getByRole('button', { name: 'Deploy Static HTML' }).click() + await expect(page.getByText('Drop accepted')).toBeVisible() + expect(staticUploadWasMultipart).toBe(true) + }) + + test('hands a selected folder to /drop with nested paths intact', async ({ + page, + }) => { + await page.route(/\/api\/projects(?:\?.*)?$/, async (route) => { + if (route.request().method() !== 'GET') return route.continue() + await route.fulfill({ + json: { projects: [], page: 1, per_page: 20, total: 0 }, + }) + }) + let archiveContainsNestedPath = false + await page.route('**/api/drop/inspect', async (route) => { + const body = route.request().postDataBuffer() + archiveContainsNestedPath = + body?.includes(Buffer.from('index.html')) === true && + body.includes(Buffer.from('assets/app.js')) + await route.fulfill({ + json: { + suggestedName: 'drop-folder-site', + candidates: [ + { + preset: 'static', + label: 'Static HTML', + directory: '.', + confidence: 'high', + reason: 'index.html found', + isStatic: true, + }, + ], + }, + }) + }) + + await page.goto('/projects') + const chooserPromise = page.waitForEvent('filechooser') + await page.getByRole('button', { name: 'Open folder' }).click() + const chooser = await chooserPromise + await chooser.setFiles( + path.join(process.cwd(), 'e2e/fixtures/drop-folder-site') + ) + + await page.waitForURL(/\/drop$/) + await expect(page.getByLabel('Project name')).toHaveValue( + 'drop-folder-site' + ) + expect(archiveContainsNestedPath).toBe(true) + }) +}) diff --git a/web/e2e/authenticated/user-creation.spec.ts b/web/e2e/authenticated/user-creation.spec.ts new file mode 100644 index 000000000..ee5022bc9 --- /dev/null +++ b/web/e2e/authenticated/user-creation.spec.ts @@ -0,0 +1,107 @@ +import { expect, test } from '../fixtures' + +test.describe('user creation', () => { + test('retries a failed team assignment without creating the account twice', async ({ + page, + }) => { + let createRequests = 0 + let teamRequests = 0 + const now = new Date().toISOString() + + await page.route(/\/api\/teams(?:\?.*)?$/, async (route) => { + if (route.request().method() !== 'GET') return route.continue() + await route.fulfill({ + json: { + teams: [ + { + id: 99, + name: 'Platform', + slug: 'platform', + description: null, + created_by: 1, + created_at: now, + updated_at: now, + }, + ], + page: 1, + page_size: 100, + total: 1, + }, + }) + }) + await page.route('**/api/users', async (route) => { + if (route.request().method() !== 'POST') return route.continue() + createRequests += 1 + await route.fulfill({ + status: 201, + json: { + user: { + id: 501, + name: 'Alex Morgan', + email: 'alex@example.com', + image: '', + mfa_enabled: false, + email_verified: false, + must_change_password: true, + deleted_at: null, + created_at: Date.now(), + updated_at: Date.now(), + }, + roles: [ + { + id: 2, + name: 'user', + created_at: Date.now(), + updated_at: Date.now(), + }, + ], + }, + }) + }) + await page.route('**/api/teams/99/members', async (route) => { + teamRequests += 1 + if (teamRequests === 1) { + await route.fulfill({ + status: 500, + json: { detail: 'temporary failure' }, + }) + return + } + await route.fulfill({ + status: 201, + json: { + id: 1, + team_id: 99, + user_id: 501, + role: 'viewer', + added_by: 1, + user_name: 'Alex Morgan', + user_email: 'alex@example.com', + created_at: now, + updated_at: now, + }, + }) + }) + + await page.goto('/settings/users/new') + await page.getByLabel('Name').fill('Alex Morgan') + await page.getByLabel('Email').fill('alex@example.com') + await page + .getByRole('button', { name: 'Generate a secure temporary password' }) + .click() + await page.getByLabel('Team', { exact: true }).click() + await page.getByRole('option', { name: 'Platform' }).click() + await page.getByRole('button', { name: 'Create user' }).click() + + await expect( + page.getByText('Account created; team assignment pending') + ).toBeVisible() + expect(createRequests).toBe(1) + expect(teamRequests).toBe(1) + + await page.getByRole('button', { name: 'Retry team assignment' }).click() + await page.waitForURL(/\/settings\/users$/) + expect(createRequests).toBe(1) + expect(teamRequests).toBe(2) + }) +}) diff --git a/web/e2e/fixtures/drop-folder-site/assets/app.js b/web/e2e/fixtures/drop-folder-site/assets/app.js new file mode 100644 index 000000000..1459b786f --- /dev/null +++ b/web/e2e/fixtures/drop-folder-site/assets/app.js @@ -0,0 +1 @@ +document.body.dataset.dropFixture = 'ready' diff --git a/web/e2e/fixtures/drop-folder-site/index.html b/web/e2e/fixtures/drop-folder-site/index.html new file mode 100644 index 000000000..d320803bb --- /dev/null +++ b/web/e2e/fixtures/drop-folder-site/index.html @@ -0,0 +1,10 @@ + + + + + Drop folder fixture + + + + + diff --git a/web/src/App.tsx b/web/src/App.tsx index 042bc0881..b02d18368 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -75,7 +75,9 @@ const ServiceDetail = lazy(() => import('./pages/ServiceDetail').then((m) => ({ default: m.ServiceDetail })) ) const ServiceMonitoring = lazy(() => - import('./pages/ServiceMonitoring').then((m) => ({ default: m.ServiceMonitoring })) + import('./pages/ServiceMonitoring').then((m) => ({ + default: m.ServiceMonitoring, + })) ) const ServiceDataBrowser = lazy(() => import('./pages/ServiceDataBrowser').then((m) => ({ @@ -110,6 +112,9 @@ const AddClusterMember = lazy(() => const Users = lazy(() => import('./pages/Users').then((m) => ({ default: m.Users })) ) +const CreateUser = lazy(() => + import('./pages/CreateUser').then((m) => ({ default: m.CreateUser })) +) const UserDetail = lazy(() => import('./pages/UserDetail').then((m) => ({ default: m.UserDetail })) ) @@ -244,6 +249,11 @@ const ForgotPassword = lazy(() => const ResetPassword = lazy(() => import('./pages/ResetPassword').then((m) => ({ default: m.ResetPassword })) ) +const RequiredPasswordChange = lazy(() => + import('./pages/RequiredPasswordChange').then((m) => ({ + default: m.RequiredPasswordChange, + })) +) const NotFound = lazy(() => import('./components/global/NotFound')) // Settings sub-pages @@ -422,226 +432,407 @@ const FullAppRoutes = () => { return ( - - - {/* Wrap sidebar with independent error boundary */} - ( - - )} - onError={(error, errorInfo) => { - console.error('[App] Sidebar error caught by boundary:', error) - console.error('[App] Component stack:', errorInfo.componentStack) - }} - > - - - - {/* App-wide disk-space banner — sits above the header inside the + + + {/* Wrap sidebar with independent error boundary */} + ( + + )} + onError={(error, errorInfo) => { + console.error('[App] Sidebar error caught by boundary:', error) + console.error( + '[App] Component stack:', + errorInfo.componentStack + ) + }} + > + + + + {/* App-wide disk-space banner — sits above the header inside the content column (to the right of the fixed sidebar, so it's never clipped by it), full content width, on every page. */} - - {/* App-wide "newer release published" banner — informational, per- + + {/* App-wide "newer release published" banner — informational, per- version dismissible, links the upgrade docs. */} - - {/* Wrap header with independent error boundary */} - ( - - )} - onError={(error, errorInfo) => { - console.error('[App] Header error caught by boundary:', error) - console.error('[App] Component stack:', errorInfo.componentStack) - }} - > -
    - - {/* Wrap page content with error boundary */} - ( - - )} - onError={(error, errorInfo) => { - console.error('[App] Page error caught by boundary:', error) - console.error('[App] Component stack:', errorInfo.componentStack) - }} - > -
    - - {extraRoutes?.map((r) => ( - - ))} - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - }> - } /> - } /> - } /> - } /> - } /> - - {/* Observe section */} - {/* ADR-027 Phase 2: global cross-project unified trace waterfall */} - } - /> - } /> - } /> - } /> - } /> - {/* CLI device-authorization approval surface. The route + + {/* Wrap header with independent error boundary */} + ( + + )} + onError={(error, errorInfo) => { + console.error('[App] Header error caught by boundary:', error) + console.error( + '[App] Component stack:', + errorInfo.componentStack + ) + }} + > +
    + + {/* Wrap page content with error boundary */} + ( + + )} + onError={(error, errorInfo) => { + console.error('[App] Page error caught by boundary:', error) + console.error( + '[App] Component stack:', + errorInfo.componentStack + ) + }} + > +
    + + {extraRoutes?.map((r) => ( + + ))} + } + /> + } + /> + } /> + } /> + } /> + } /> + } /> + } /> + } + /> + }> + } + /> + } /> + } + /> + } + /> + } /> + + {/* Observe section */} + {/* ADR-027 Phase 2: global cross-project unified trace waterfall */} + } + /> + } /> + } /> + } + /> + } /> + {/* CLI device-authorization approval surface. The route sits inside the protected layout so unauthenticated visitors get bounced through /login and the captureReturnTo() infrastructure brings them back. */} - } /> - } /> - {/* Settings drill-down: only items NOT surfaced at the + } /> + } /> + {/* Settings drill-down: only items NOT surfaced at the main sidebar root live here. Top-level resources (domains, storage, email, AI, source providers, backups) moved out so they don't trigger the settings sidebar swap. */} - }> - } /> - } /> - } /> - } /> - } /> - {/* Teams sit under /settings alongside Users and API Keys: + }> + } /> + } + /> + } /> + } /> + } /> + } /> + {/* Teams sit under /settings alongside Users and API Keys: the sidebar lists them together, and a top-level route would drop out of the settings layout on click. */} - } /> - } /> - } /> - } /> - } - /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - {/* Security */} - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - - {/* Top-level resources surfaced in the main sidebar */} - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - }> - } /> - } /> - } /> - } /> - } /> - } /> - - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - {/* Backward-compat: old /settings/ links → new top-level */} - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - {/* Projects */} - } /> - } /> - } - /> - } /> - {/* Utility */} - } /> - {/* External plugin routes */} - } /> - } /> - -
    -
    - - {/* Persistent AI assistant dock (ADR-023): a flex sibling so it pushes + } /> + } /> + } /> + } + /> + } + /> + } /> + } /> + } /> + } /> + } /> + } /> + } + /> + {/* Security */} + } /> + } + /> + } + /> + } + /> + } + /> + } /> + } /> + } + /> + } /> + + {/* Top-level resources surfaced in the main sidebar */} + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } + /> + } + /> + } /> + } + /> + } + /> + } + /> + } + /> + } /> + } + /> + } + /> + } + /> + } /> + } /> + } /> + } + > + } /> + } + /> + } + /> + } + /> + } + /> + } + /> + + } + /> + } + /> + } + /> + } + /> + } /> + } + /> + } + /> + } /> + } + /> + } + /> + } /> + } + /> + } + /> + } + /> + } + /> + } + /> + } + /> + } + /> + {/* Backward-compat: old /settings/ links → new top-level */} + } + /> + } + /> + } + /> + } + /> + } + /> + } + /> + } + /> + } + /> + } + /> + {/* Projects */} + } /> + } + /> + } + /> + } + /> + {/* Utility */} + } /> + {/* External plugin routes */} + } + /> + } /> + +
    +
    + + {/* Persistent AI assistant dock (ADR-023): a flex sibling so it pushes the layout rather than covering it — stays open and streaming while the user navigates the console. */} - - - {/* Shared AI-autofix setup dialog — mounted once so any surface can + + + {/* Shared AI-autofix setup dialog — mounted once so any surface can open it via `useAutofixOnboarding()` instead of hiding autofix. */} - - - + + + ) @@ -671,7 +862,14 @@ const AppContent = () => { {/* Target of the password-reset email link ({base_url}/auth/reset-password?token=...) — see send_password_reset_email in temps-auth. */} - } /> + } + /> + } + /> {/* Protected routes - layout determined by demo mode */} = [ Pick & { @@ -1750,6 +1750,20 @@ export const listPublicProvidersOptions = (options?: Options>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await changeRequiredPassword({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + export const requestPasswordResetMutation = (options?: Partial>): UseMutationOptions> => { const mutationOptions: UseMutationOptions> = { mutationFn: async (fnOptions) => { diff --git a/web/src/api/client/index.ts b/web/src/api/client/index.ts index 727290de7..67df843e1 100644 --- a/web/src/api/client/index.ts +++ b/web/src/api/client/index.ts @@ -1,4 +1,4 @@ // This file is auto-generated by @hey-api/openapi-ts -export { acknowledgeAlarm, activateAiProvider, activateApiKey, activateConnection, activateProvider, addClusterMember, addContext, addEnvironmentDomain, addEvents, addManagedDomain, addSessionReplayEvents, addTeamMember, adminDrainNode, adminDrainStatus, adminGetNode, adminListNodeContainers, adminListNodes, adminRemoveNode, adminUndrainNode, applyHostnameMode, archiveConversation, archiveFlag, assignRole, attachScheduleServices, blobCopy, blobDelete, blobDisable, blobDownload, blobEnable, blobHead, blobList, blobPut, blobStatus, blobUpdate, cancel, cancelBackup, cancelDeployment, cancelDomainOrder, cancelPgUpgrade, cancelRun, cancelScheduleRun, changePasswordSelf, changeProjectSource, chatCompletions, checkAnalyticsHasEvents, checkCommitExists, checkDomainStatus, checkExplorerSupport, checkIpBlocked, checkProviderDeletionSafety, chunkUploadOptions, cleanupExpiredBackups, clearPreviewPassword, cliDeviceApprove, cliDeviceDeny, cliDeviceLookup, cliDevicePoll, cliDeviceStart, cliLogout, cmd, cmdKill, cmdLogs, confirmPendingAction, containerMetricsGetHistory, createAgent, createAlert, createAlertRule, createApiKey, createBackupSchedule, createBitbucketProvider, createCloudflareProvider, createConversation, createCustomDomain, createDashboard, createDeploymentToken, createDnsProvider, createDomain, createDsn, createEmailDomain, createEmailProvider, createEnvironment, createEnvironmentVariable, createFlag, createFunnel, createGenericProvider, createGiteaPatProvider, createGithubPatProvider, createGitlabOauthProvider, createGitlabPatProvider, createGitProvider, createGlobalMcp, createGlobalSkill, createIncident, createIpAccessControl, createMcp, createMonitor, createNotificationEmailProvider, createNotificationProvider, createOidcProvider, createOidcRoleMapping, createOrRecreateOrder, createPlan, createPr, createProject, createProjectFromTemplate, createProjectRelease, createProjectSecret, createProviderKey, createRelease, createRoute, createS3Source, createSandbox, createService, createSkill, createSlackProvider, createTeam, createUser, createWebhook, createWebhookProvider, deactivateApiKey, deactivateConnection, deactivateProvider, deleteAgent, deleteAlert, deleteAlertRule, deleteApiKey, deleteBackup, deleteBackupSchedule, deleteConnection, deleteCustomDomain, deleteDashboard, deleteDeploymentToken, deleteDnsProvider, deleteDomain, deleteEmailDomain, deleteEmailProvider, deleteEnvironment, deleteEnvironmentDomain, deleteEnvironmentVariable, deleteExternalImage, deleteFunnel, deleteGitProvider, deleteGlobalMcp, deleteGlobalSkill, deleteIpAccessControl, deleteMcp, deleteMonitor, deleteNotificationProvider, deleteOidcProvider, deleteOidcRoleMapping, deletePreferences, deleteProject, deleteProjectSecret, deleteProviderKey, deleteProviderSafely, deleteReleaseSourceFiles, deleteReleaseSourceMaps, deleteRoute, deleteS3Source, deleteScan, deleteSecret, deleteService, deleteSessionReplay, deleteSkill, deleteSourceMap, deleteStaticBundle, deleteTeam, deleteUser, deleteWebhook, deployFromImage, deployFromImageUpload, deployFromStatic, deployFromUploadedSource, deploymentMetricsGetLatest, deploymentMetricsGetRange, deploymentMetricsToggle, destroySandbox, detachScheduleService, detectPublicPresets, disableBackupSchedule, disableMfa, disconnectCloud, discoverWorkloads, domain, downloadGlobalSkillArchive, downloadObject, downloadSkillArchive, emailStatus, embeddings, enableBackupSchedule, enrichVisitor, enrollCloud, exec, execDetached, executeDeploymentOperation, executeImport, extendTimeout, externalServiceEnablePgStatStatements, externalServiceMetricsByDatabase, externalServiceMetricsCreateAlertRule, externalServiceMetricsDeleteAlertRule, externalServiceMetricsGetAlertRules, externalServiceMetricsGetLatest, externalServiceMetricsGetRange, externalServiceMetricsStatus, externalServiceMetricsToggle, externalServiceMetricsUpdateAlertRule, externalServiceResetPgStatStatements, finalizeOrder, finalizeProjectRelease, findConversation, generateJoinToken, generatePresetDockerfile, getAccessInfo, getActiveVisitors, getActivityGraph, getAdminGate, getAgent, getAggregatedBuckets, getAiAgentBreakdown, getAiAgentPages, getAiAgentTimeline, getAiPageBreakdown, getAiStatusBreakdown, getAlert, getAlertRule, getAllRepositoriesByName, getAnalyticsActiveVisitors, getAnalyticsEventsCount, getAnalyticsSessionEvents, getAnalyticsVisitorSessions, getApiKey, getApiKeyPermissions, getAuditLog, getBackup, getBackupSchedule, getBranchesByRepositoryId, getBucketedIncidents, getBucketedStatus, getChallengeToken, getChatReadiness, getCliStatus, getCloudCapability, getCloudStatus, getClusterHealth, getClusterMember, getCmd, getContainerDetail, getContainerEnvironmentVariable, getContainerInfo, getContainerLogs, getContainerLogsById, getContainerMetrics, getConversation, getConversationDetail, getConversations, getCronById, getCronExecutions, getCrossProjectTraceSiblings, getCurrentMonitorStatus, getCurrentUser, getCustomDomain, getDashboard, getDashboardProjectsAnalytics, getDelivery, getDeployment, getDeploymentContainerLogContent, getDeploymentJobLogs, getDeploymentJobs, getDeploymentOperations, getDeploymentOperationStatus, getDeploymentToken, getDiskStatus, getDnsChanges, getDnsProvider, getDomain, getDomainByHost, getDomainById, getDomainByName, getDomainDnsRecords, getDomainOrder, getEmail, getEmailEvents, getEmailLinks, getEmailProvider, getEmailStats, getEmailTracking, getEmailTrackingStatus, getEntityInfo, getEnvironment, getEnvironmentCrons, getEnvironmentDomains, getEnvironments, getEnvironmentVariables, getEnvironmentVariableValue, getErrorDashboardStats, getErrorEvent, getErrorGroup, getErrorStats, getErrorTimeSeries, getEventDetail, getEventEntries, getEventsCount, getEventsTimeline, getEventTypeBreakdown, getEventVisitors, getExternalImage, getFile, getFlag, getFlagSnapshot, getFunnelMetrics, getGenaiTrace, getGeneralStats, getGitProvider, getGlobalEvents, getGlobalEventStats, getGlobalMcp, getGlobalSandboxStatus, getGlobalSkill, getGroupedPageMetrics, getHealth, getHourlyVisits, getHttpChallengeDebug, getImportStatus, getIncident, getIncidentUpdates, getIpAccessControl, getIpGeolocation, getJoinTokenStatus, getLastDeployment, getLatestScan, getLatestScansPerEnvironment, getLiveVisitorsList, getLogContext, getMcp, getMetricsOverTime, getMonitor, getNotificationProvider, getOnDemandCertStatus, getOrCreateDsn, getPageFlow, getPageHourlySessions, getPagePathDetail, getPagePaths, getPagePathsSparklines, getPagePathVisitors, getPendingAction, getPerformanceMetrics, getPgUpgrade, getPgUpgradeLogs, getPipelineStats, getPlatformInfo, getPostgresWalHealth, getPreferences, getPreviewGatewayLogs, getPreviewGatewaySettings, getPreviewGatewayStatus, getPricing, getPrivateIp, getProject, getProjectAlarmsSummary, getProjectBySlug, getProjectDeployments, getProjects, getProjectServiceEnvironmentVariables, getProjectSessionReplays, getProjectsHealth, getProjectsMonitorHealth, getProjectStatistics, getProjectTemplate, getPropertyBreakdown, getPropertyTimeline, getProviderConnections, getProviderMetadata, getProvidersMetadata, getProxyLogById, getProxyLogByRequestId, getProxyLogs, getPublicBranches, getPublicIp, getPublicRepository, getQuota, getRecentActivity, getRemoteExternalImage, getRepositoryBranches, getRepositoryById, getRepositoryByName, getRepositoryPresetByName, getRepositoryPresetLive, getRepositoryTags, getResolvedEnvironmentVariables, getResolvedEnvironmentVariableValue, getRestoreCapabilities, getRestoreRun, getRoute, getRun, getRunWithLogs, getS3Credentials, getS3Source, getSandbox, getSandboxStatus, getScan, getScanByDeployment, getScanVulnerabilities, getService, getServiceBySlug, getServiceEnvironmentVariable, getServiceEnvironmentVariables, getServiceHealthStatus, getServicePreviewEnvironmentVariableNames, getServicePreviewEnvironmentVariablesMasked, getServiceRuntime, getServiceStats, getServiceTypeParameters, getServiceTypes, getSessionDetails, getSessionEvents, getSessionLogs, getSessionReplay, getSessionReplayEvents, getSettings, getSkill, getSlowQueries, getStaticBundle, getStatusOverview, getTagsByRepositoryId, getTeam, getTimeBucketStats, getTodayStats, getTrace, getUnifiedTrace, getUniqueCounts, getUniqueEvents, getUpdateStatus, getUptimeHistory, getUsageByProvider, getUsageRecent, getUsageSummary, getUsageTimeseries, getUsageTopModels, getVisitorByGuid, getVisitorById, getVisitorDetails, getVisitorFacets, getVisitorInfo, getVisitorJourney, getVisitors, getVisitorSessions, getVisitorStats, getWebhook, grantProjectAccess, handleGitProviderOauthCallback, hasAnalyticsEvents, hasErrorGroups, hasPerformanceMetrics, importExternalService, ingestLogs, ingestLogsByPath, ingestMetrics, ingestMetricsByPath, ingestSentryEnvelope, ingestSentryEvent, ingestTraces, ingestTracesByPath, initSessionReplay, inspectDropArchive, jobLogs, jobStatus, killJob, kvDel, kvDisable, kvEnable, kvExpire, kvGet, kvIncr, kvKeys, kvSet, kvStatus, kvTtl, kvUpdate, latestRunForSource, linkCustomDomainToCertificate, linkServiceToProject, listAgentRuns, listAgents, listAiProviders, listAlertRules, listAlerts, listAllConversations, listAllRuns, listApiKeys, listAuditLogs, listAvailableContainers, listBackupAlerts, listBackupChildren, listBackupSchedules, listBackupsForSchedule, listCommitsByRepositoryId, listConnections, listContainers, listContainersAtPath, listConversations, listCustomDomainsForProject, listDashboards, listDeliveries, listDeploymentContainerLogs, listDeploymentTokens, listDnsProviders, listDomains, listDsns, listEmailDomains, listEmailProviders, listEmails, listEnrollmentTokens, listEntities, listErrorEvents, listErrorGroups, listEvents, listEventTypes, listExternalImages, listExternalPlugins, listExternalServiceBackups, listFlags, listFunnels, listGitProviders, listGlobalMcps, listGlobalSkills, listIncidents, listInsights, listIpAccessControl, listJobs, listKnownAiAgents, listManagedDomains, listMcps, listMetricLabelKeys, listMetricLabelValues, listMetricNames, listModels, listMonitors, listNotificationProviders, listOidcProviders, listOidcProviderUsers, listOidcRoleMappings, listOnDemandCerts, listOrders, listPeers, listPendingActions, listPgUpgrades, listPresets, listProjectAccess, listProjectAlarms, listProjectScans, listProjectSecrets, listProjectServices, listProjectTemplates, listProjectTemplateTags, listProviderKeys, listProviderZones, listPublicProviders, listReleaseFiles, listReleases, listRemoteExternalImages, listRepositoriesByConnection, listRepositoriesByProvider, listRestoreRunsForService, listRootContainers, listRoutes, listS3Sources, listSandboxes, listScheduleRunJobs, listScheduleRuns, listScheduleServices, listSecrets, listServiceHealthStatuses, listServiceProjects, listServices, listServiceSchedules, listSkills, listSourceBackups, listSourceFiles, listSourceMaps, listSources, listStaticBundles, listSyncedRepositories, listTeamMembers, listTeamProjects, listTeams, listUsers, listWebhooks, login, logout, lookupDnsARecords, mintEnrollmentToken, mkdir, nodeHeartbeat, nodeMetricsGetRange, observabilityFullEvent, observabilityListEvents, oidcCallback, type Options, patchAdminGate, patchPreviewGatewaySettings, pauseDeployment, pauseSandbox, planRestore, postDnsAck, previewAlert, previewFunnelMetrics, previewHostnameMode, promoteClusterMember, promoteDeployment, provisionDomain, purgeProjectLogs, pushExternalImage, queryData, queryGenaiTraces, queryLogs, queryMetrics, queryTraces, queryTraceSummaries, readFile, reAnalyze, recordConsoleEvent, recordEventMetrics, recordFlagExposure, recordSpeedMetrics, refreshRouteTable, regenerateDsn, registerExternalImage, registerNode, reinstallGitlabWebhook, rejectPendingAction, reloadPlugins, removeClusterMember, removeManagedDomain, removeRole, removeTeamMember, renameConversation, renewDomain, requestPasswordReset, resetPassword, resizeSandbox, resolveAlarm, restartContainer, restartPreviewGateway, restartSandbox, restoreFlag, restoreUser, resumeDeployment, resumeSandbox, retryCluster, retryDelivery, retryPgUpgrade, retryRun, revealGlobalMcpConfig, revealMcpConfig, revealNotificationProviderConfig, revealServiceParameter, revenueCreateIntegration, revenueDeleteIntegration, revenueGlobalEvents, revenueImportInvoicesCsv, revenueImportSubscriptionsCsv, revenueListIntegrations, revenueListProviders, revenueMetricsCustomers, revenueMetricsGlobalMrr, revenueMetricsGlobalSummary, revenueMetricsMrr, revenueMetricsSummary, revenueRecentEvents, revenueRotateToken, revenueUpdateConfig, revenueUpdateSecret, revokeDsn, revokeEnrollmentToken, revokeJoinToken, revokeProjectAccess, rollbackPgUpgrade, rollbackToDeployment, rootfsGc, rootfsReport, rotateApiKey, rotateDeploymentToken, runBackupForSource, runConnectionHealthCheck, runExternalServiceBackup, runScheduleNow, sandboxCreatePreviewLink, saveAgentToken, saveAiProviderCredential, searchLogs, sendEmail, setDefaultS3Source, setFlagEnvironment, setPreviewPassword, setupDns, setupDnsChallenge, setupEmailTracking, setupMfa, sleepEnvironment, smokeTestAgent, sourceSandbox, startAnalysis, startContainer, startFix, startGitProviderOauth, startOidcLoginBySlug, startPgUpgrade, startRestore, startService, statPath, stopContainer, stopSandbox, stopService, streamContainerMetrics, streamEvents, streamRunEvents, syncRepositories, tailDeploymentJobLogs, tailLogs, teardownDeployment, teardownEnvironment, testNotificationProvider, testOidcProvider, testProvider, testProviderConnection, testProviderKeyById, testProviderKeyInline, testS3ConnectionPreview, testS3SourceConnection, trackClick, trackOpen, triggerAgent, triggerProjectPipeline, triggerScan, triggerServiceHealthCheck, triggerWeeklyDigest, unlinkServiceFromProject, updateAgent, updateAiProvider, updateAlert, updateAlertRule, updateApiKey, updateAutomaticDeploy, updateBackupSchedule, updateCloudflareProvider, updateConnectionToken, updateCustomDomain, updateDashboard, updateDeploymentToken, updateEmailProvider, updateEnvironmentSettings, updateEnvironmentSubdomain, updateEnvironmentVariable, updateErrorGroup, updateFlag, updateFunnel, updateGitProviderCredentials, updateGitSettings, updateGlobalMcp, updateGlobalSkill, updateIncidentStatus, updateIpAccessControl, updateManagedDomain, updateMcp, updateNotificationEmailProvider, updateNotificationProvider, updateOidcProvider, updatePreferences, updateProject, updateProjectDeploymentConfig, updateProjectSecret, updateProjectSettings, updateProvider, updateProviderKey, updateRoute, updateS3Source, updateSelf, updateService, updateServiceResources, updateSessionDuration, updateSettings, updateSkill, updateSlackProvider, updateSpeedMetrics, updateTeam, updateTeamMemberRole, updateUser, updateWebhook, updateWebhookProvider, upgradePreviewGateway, upgradeService, uploadGlobalSkill, uploadReleaseFile, uploadSkill, uploadSourceFile, uploadSourceMap, uploadStaticBundle, upsertSecret, validateConnection, validateEmail, verifyAndEnableMfa, verifyDomain, verifyEmail, verifyManagedDomain, verifyMfaChallenge, verifyStepUp, wakeEnvironment, webhookTrigger, workflowDryRun, writeFile, writeFiles } from './sdk.gen'; -export type { AcknowledgeAlarmData, AcknowledgeAlarmErrors, AcknowledgeAlarmResponses, AcmeOrderResponse, ActivateAiProviderData, ActivateAiProviderErrors, ActivateAiProviderResponse, ActivateAiProviderResponses, ActivateApiKeyData, ActivateApiKeyErrors, ActivateApiKeyResponse, ActivateApiKeyResponses, ActivateConnectionData, ActivateConnectionErrors, ActivateConnectionResponses, ActivateProviderData, ActivateProviderErrors, ActivateProviderResponse, ActivateProviderResponses, ActiveVisitor, ActiveVisitorsQuery, ActiveVisitorsResponse, ActivityDay, ActivityEvent, ActivityGraphQuery, ActivityGraphResponse, AddClusterMemberData, AddClusterMemberErrors, AddClusterMemberRequest, AddClusterMemberResponse, AddClusterMemberResponses, AddContextData, AddContextErrors, AddContextRequest, AddContextResponses, AddEnvironmentDomainData, AddEnvironmentDomainErrors, AddEnvironmentDomainRequest, AddEnvironmentDomainResponse, AddEnvironmentDomainResponses, AddEventsData, AddEventsError, AddEventsErrors, AddEventsRequest, AddEventsResponse, AddEventsResponse2, AddEventsResponses, AddManagedDomainApiRequest, AddManagedDomainData, AddManagedDomainErrors, AddManagedDomainResponse, AddManagedDomainResponses, AddSessionReplayEventsData, AddSessionReplayEventsError, AddSessionReplayEventsErrors, AddSessionReplayEventsResponse, AddSessionReplayEventsResponses, AddTeamMemberData, AddTeamMemberErrors, AddTeamMemberResponse, AddTeamMemberResponses, AdminDrainNodeData, AdminDrainNodeErrors, AdminDrainNodeResponse, AdminDrainNodeResponses, AdminDrainStatusData, AdminDrainStatusErrors, AdminDrainStatusResponse, AdminDrainStatusResponses, AdminGateResponse, AdminGateSource, AdminGetNodeData, AdminGetNodeErrors, AdminGetNodeResponse, AdminGetNodeResponses, AdminListNodeContainersData, AdminListNodeContainersErrors, AdminListNodeContainersResponse, AdminListNodeContainersResponses, AdminListNodesData, AdminListNodesErrors, AdminListNodesResponse, AdminListNodesResponses, AdminRemoveNodeData, AdminRemoveNodeErrors, AdminRemoveNodeResponse, AdminRemoveNodeResponses, AdminUndrainNodeData, AdminUndrainNodeErrors, AdminUndrainNodeResponse, AdminUndrainNodeResponses, AgentConfigResponse, AgentRunLogResponse, AgentRunResponse, AgentRunWithLogsResponse, AgentSandboxSettings, AgentSandboxSettingsMasked, AggregatedBucketItem, AggregatedBucketsQuery, AggregatedBucketsResponse, AggregationLevel, AggregationTemporality, AiAgentBreakdownResponse, AiAgentBreakdownRow, AiAgentDescriptor, AiAgentPageRow, AiAgentPagesResponse, AiAgentTimelineResponse, AiAgentTimelineRow, AiChatLimitsSettings, AiConfigSettings, AiPageBreakdownResponse, AiPageBreakdownRow, AiStatusBreakdownResponse, AiStatusBreakdownRow, AlarmListResponse, AlarmResponse, AlarmSummaryResponse, AlertRuleResponse, AllocEntry, AnalyticsSessionEventsResponse, AnnotatedSpan, AnomalyAlgorithm, AnomalyParams, AnomalyPreviewPointResponse, AnomalyPreviewRequest, AnomalyPreviewResponse, ApiKeyListResponse, ApiKeyResponse, ApplyHostnameModeData, ApplyHostnameModeErrors, ApplyHostnameModeRequest, ApplyHostnameModeResponse, ApplyHostnameModeResponses, AppSettings, AppSettingsResponse, ArchiveConversationData, ArchiveConversationErrors, ArchiveConversationResponse, ArchiveConversationResponses, ArchiveFlagData, ArchiveFlagErrors, ArchiveFlagResponse, ArchiveFlagResponse2, ArchiveFlagResponses, ArchiveMode, AssignRoleData, AssignRoleErrors, AssignRoleRequest, AssignRoleResponses, AttachScheduleServicesData, AttachScheduleServicesError, AttachScheduleServicesErrors, AttachScheduleServicesRequest, AttachScheduleServicesResponse, AttachScheduleServicesResponse2, AttachScheduleServicesResponses, AuditLogIpInfo, AuditLogResponse, AuditLogUserInfo, AuthFlavorDto, AuthResponse, AuthStatusResponse, AuthTokenResponse, AutofixerRunResponse, AutofixerRunWithLogsResponse, AutofixRunConfig, AutoWatchParams, AvailableContainerInfo, AvailablePermissions, BackupAlertListResponse, BackupAlertResponse, BackupResponse, BackupScheduleResponse, BitbucketAuthInput, BlobCopyData, BlobCopyError, BlobCopyErrors, BlobCopyResponse, BlobCopyResponses, BlobDeleteData, BlobDeleteError, BlobDeleteErrors, BlobDeleteResponse, BlobDeleteResponses, BlobDisableData, BlobDisableErrors, BlobDisableResponse, BlobDisableResponses, BlobDownloadData, BlobDownloadError, BlobDownloadErrors, BlobDownloadResponses, BlobEnableData, BlobEnableErrors, BlobEnableResponse, BlobEnableResponses, BlobHeadData, BlobHeadError, BlobHeadErrors, BlobHeadResponses, BlobListData, BlobListError, BlobListErrors, BlobListResponse, BlobListResponses, BlobPutData, BlobPutError, BlobPutErrors, BlobPutResponse, BlobPutResponses, BlobResponse, BlobStatusData, BlobStatusErrors, BlobStatusResponse, BlobStatusResponse2, BlobStatusResponses, BlobUpdateData, BlobUpdateErrors, BlobUpdateResponse, BlobUpdateResponses, BranchInfo, BranchListResponse, BrowserCount, BrowsersQuery, BuildConfiguration, BuildLimitsSettings, CancelBackupData, CancelBackupError, CancelBackupErrors, CancelBackupResponse, CancelBackupResponse2, CancelBackupResponses, CancelData, CancelDeploymentData, CancelDeploymentErrors, CancelDeploymentResponse, CancelDeploymentResponses, CancelDomainOrderData, CancelDomainOrderErrors, CancelDomainOrderResponse, CancelDomainOrderResponses, CancelErrors, CancelPgUpgradeData, CancelPgUpgradeErrors, CancelPgUpgradeResponse, CancelPgUpgradeResponses, CancelResponses, CancelRunData, CancelRunErrors, CancelRunResponse, CancelRunResponses, CancelScheduleRunData, CancelScheduleRunError, CancelScheduleRunErrors, CancelScheduleRunResponse, CancelScheduleRunResponses, CertStatusResponse, ChallengeConfig, ChallengeError, ChallengeValidationStatus, ChangePasswordRequest, ChangePasswordSelfData, ChangePasswordSelfErrors, ChangePasswordSelfResponse, ChangePasswordSelfResponses, ChangeProjectSourceData, ChangeProjectSourceErrors, ChangeProjectSourceRequest, ChangeProjectSourceResponse, ChangeProjectSourceResponses, ChatCompletionChoice, ChatCompletionRequest, ChatCompletionResponse, ChatCompletionsData, ChatCompletionsError, ChatCompletionsErrors, ChatCompletionsResponse, ChatCompletionsResponses, ChatMessage, ChatReadinessResponse, CheckAnalyticsHasEventsData, CheckAnalyticsHasEventsErrors, CheckAnalyticsHasEventsResponse, CheckAnalyticsHasEventsResponses, CheckCommitExistsData, CheckCommitExistsErrors, CheckCommitExistsResponse, CheckCommitExistsResponses, CheckDomainStatusData, CheckDomainStatusErrors, CheckDomainStatusResponse, CheckDomainStatusResponses, CheckExplorerSupportData, CheckExplorerSupportErrors, CheckExplorerSupportResponse, CheckExplorerSupportResponses, CheckIpBlockedData, CheckIpBlockedError, CheckIpBlockedErrors, CheckIpBlockedResponses, CheckProviderDeletionSafetyData, CheckProviderDeletionSafetyErrors, CheckProviderDeletionSafetyResponse, CheckProviderDeletionSafetyResponses, ChildBackupEntryResponse, ChildBackupListResponse, ChunkUploadOptionsData, ChunkUploadOptionsResponse, ChunkUploadOptionsResponses, CleanupExpiredBackupsData, CleanupExpiredBackupsError, CleanupExpiredBackupsErrors, CleanupExpiredBackupsRequest, CleanupExpiredBackupsResponse, CleanupExpiredBackupsResponses, ClearPreviewPasswordData, ClearPreviewPasswordErrors, ClearPreviewPasswordResponse, ClearPreviewPasswordResponses, CliDeviceApproveData, CliDeviceApproveErrors, CliDeviceApproveRequest, CliDeviceApproveResponse, CliDeviceApproveResponse2, CliDeviceApproveResponses, CliDeviceDenyData, CliDeviceDenyErrors, CliDeviceDenyResponse, CliDeviceDenyResponses, CliDeviceLookupData, CliDeviceLookupErrors, CliDeviceLookupResponse, CliDeviceLookupResponse2, CliDeviceLookupResponses, CliDevicePollData, CliDevicePollErrors, CliDevicePollRequest, CliDevicePollResponse, CliDevicePollResponse2, CliDevicePollResponses, CliDeviceStartData, CliDeviceStartErrors, CliDeviceStartRequest, CliDeviceStartResponse, CliDeviceStartResponse2, CliDeviceStartResponses, ClientOptions, CliLoginRequest, CliLogoutData, CliLogoutErrors, CliLogoutResponse, CliLogoutResponses, CloudCapability, CloudflareConfig, CloudProvider, CloudSettings, CloudStatus, ClusterCapacity, ClusterDnsSettings, ClusterHealthReportResponse, ClusterMemberHealthResponse, ClusterMemberRequest, CmdBody, CmdData, CmdErrors, CmdInner, CmdKillBody, CmdKillData, CmdKillErrors, CmdKillResponse, CmdKillResponses, CmdLogsData, CmdLogsErrors, CmdLogsResponses, CmdResponse, CmdResponse2, CmdResponses, CommitExistsResponse, CommitInfo, CommitListResponse, Comparator, ComposePublicPort, ConfirmPendingActionData, ConfirmPendingActionErrors, ConfirmPendingActionResponse, ConfirmPendingActionResponses, ConnectionListQuery, ConnectionListResponse, ConnectionResponse, ConnectionTestResult, ConsoleEventPayload, ContainerActionResponse, ContainerDetailResponse, ContainerEnvironmentVariableValueResponse, ContainerInfoResponse, ContainerInventoryItem, ContainerListResponse, ContainerLogSettings, ContainerLogsQuery, ContainerMetricHistoryPoint, ContainerMetricsGetHistoryData, ContainerMetricsGetHistoryErrors, ContainerMetricsGetHistoryResponse, ContainerMetricsGetHistoryResponses, ContainerMetricsHistoryQuery, ContainerMetricsResponse, ContainerResponse, ContainerRuntimeInfo, ContainerStatsSample, ContentPart, ContextLine, ContextLogsRequest, ContextLogsResponse, ConversationDetailResponse, ConversationResponse, ConversationsQueryParams, ConversationSummary, CopyBlobRequest, CostAnalysis, CreateAgentData, CreateAgentErrors, CreateAgentResponse, CreateAgentResponses, CreateAlertData, CreateAlertError, CreateAlertErrors, CreateAlertResponse, CreateAlertResponses, CreateAlertRuleData, CreateAlertRuleErrors, CreateAlertRuleRequest, CreateAlertRuleResponse, CreateAlertRuleResponses, CreateApiKeyData, CreateApiKeyErrors, CreateApiKeyRequest, CreateApiKeyResponse, CreateApiKeyResponse2, CreateApiKeyResponses, CreateBackupScheduleData, CreateBackupScheduleError, CreateBackupScheduleErrors, CreateBackupScheduleRequest, CreateBackupScheduleResponse, CreateBackupScheduleResponses, CreateBitbucketProviderData, CreateBitbucketProviderErrors, CreateBitbucketProviderResponse, CreateBitbucketProviderResponses, CreateBitbucketRequest, CreateCloudflareProviderData, CreateCloudflareProviderErrors, CreateCloudflareProviderRequest, CreateCloudflareProviderResponse, CreateCloudflareProviderResponses, CreateConversationData, CreateConversationErrors, CreateConversationRequest, CreateConversationResponse, CreateConversationResponses, CreateCustomDomainData, CreateCustomDomainErrors, CreateCustomDomainResponse, CreateCustomDomainResponses, CreateDashboardData, CreateDashboardError, CreateDashboardErrors, CreateDashboardRequest, CreateDashboardResponse, CreateDashboardResponses, CreateDeploymentTokenData, CreateDeploymentTokenErrors, CreateDeploymentTokenRequest, CreateDeploymentTokenResponse, CreateDeploymentTokenResponse2, CreateDeploymentTokenResponses, CreateDnsProviderData, CreateDnsProviderErrors, CreateDnsProviderRequest, CreateDnsProviderResponse, CreateDnsProviderResponses, CreateDomainData, CreateDomainErrors, CreateDomainRequest, CreateDomainResponse, CreateDomainResponses, CreatedResource, CreateDsnData, CreateDsnErrors, CreateDsnRequest, CreateDsnResponse, CreateDsnResponses, CreateEmailDomainData, CreateEmailDomainErrors, CreateEmailDomainRequest, CreateEmailDomainResponse, CreateEmailDomainResponses, CreateEmailProviderData, CreateEmailProviderErrors, CreateEmailProviderRequest, CreateEmailProviderResponse, CreateEmailProviderResponses, CreateEnvironmentData, CreateEnvironmentErrors, CreateEnvironmentRequest, CreateEnvironmentResponse, CreateEnvironmentResponses, CreateEnvironmentVariableData, CreateEnvironmentVariableErrors, CreateEnvironmentVariableRequest, CreateEnvironmentVariableResponse, CreateEnvironmentVariableResponses, CreateExternalServiceRequest, CreateFlagData, CreateFlagErrors, CreateFlagRequest, CreateFlagResponse, CreateFlagResponses, CreateFunnelData, CreateFunnelErrors, CreateFunnelRequest, CreateFunnelResponse, CreateFunnelResponse2, CreateFunnelResponses, CreateFunnelStep, CreateGenericProviderData, CreateGenericProviderErrors, CreateGenericProviderResponse, CreateGenericProviderResponses, CreateGenericRequest, CreateGiteaPatProviderData, CreateGiteaPatProviderErrors, CreateGiteaPatProviderResponse, CreateGiteaPatProviderResponses, CreateGiteaPatRequest, CreateGithubPatProviderData, CreateGithubPatProviderErrors, CreateGithubPatProviderResponse, CreateGithubPatProviderResponses, CreateGitHubPatRequest, CreateGitlabOauthProviderData, CreateGitlabOauthProviderErrors, CreateGitlabOauthProviderResponse, CreateGitlabOauthProviderResponses, CreateGitLabOAuthRequest, CreateGitlabPatProviderData, CreateGitlabPatProviderErrors, CreateGitlabPatProviderResponse, CreateGitlabPatProviderResponses, CreateGitLabPatRequest, CreateGitProviderData, CreateGitProviderErrors, CreateGitProviderResponse, CreateGitProviderResponses, CreateGlobalMcpData, CreateGlobalMcpErrors, CreateGlobalMcpResponse, CreateGlobalMcpResponses, CreateGlobalSkillData, CreateGlobalSkillErrors, CreateGlobalSkillResponse, CreateGlobalSkillResponses, CreateIncidentData, CreateIncidentErrors, CreateIncidentRequest, CreateIncidentResponse, CreateIncidentResponses, CreateIntegrationBody, CreateIpAccessControlData, CreateIpAccessControlError, CreateIpAccessControlErrors, CreateIpAccessControlRequest, CreateIpAccessControlResponse, CreateIpAccessControlResponses, CreateMcpData, CreateMcpErrors, CreateMcpRequest, CreateMcpResponse, CreateMcpResponses, CreateMetricAlertRequest, CreateMonitorData, CreateMonitorErrors, CreateMonitorRequest, CreateMonitorResponse, CreateMonitorResponses, CreateNotificationEmailProviderData, CreateNotificationEmailProviderErrors, CreateNotificationEmailProviderRequest, CreateNotificationEmailProviderResponse, CreateNotificationEmailProviderResponses, CreateNotificationProviderData, CreateNotificationProviderErrors, CreateNotificationProviderResponse, CreateNotificationProviderResponses, CreateOidcProviderData, CreateOidcProviderErrors, CreateOidcProviderRequest, CreateOidcProviderResponse, CreateOidcProviderResponses, CreateOidcRoleMappingData, CreateOidcRoleMappingRequest, CreateOidcRoleMappingResponse, CreateOidcRoleMappingResponses, CreateOrRecreateOrderData, CreateOrRecreateOrderErrors, CreateOrRecreateOrderResponse, CreateOrRecreateOrderResponses, CreatePlanData, CreatePlanErrors, CreatePlanRequest, CreatePlanResponse, CreatePlanResponse2, CreatePlanResponses, CreatePrData, CreatePrErrors, CreateProjectAccessRequest, CreateProjectData, CreateProjectErrors, CreateProjectFromTemplateData, CreateProjectFromTemplateErrors, CreateProjectFromTemplateRequest, CreateProjectFromTemplateResponse, CreateProjectFromTemplateResponse2, CreateProjectFromTemplateResponses, CreateProjectReleaseData, CreateProjectReleaseErrors, CreateProjectReleaseResponse, CreateProjectReleaseResponses, CreateProjectRequest, CreateProjectResponse, CreateProjectResponses, CreateProjectSecretData, CreateProjectSecretErrors, CreateProjectSecretRequest, CreateProjectSecretResponse, CreateProjectSecretResponses, CreateProviderKeyData, CreateProviderKeyError, CreateProviderKeyErrors, CreateProviderKeyRequest, CreateProviderKeyResponse, CreateProviderKeyResponses, CreateProviderRequest, CreatePrResponse, CreatePrResponse2, CreatePrResponses, CreateReleaseData, CreateReleaseErrors, CreateReleaseResponse, CreateReleaseResponses, CreateRouteData, CreateRouteErrors, CreateRouteRequest, CreateRouteResponse, CreateRouteResponses, CreateS3SourceData, CreateS3SourceError, CreateS3SourceErrors, CreateS3SourceRequest, CreateS3SourceResponse, CreateS3SourceResponses, CreateSandboxBody, CreateSandboxData, CreateSandboxErrors, CreateSandboxResponse, CreateSandboxResponses, CreateServiceData, CreateServiceErrors, CreateServiceResponse, CreateServiceResponses, CreateSkillData, CreateSkillErrors, CreateSkillRequest, CreateSkillResponse, CreateSkillResponses, CreateSlackProviderData, CreateSlackProviderErrors, CreateSlackProviderRequest, CreateSlackProviderResponse, CreateSlackProviderResponses, CreateTeamData, CreateTeamErrors, CreateTeamMemberRequest, CreateTeamRequest, CreateTeamResponse, CreateTeamResponses, CreateUserData, CreateUserErrors, CreateUserRequest, CreateUserResponse, CreateUserResponses, CreateWebhookData, CreateWebhookErrors, CreateWebhookProviderData, CreateWebhookProviderErrors, CreateWebhookProviderRequest, CreateWebhookProviderResponse, CreateWebhookProviderResponses, CreateWebhookRequestBody, CreateWebhookResponse, CreateWebhookResponses, CronExecutionInfo, CronInfo, CrossProjectSiblingRef, CrossProjectTraceResponse, CurrentStatusResponse, CustomDomainRequest, CustomDomainResponse, CustomerMovementResponse, DashboardLayout, DashboardProjectsAnalyticsQuery, DashboardProjectsAnalyticsResponse, DashboardSection, DashboardTile, DatabaseMetricsResponse, DatabaseMetricsRow, DataImplication, DataImplicationSeverity, DeactivateApiKeyData, DeactivateApiKeyErrors, DeactivateApiKeyResponse, DeactivateApiKeyResponses, DeactivateConnectionData, DeactivateConnectionErrors, DeactivateConnectionResponses, DeactivateProviderData, DeactivateProviderErrors, DeactivateProviderResponses, DeleteAgentData, DeleteAgentErrors, DeleteAgentResponse, DeleteAgentResponses, DeleteAlertData, DeleteAlertError, DeleteAlertErrors, DeleteAlertResponse, DeleteAlertResponses, DeleteAlertRuleData, DeleteAlertRuleErrors, DeleteAlertRuleResponse, DeleteAlertRuleResponses, DeleteApiKeyData, DeleteApiKeyErrors, DeleteApiKeyResponse, DeleteApiKeyResponses, DeleteBackupData, DeleteBackupError, DeleteBackupErrors, DeleteBackupResponse, DeleteBackupResponses, DeleteBackupScheduleData, DeleteBackupScheduleError, DeleteBackupScheduleErrors, DeleteBackupScheduleResponse, DeleteBackupScheduleResponses, DeleteBlobRequest, DeleteBlobResponse, DeleteConnectionData, DeleteConnectionErrors, DeleteConnectionResponse, DeleteConnectionResponses, DeleteCustomDomainData, DeleteCustomDomainErrors, DeleteCustomDomainResponse, DeleteCustomDomainResponses, DeleteDashboardData, DeleteDashboardError, DeleteDashboardErrors, DeleteDashboardResponse, DeleteDashboardResponses, DeleteDeploymentTokenData, DeleteDeploymentTokenErrors, DeleteDeploymentTokenResponse, DeleteDeploymentTokenResponses, DeleteDnsProviderData, DeleteDnsProviderErrors, DeleteDnsProviderResponse, DeleteDnsProviderResponses, DeleteDomainData, DeleteDomainErrors, DeleteDomainResponse, DeleteDomainResponses, DeleteEmailDomainData, DeleteEmailDomainErrors, DeleteEmailDomainResponse, DeleteEmailDomainResponses, DeleteEmailProviderData, DeleteEmailProviderErrors, DeleteEmailProviderResponse, DeleteEmailProviderResponses, DeleteEnvironmentData, DeleteEnvironmentDomainData, DeleteEnvironmentDomainErrors, DeleteEnvironmentDomainResponse, DeleteEnvironmentDomainResponses, DeleteEnvironmentErrors, DeleteEnvironmentResponse, DeleteEnvironmentResponses, DeleteEnvironmentVariableData, DeleteEnvironmentVariableErrors, DeleteEnvironmentVariableResponse, DeleteEnvironmentVariableResponses, DeleteExternalImageData, DeleteExternalImageErrors, DeleteExternalImageResponse, DeleteExternalImageResponses, DeleteFunnelData, DeleteFunnelErrors, DeleteFunnelResponses, DeleteGitProviderData, DeleteGitProviderErrors, DeleteGitProviderResponse, DeleteGitProviderResponses, DeleteGlobalMcpData, DeleteGlobalMcpErrors, DeleteGlobalMcpResponse, DeleteGlobalMcpResponses, DeleteGlobalSkillData, DeleteGlobalSkillErrors, DeleteGlobalSkillResponse, DeleteGlobalSkillResponses, DeleteIpAccessControlData, DeleteIpAccessControlError, DeleteIpAccessControlErrors, DeleteIpAccessControlResponse, DeleteIpAccessControlResponses, DeleteMcpData, DeleteMcpErrors, DeleteMcpResponse, DeleteMcpResponses, DeleteMonitorData, DeleteMonitorErrors, DeleteMonitorResponse, DeleteMonitorResponses, DeleteNotificationProviderData, DeleteNotificationProviderErrors, DeleteNotificationProviderResponse, DeleteNotificationProviderResponses, DeleteOidcProviderData, DeleteOidcProviderResponse, DeleteOidcProviderResponses, DeleteOidcRoleMappingData, DeleteOidcRoleMappingResponse, DeleteOidcRoleMappingResponses, DeletePreferencesData, DeletePreferencesErrors, DeletePreferencesResponse, DeletePreferencesResponses, DeleteProjectData, DeleteProjectErrors, DeleteProjectResponse, DeleteProjectResponses, DeleteProjectSecretData, DeleteProjectSecretErrors, DeleteProjectSecretResponse, DeleteProjectSecretResponses, DeleteProviderKeyData, DeleteProviderKeyError, DeleteProviderKeyErrors, DeleteProviderKeyResponse, DeleteProviderKeyResponses, DeleteProviderSafelyData, DeleteProviderSafelyErrors, DeleteProviderSafelyResponse, DeleteProviderSafelyResponses, DeleteReleaseSourceFilesData, DeleteReleaseSourceFilesErrors, DeleteReleaseSourceFilesResponse, DeleteReleaseSourceFilesResponses, DeleteReleaseSourceMapsData, DeleteReleaseSourceMapsErrors, DeleteReleaseSourceMapsResponse, DeleteReleaseSourceMapsResponses, DeleteResponse, DeleteRouteData, DeleteRouteErrors, DeleteRouteResponse, DeleteRouteResponses, DeleteS3SourceData, DeleteS3SourceError, DeleteS3SourceErrors, DeleteS3SourceResponse, DeleteS3SourceResponses, DeleteScanData, DeleteScanError, DeleteScanErrors, DeleteScanResponse, DeleteScanResponses, DeleteSecretData, DeleteSecretErrors, DeleteSecretResponse, DeleteSecretResponses, DeleteServiceData, DeleteServiceErrors, DeleteServiceResponse, DeleteServiceResponses, DeleteSessionReplayData, DeleteSessionReplayError, DeleteSessionReplayErrors, DeleteSessionReplayResponses, DeleteSkillData, DeleteSkillErrors, DeleteSkillResponse, DeleteSkillResponses, DeleteSourceMapData, DeleteSourceMapErrors, DeleteSourceMapResponse, DeleteSourceMapResponses, DeleteStaticBundleData, DeleteStaticBundleErrors, DeleteStaticBundleResponse, DeleteStaticBundleResponses, DeleteTeamData, DeleteTeamErrors, DeleteTeamResponse, DeleteTeamResponses, DeleteUserData, DeleteUserErrors, DeleteUserResponse, DeleteUserResponses, DeleteWebhookData, DeleteWebhookErrors, DeleteWebhookResponse, DeleteWebhookResponses, DelRequest, DelResponse, DeployFromImageData, DeployFromImageErrors, DeployFromImageRequest, DeployFromImageResponse, DeployFromImageResponses, DeployFromImageUploadData, DeployFromImageUploadErrors, DeployFromImageUploadQuery, DeployFromImageUploadResponse, DeployFromImageUploadResponses, DeployFromStaticData, DeployFromStaticErrors, DeployFromStaticRequest, DeployFromStaticResponse, DeployFromStaticResponses, DeployFromUploadedSourceData, DeployFromUploadedSourceErrors, DeployFromUploadedSourceResponse, DeployFromUploadedSourceResponses, DeploymentConfig, DeploymentConfigSnapshot, DeploymentConfiguration, DeploymentContainerLogContentResponse, DeploymentContainerLogResponse, DeploymentContainerLogsListResponse, DeploymentEnvironmentResponse, DeploymentJobResponse, DeploymentJobsResponse, DeploymentListResponse, DeploymentMetadata, DeploymentMetricsGetLatestData, DeploymentMetricsGetLatestErrors, DeploymentMetricsGetLatestResponse, DeploymentMetricsGetLatestResponses, DeploymentMetricsGetRangeData, DeploymentMetricsGetRangeErrors, DeploymentMetricsGetRangeResponse, DeploymentMetricsGetRangeResponses, DeploymentMetricsToggleData, DeploymentMetricsToggleErrors, DeploymentMetricsToggleResponses, DeploymentResponse, DeploymentStateResponse, DeploymentStrategy, DeploymentTokenListResponse, DeploymentTokenResponse, DestroySandboxData, DestroySandboxErrors, DestroySandboxResponse, DestroySandboxResponses, DetachScheduleServiceData, DetachScheduleServiceError, DetachScheduleServiceErrors, DetachScheduleServiceResponse, DetachScheduleServiceResponses, DetectionConfig, DetectPublicPresetsData, DetectPublicPresetsErrors, DetectPublicPresetsResponse, DetectPublicPresetsResponses, DeviceCount, DigestSections, Direction, DisableBackupScheduleData, DisableBackupScheduleErrors, DisableBackupScheduleResponse, DisableBackupScheduleResponses, DisableBlobResponse, DisableKvResponse, DisableMfaData, DisableMfaErrors, DisableMfaRequest, DisableMfaResponse, DisableMfaResponses, DisconnectCloudData, DisconnectCloudResponse, DisconnectCloudResponses, DiscoverRequest, DiscoverResponse, DiscoverWorkloadsData, DiscoverWorkloadsErrors, DiscoverWorkloadsResponse, DiscoverWorkloadsResponses, DiskInfo, DiskSpaceAlert, DiskSpaceAlertSettings, DiskSpaceCheckResult, DnsAckRequest, DnsAckResponse, DnsChallengeRecordResult, DnsChangesResponse, DnsCompletionResponse, DnsLookupError, DnsLookupRequest, DnsLookupResponse, DnsProviderCredentials, DnsProviderResponse, DnsProviderSettings, DnsProviderSettingsMasked, DnsProviderType, DnsRecord, DnsRecordChange, DnsRecordContent, DnsRecordResponse, DnsRecordSetupResult, DnsRecordStatusResponse, DnsZone, DockerComposePresetConfig, DockerfilePresetConfig, DockerfileVariant, DockerRegistrySettings, DockerRegistrySettingsMasked, DomainAction, DomainChallengeResponse, DomainData, DomainEnvironmentResponse, DomainError, DomainErrors, DomainPlan, DomainResponse, DomainResponse2, DomainResponses, DownloadGlobalSkillArchiveData, DownloadGlobalSkillArchiveErrors, DownloadGlobalSkillArchiveResponse, DownloadGlobalSkillArchiveResponses, DownloadObjectData, DownloadObjectErrors, DownloadObjectResponse, DownloadObjectResponses, DownloadSkillArchiveData, DownloadSkillArchiveErrors, DownloadSkillArchiveResponse, DownloadSkillArchiveResponses, DrainNodeResponse, DrainStatusResponse, DropArchiveUpload, DropInspectionResponse, DropOffPoint, DropPresetCandidate, EmailConfig, EmailDomainResponse, EmailDomainWithDnsResponse, EmailProviderResponse, EmailProviderTypeRoute, EmailRequest, EmailResponse, EmailStatsResponse, EmailStatusData, EmailStatusErrors, EmailStatusResponse, EmailStatusResponse2, EmailStatusResponses, EmailTrackingResponse, EmailTrackingSetupResponse, EmailTrackingStatusResponse, EmbeddingData, EmbeddingInput, EmbeddingRequest, EmbeddingResponse, EmbeddingsData, EmbeddingsError, EmbeddingsErrors, EmbeddingsResponse, EmbeddingsResponses, EmbeddingUsage, EnableBackupScheduleData, EnableBackupScheduleErrors, EnableBackupScheduleResponse, EnableBackupScheduleResponses, EnableBlobRequest, EnableBlobResponse, EnableKvRequest, EnableKvResponse, EnablePgStatStatementsResponse, EndpointDto, EnqueuedJob, EnrichVisitorData, EnrichVisitorErrors, EnrichVisitorRequest, EnrichVisitorResponse, EnrichVisitorResponse2, EnrichVisitorResponses, EnrollCloudData, EnrollCloudRequest, EnrollCloudResponse, EnrollCloudResponses, EnrollmentTokenInfo, EnrollmentTokenListResponse, EntityInfoResponse, EntityResponse, EnvironmentConfiguration, EnvironmentDomainResponse, EnvironmentInfo, EnvironmentResponse, EnvironmentVariable, EnvironmentVariableInfo, EnvironmentVariableResponse, EnvironmentVariableValueResponse, EnvVarInput, EnvVarIntegrationInfo, EnvVarResponse, EnvVarTemplateResponse, ErrorDashboardStatsQuery, ErrorDashboardStatsResponse, ErrorEventResponse, ErrorGroupResponse, ErrorGroupStatsResponse, ErrorResponse, ErrorRow, ErrorTimeSeriesDataResponse, ErrorTimeSeriesQuery, EventActivityBucket, EventBreakdown, EventBrowserStats, EventCount, EventCountryStats, EventDetailQuery, EventDetailResponse, EventEntriesQuery, EventEntriesResponse, EventEntryInfo, EventKind, EventMetricsPayload, EventReferrerStats, EventsCountQuery, EventsResponse, EventTimeline, EventTimelineQuery, EventType, EventTypeBreakdown, EventTypeBreakdownQuery, EventTypeResponse, EventTypesResponse, EventVisitorInfo, EventVisitorsQuery, EventVisitorsResponse, ExecBody, ExecData, ExecDetachedData, ExecDetachedErrors, ExecDetachedResponse, ExecDetachedResponse2, ExecDetachedResponses, ExecErrors, ExecResponse, ExecResponse2, ExecResponses, ExecuteDeploymentOperationData, ExecuteDeploymentOperationErrors, ExecuteDeploymentOperationResponse, ExecuteDeploymentOperationResponses, ExecuteImportData, ExecuteImportErrors, ExecuteImportRequest, ExecuteImportResponse, ExecuteImportResponse2, ExecuteImportResponses, ExecuteOperationRequest, ExpireRequest, ExpireResponse, ExplorerSupportResponse, ExtendTimeoutBody, ExtendTimeoutData, ExtendTimeoutErrors, ExtendTimeoutResponse, ExtendTimeoutResponses, ExternalImageResponse, ExternalServiceBackupResponse, ExternalServiceDetails, ExternalServiceEnablePgStatStatementsData, ExternalServiceEnablePgStatStatementsErrors, ExternalServiceEnablePgStatStatementsResponse, ExternalServiceEnablePgStatStatementsResponses, ExternalServiceInfo, ExternalServiceMetricsByDatabaseData, ExternalServiceMetricsByDatabaseErrors, ExternalServiceMetricsByDatabaseResponse, ExternalServiceMetricsByDatabaseResponses, ExternalServiceMetricsCreateAlertRuleData, ExternalServiceMetricsCreateAlertRuleErrors, ExternalServiceMetricsCreateAlertRuleResponse, ExternalServiceMetricsCreateAlertRuleResponses, ExternalServiceMetricsDeleteAlertRuleData, ExternalServiceMetricsDeleteAlertRuleErrors, ExternalServiceMetricsDeleteAlertRuleResponse, ExternalServiceMetricsDeleteAlertRuleResponses, ExternalServiceMetricsGetAlertRulesData, ExternalServiceMetricsGetAlertRulesErrors, ExternalServiceMetricsGetAlertRulesResponse, ExternalServiceMetricsGetAlertRulesResponses, ExternalServiceMetricsGetLatestData, ExternalServiceMetricsGetLatestErrors, ExternalServiceMetricsGetLatestResponse, ExternalServiceMetricsGetLatestResponses, ExternalServiceMetricsGetRangeData, ExternalServiceMetricsGetRangeErrors, ExternalServiceMetricsGetRangeResponse, ExternalServiceMetricsGetRangeResponses, ExternalServiceMetricsStatusData, ExternalServiceMetricsStatusErrors, ExternalServiceMetricsStatusResponse, ExternalServiceMetricsStatusResponses, ExternalServiceMetricsToggleData, ExternalServiceMetricsToggleErrors, ExternalServiceMetricsToggleResponses, ExternalServiceMetricsUpdateAlertRuleData, ExternalServiceMetricsUpdateAlertRuleErrors, ExternalServiceMetricsUpdateAlertRuleResponse, ExternalServiceMetricsUpdateAlertRuleResponses, ExternalServiceResetPgStatStatementsData, ExternalServiceResetPgStatStatementsErrors, ExternalServiceResetPgStatStatementsResponse, ExternalServiceResetPgStatStatementsResponses, ExternalServiceSummary, FieldResponse, FinalizeOrderData, FinalizeOrderErrors, FinalizeOrderResponse, FinalizeOrderResponses, FinalizeProjectReleaseData, FinalizeProjectReleaseErrors, FinalizeProjectReleaseResponse, FinalizeProjectReleaseResponses, FindConversationData, FindConversationErrors, FindConversationResponse, FindConversationResponses, FiringSeriesEntry, FlagEnvironmentResponse, FlagListResponse, FlagResponse, FlagSnapshot, FlagSnapshotResponse, FlagValueType, ForecastAlgorithm, ForecastParams, FullError, FullEvent, FullRequest, FunnelMetricsResponse, FunnelResponse, GatewayStatus, GenAiEvent, GenAiSpanDetail, GenAiTraceDetailResponse, GenAiTraceSummariesResponse, GenAiTraceSummary, GeneralStatsQuery, GeneralStatsResponse, GenerateDockerfileRequest, GenerateDockerfileResponse, GenerateJoinTokenData, GenerateJoinTokenErrors, GenerateJoinTokenResponse, GenerateJoinTokenResponse2, GenerateJoinTokenResponses, GeneratePresetDockerfileData, GeneratePresetDockerfileErrors, GeneratePresetDockerfileResponse, GeneratePresetDockerfileResponses, GeoLocationResponse, GeoRestrictionsConfig, GetAccessInfoData, GetAccessInfoErrors, GetAccessInfoResponse, GetAccessInfoResponses, GetActiveVisitorsData, GetActiveVisitorsErrors, GetActiveVisitorsResponse, GetActiveVisitorsResponses, GetActivityGraphData, GetActivityGraphErrors, GetActivityGraphResponse, GetActivityGraphResponses, GetAdminGateData, GetAdminGateErrors, GetAdminGateResponse, GetAdminGateResponses, GetAgentData, GetAgentErrors, GetAgentResponse, GetAgentResponses, GetAggregatedBucketsData, GetAggregatedBucketsErrors, GetAggregatedBucketsResponse, GetAggregatedBucketsResponses, GetAiAgentBreakdownData, GetAiAgentBreakdownError, GetAiAgentBreakdownErrors, GetAiAgentBreakdownResponse, GetAiAgentBreakdownResponses, GetAiAgentPagesData, GetAiAgentPagesError, GetAiAgentPagesErrors, GetAiAgentPagesResponse, GetAiAgentPagesResponses, GetAiAgentTimelineData, GetAiAgentTimelineError, GetAiAgentTimelineErrors, GetAiAgentTimelineResponse, GetAiAgentTimelineResponses, GetAiPageBreakdownData, GetAiPageBreakdownError, GetAiPageBreakdownErrors, GetAiPageBreakdownResponse, GetAiPageBreakdownResponses, GetAiStatusBreakdownData, GetAiStatusBreakdownError, GetAiStatusBreakdownErrors, GetAiStatusBreakdownResponse, GetAiStatusBreakdownResponses, GetAlertData, GetAlertError, GetAlertErrors, GetAlertResponse, GetAlertResponses, GetAlertRuleData, GetAlertRuleErrors, GetAlertRuleResponse, GetAlertRuleResponses, GetAllRepositoriesByNameData, GetAllRepositoriesByNameErrors, GetAllRepositoriesByNameResponse, GetAllRepositoriesByNameResponses, GetAnalyticsActiveVisitorsData, GetAnalyticsActiveVisitorsErrors, GetAnalyticsActiveVisitorsResponse, GetAnalyticsActiveVisitorsResponses, GetAnalyticsEventsCountData, GetAnalyticsEventsCountErrors, GetAnalyticsEventsCountResponse, GetAnalyticsEventsCountResponses, GetAnalyticsSessionEventsData, GetAnalyticsSessionEventsErrors, GetAnalyticsSessionEventsResponse, GetAnalyticsSessionEventsResponses, GetAnalyticsVisitorSessionsData, GetAnalyticsVisitorSessionsErrors, GetAnalyticsVisitorSessionsResponse, GetAnalyticsVisitorSessionsResponses, GetApiKeyData, GetApiKeyErrors, GetApiKeyPermissionsData, GetApiKeyPermissionsErrors, GetApiKeyPermissionsResponse, GetApiKeyPermissionsResponses, GetApiKeyResponse, GetApiKeyResponses, GetAuditLogData, GetAuditLogErrors, GetAuditLogResponse, GetAuditLogResponses, GetBackupData, GetBackupError, GetBackupErrors, GetBackupResponse, GetBackupResponses, GetBackupScheduleData, GetBackupScheduleErrors, GetBackupScheduleResponse, GetBackupScheduleResponses, GetBranchesByRepositoryIdData, GetBranchesByRepositoryIdErrors, GetBranchesByRepositoryIdResponse, GetBranchesByRepositoryIdResponses, GetBucketedIncidentsData, GetBucketedIncidentsErrors, GetBucketedIncidentsResponse, GetBucketedIncidentsResponses, GetBucketedStatusData, GetBucketedStatusErrors, GetBucketedStatusResponse, GetBucketedStatusResponses, GetChallengeTokenData, GetChallengeTokenErrors, GetChallengeTokenResponse, GetChallengeTokenResponses, GetChatReadinessData, GetChatReadinessErrors, GetChatReadinessResponse, GetChatReadinessResponses, GetCliStatusData, GetCliStatusErrors, GetCliStatusResponses, GetCloudCapabilityData, GetCloudCapabilityResponse, GetCloudCapabilityResponses, GetCloudStatusData, GetCloudStatusResponse, GetCloudStatusResponses, GetClusterHealthData, GetClusterHealthErrors, GetClusterHealthResponse, GetClusterHealthResponses, GetClusterMemberData, GetClusterMemberErrors, GetClusterMemberResponse, GetClusterMemberResponses, GetCmdData, GetCmdErrors, GetCmdResponse, GetCmdResponses, GetContainerDetailData, GetContainerDetailErrors, GetContainerDetailResponse, GetContainerDetailResponses, GetContainerEnvironmentVariableData, GetContainerEnvironmentVariableErrors, GetContainerEnvironmentVariableResponse, GetContainerEnvironmentVariableResponses, GetContainerInfoData, GetContainerInfoErrors, GetContainerInfoResponse, GetContainerInfoResponses, GetContainerLogsByIdData, GetContainerLogsByIdErrors, GetContainerLogsData, GetContainerLogsErrors, GetContainerMetricsData, GetContainerMetricsErrors, GetContainerMetricsResponse, GetContainerMetricsResponses, GetConversationData, GetConversationDetailData, GetConversationDetailError, GetConversationDetailErrors, GetConversationDetailResponse, GetConversationDetailResponses, GetConversationErrors, GetConversationResponse, GetConversationResponses, GetConversationsData, GetConversationsError, GetConversationsErrors, GetConversationsResponse, GetConversationsResponses, GetCronByIdData, GetCronByIdErrors, GetCronByIdResponse, GetCronByIdResponses, GetCronExecutionsData, GetCronExecutionsErrors, GetCronExecutionsResponse, GetCronExecutionsResponses, GetCrossProjectTraceSiblingsData, GetCrossProjectTraceSiblingsError, GetCrossProjectTraceSiblingsErrors, GetCrossProjectTraceSiblingsResponse, GetCrossProjectTraceSiblingsResponses, GetCurrentMonitorStatusData, GetCurrentMonitorStatusErrors, GetCurrentMonitorStatusResponse, GetCurrentMonitorStatusResponses, GetCurrentUserData, GetCurrentUserErrors, GetCurrentUserResponse, GetCurrentUserResponses, GetCustomDomainData, GetCustomDomainErrors, GetCustomDomainResponse, GetCustomDomainResponses, GetDashboardData, GetDashboardError, GetDashboardErrors, GetDashboardProjectsAnalyticsData, GetDashboardProjectsAnalyticsErrors, GetDashboardProjectsAnalyticsResponse, GetDashboardProjectsAnalyticsResponses, GetDashboardResponse, GetDashboardResponses, GetDeliveryData, GetDeliveryErrors, GetDeliveryResponse, GetDeliveryResponses, GetDeploymentContainerLogContentData, GetDeploymentContainerLogContentErrors, GetDeploymentContainerLogContentResponse, GetDeploymentContainerLogContentResponses, GetDeploymentData, GetDeploymentErrors, GetDeploymentJobLogsData, GetDeploymentJobLogsErrors, GetDeploymentJobLogsResponse, GetDeploymentJobLogsResponses, GetDeploymentJobsData, GetDeploymentJobsErrors, GetDeploymentJobsResponse, GetDeploymentJobsResponses, GetDeploymentOperationsData, GetDeploymentOperationsErrors, GetDeploymentOperationsResponse, GetDeploymentOperationsResponses, GetDeploymentOperationStatusData, GetDeploymentOperationStatusErrors, GetDeploymentOperationStatusResponse, GetDeploymentOperationStatusResponses, GetDeploymentResponse, GetDeploymentResponses, GetDeploymentsParams, GetDeploymentTokenData, GetDeploymentTokenErrors, GetDeploymentTokenResponse, GetDeploymentTokenResponses, GetDiskStatusData, GetDiskStatusErrors, GetDiskStatusResponse, GetDiskStatusResponses, GetDnsChangesData, GetDnsChangesErrors, GetDnsChangesResponse, GetDnsChangesResponses, GetDnsProviderData, GetDnsProviderErrors, GetDnsProviderResponse, GetDnsProviderResponses, GetDomainByHostData, GetDomainByHostErrors, GetDomainByHostResponse, GetDomainByHostResponses, GetDomainByIdData, GetDomainByIdErrors, GetDomainByIdResponse, GetDomainByIdResponses, GetDomainByNameData, GetDomainByNameErrors, GetDomainByNameResponse, GetDomainByNameResponses, GetDomainData, GetDomainDnsRecordsData, GetDomainDnsRecordsErrors, GetDomainDnsRecordsResponse, GetDomainDnsRecordsResponses, GetDomainErrors, GetDomainOrderData, GetDomainOrderErrors, GetDomainOrderResponse, GetDomainOrderResponses, GetDomainResponse, GetDomainResponses, GetEmailData, GetEmailErrors, GetEmailEventsData, GetEmailEventsErrors, GetEmailEventsResponse, GetEmailEventsResponses, GetEmailLinksData, GetEmailLinksErrors, GetEmailLinksResponse, GetEmailLinksResponses, GetEmailProviderData, GetEmailProviderErrors, GetEmailProviderResponse, GetEmailProviderResponses, GetEmailResponse, GetEmailResponses, GetEmailStatsData, GetEmailStatsErrors, GetEmailStatsResponse, GetEmailStatsResponses, GetEmailTrackingData, GetEmailTrackingErrors, GetEmailTrackingResponse, GetEmailTrackingResponses, GetEmailTrackingStatusData, GetEmailTrackingStatusErrors, GetEmailTrackingStatusResponse, GetEmailTrackingStatusResponses, GetEntityInfoData, GetEntityInfoErrors, GetEntityInfoResponse, GetEntityInfoResponses, GetEnvironmentCronsData, GetEnvironmentCronsErrors, GetEnvironmentCronsResponse, GetEnvironmentCronsResponses, GetEnvironmentData, GetEnvironmentDomainsData, GetEnvironmentDomainsErrors, GetEnvironmentDomainsResponse, GetEnvironmentDomainsResponses, GetEnvironmentErrors, GetEnvironmentResponse, GetEnvironmentResponses, GetEnvironmentsData, GetEnvironmentsErrors, GetEnvironmentsResponse, GetEnvironmentsResponses, GetEnvironmentVariablesData, GetEnvironmentVariablesErrors, GetEnvironmentVariablesQuery, GetEnvironmentVariablesResponse, GetEnvironmentVariablesResponses, GetEnvironmentVariableValueData, GetEnvironmentVariableValueErrors, GetEnvironmentVariableValueResponse, GetEnvironmentVariableValueResponses, GetErrorDashboardStatsData, GetErrorDashboardStatsErrors, GetErrorDashboardStatsResponse, GetErrorDashboardStatsResponses, GetErrorEventData, GetErrorEventErrors, GetErrorEventResponse, GetErrorEventResponses, GetErrorGroupData, GetErrorGroupErrors, GetErrorGroupResponse, GetErrorGroupResponses, GetErrorStatsData, GetErrorStatsErrors, GetErrorStatsResponse, GetErrorStatsResponses, GetErrorTimeSeriesData, GetErrorTimeSeriesErrors, GetErrorTimeSeriesResponse, GetErrorTimeSeriesResponses, GetEventDetailData, GetEventDetailErrors, GetEventDetailResponse, GetEventDetailResponses, GetEventEntriesData, GetEventEntriesErrors, GetEventEntriesResponse, GetEventEntriesResponses, GetEventsCountData, GetEventsCountErrors, GetEventsCountResponse, GetEventsCountResponses, GetEventsTimelineData, GetEventsTimelineErrors, GetEventsTimelineResponse, GetEventsTimelineResponses, GetEventTypeBreakdownData, GetEventTypeBreakdownErrors, GetEventTypeBreakdownResponse, GetEventTypeBreakdownResponses, GetEventVisitorsData, GetEventVisitorsErrors, GetEventVisitorsResponse, GetEventVisitorsResponses, GetExternalImageData, GetExternalImageErrors, GetExternalImageResponse, GetExternalImageResponses, GetFileData, GetFileErrors, GetFileResponse, GetFileResponses, GetFlagData, GetFlagErrors, GetFlagResponse, GetFlagResponses, GetFlagSnapshotData, GetFlagSnapshotErrors, GetFlagSnapshotResponse, GetFlagSnapshotResponses, GetFunnelMetricsData, GetFunnelMetricsErrors, GetFunnelMetricsQuery, GetFunnelMetricsResponse, GetFunnelMetricsResponses, GetGenaiTraceData, GetGenaiTraceError, GetGenaiTraceErrors, GetGenaiTraceResponse, GetGenaiTraceResponses, GetGeneralStatsData, GetGeneralStatsErrors, GetGeneralStatsResponse, GetGeneralStatsResponses, GetGitProviderData, GetGitProviderErrors, GetGitProviderResponse, GetGitProviderResponses, GetGlobalEventsData, GetGlobalEventsErrors, GetGlobalEventsResponse, GetGlobalEventsResponses, GetGlobalEventStatsData, GetGlobalEventStatsErrors, GetGlobalEventStatsResponse, GetGlobalEventStatsResponses, GetGlobalMcpData, GetGlobalMcpErrors, GetGlobalMcpResponse, GetGlobalMcpResponses, GetGlobalSandboxStatusData, GetGlobalSandboxStatusErrors, GetGlobalSandboxStatusResponse, GetGlobalSandboxStatusResponses, GetGlobalSkillData, GetGlobalSkillErrors, GetGlobalSkillResponse, GetGlobalSkillResponses, GetGroupedPageMetricsData, GetGroupedPageMetricsError, GetGroupedPageMetricsErrors, GetGroupedPageMetricsResponse, GetGroupedPageMetricsResponses, GetHealthData, GetHealthError, GetHealthErrors, GetHealthResponse, GetHealthResponses, GetHourlyVisitsData, GetHourlyVisitsErrors, GetHourlyVisitsResponse, GetHourlyVisitsResponses, GetHttpChallengeDebugData, GetHttpChallengeDebugErrors, GetHttpChallengeDebugResponse, GetHttpChallengeDebugResponses, GetImportStatusData, GetImportStatusErrors, GetImportStatusResponse, GetImportStatusResponses, GetIncidentData, GetIncidentErrors, GetIncidentResponse, GetIncidentResponses, GetIncidentUpdatesData, GetIncidentUpdatesErrors, GetIncidentUpdatesResponse, GetIncidentUpdatesResponses, GetIpAccessControlData, GetIpAccessControlError, GetIpAccessControlErrors, GetIpAccessControlResponse, GetIpAccessControlResponses, GetIpGeolocationData, GetIpGeolocationError, GetIpGeolocationErrors, GetIpGeolocationResponse, GetIpGeolocationResponses, GetJoinTokenStatusData, GetJoinTokenStatusErrors, GetJoinTokenStatusResponse, GetJoinTokenStatusResponses, GetLastDeploymentData, GetLastDeploymentErrors, GetLastDeploymentResponse, GetLastDeploymentResponses, GetLatestScanData, GetLatestScanError, GetLatestScanErrors, GetLatestScanResponse, GetLatestScanResponses, GetLatestScansPerEnvironmentData, GetLatestScansPerEnvironmentError, GetLatestScansPerEnvironmentErrors, GetLatestScansPerEnvironmentResponse, GetLatestScansPerEnvironmentResponses, GetLiveVisitorsListData, GetLiveVisitorsListErrors, GetLiveVisitorsListResponse, GetLiveVisitorsListResponses, GetLogContextData, GetLogContextError, GetLogContextErrors, GetLogContextResponse, GetLogContextResponses, GetMcpData, GetMcpErrors, GetMcpResponse, GetMcpResponses, GetMetricsOverTimeData, GetMetricsOverTimeError, GetMetricsOverTimeErrors, GetMetricsOverTimeResponse, GetMetricsOverTimeResponses, GetMonitorData, GetMonitorErrors, GetMonitorResponse, GetMonitorResponses, GetNotificationProviderData, GetNotificationProviderErrors, GetNotificationProviderResponse, GetNotificationProviderResponses, GetOnDemandCertStatusData, GetOnDemandCertStatusErrors, GetOnDemandCertStatusResponse, GetOnDemandCertStatusResponses, GetOrCreateDsnData, GetOrCreateDsnErrors, GetOrCreateDsnRequest, GetOrCreateDsnResponse, GetOrCreateDsnResponses, GetPageFlowData, GetPageFlowErrors, GetPageFlowResponse, GetPageFlowResponses, GetPageHourlySessionsData, GetPageHourlySessionsErrors, GetPageHourlySessionsResponse, GetPageHourlySessionsResponses, GetPagePathDetailData, GetPagePathDetailErrors, GetPagePathDetailResponse, GetPagePathDetailResponses, GetPagePathsData, GetPagePathsErrors, GetPagePathsResponse, GetPagePathsResponses, GetPagePathsSparklinesData, GetPagePathsSparklinesErrors, GetPagePathsSparklinesResponse, GetPagePathsSparklinesResponses, GetPagePathVisitorsData, GetPagePathVisitorsErrors, GetPagePathVisitorsResponse, GetPagePathVisitorsResponses, GetPendingActionData, GetPendingActionErrors, GetPendingActionResponse, GetPendingActionResponses, GetPerformanceMetricsData, GetPerformanceMetricsError, GetPerformanceMetricsErrors, GetPerformanceMetricsResponse, GetPerformanceMetricsResponses, GetPgUpgradeData, GetPgUpgradeErrors, GetPgUpgradeLogsData, GetPgUpgradeLogsErrors, GetPgUpgradeLogsResponse, GetPgUpgradeLogsResponses, GetPgUpgradeResponse, GetPgUpgradeResponses, GetPipelineStatsData, GetPipelineStatsError, GetPipelineStatsErrors, GetPipelineStatsResponse, GetPipelineStatsResponses, GetPlatformInfoData, GetPlatformInfoErrors, GetPlatformInfoResponse, GetPlatformInfoResponses, GetPostgresWalHealthData, GetPostgresWalHealthErrors, GetPostgresWalHealthResponse, GetPostgresWalHealthResponses, GetPreferencesData, GetPreferencesErrors, GetPreferencesResponse, GetPreferencesResponses, GetPreviewGatewayLogsData, GetPreviewGatewayLogsResponse, GetPreviewGatewayLogsResponses, GetPreviewGatewaySettingsData, GetPreviewGatewaySettingsResponse, GetPreviewGatewaySettingsResponses, GetPreviewGatewayStatusData, GetPreviewGatewayStatusResponse, GetPreviewGatewayStatusResponses, GetPricingData, GetPricingError, GetPricingErrors, GetPricingResponse, GetPricingResponses, GetPrivateIpData, GetPrivateIpErrors, GetPrivateIpResponses, GetProjectAlarmsSummaryData, GetProjectAlarmsSummaryErrors, GetProjectAlarmsSummaryResponse, GetProjectAlarmsSummaryResponses, GetProjectBySlugData, GetProjectBySlugErrors, GetProjectBySlugResponse, GetProjectBySlugResponses, GetProjectData, GetProjectDeploymentsData, GetProjectDeploymentsErrors, GetProjectDeploymentsResponse, GetProjectDeploymentsResponses, GetProjectErrors, GetProjectResponse, GetProjectResponses, GetProjectsData, GetProjectSecretsQuery, GetProjectsErrors, GetProjectServiceEnvironmentVariablesData, GetProjectServiceEnvironmentVariablesErrors, GetProjectServiceEnvironmentVariablesResponse, GetProjectServiceEnvironmentVariablesResponses, GetProjectSessionReplaysData, GetProjectSessionReplaysError, GetProjectSessionReplaysErrors, GetProjectSessionReplaysQuery, GetProjectSessionReplaysResponse, GetProjectSessionReplaysResponse2, GetProjectSessionReplaysResponses, GetProjectsHealthData, GetProjectsHealthError, GetProjectsHealthErrors, GetProjectsHealthResponse, GetProjectsHealthResponses, GetProjectsMonitorHealthData, GetProjectsMonitorHealthErrors, GetProjectsMonitorHealthResponse, GetProjectsMonitorHealthResponses, GetProjectsResponse, GetProjectsResponses, GetProjectStatisticsData, GetProjectStatisticsErrors, GetProjectStatisticsResponse, GetProjectStatisticsResponses, GetProjectTemplateData, GetProjectTemplateErrors, GetProjectTemplateResponse, GetProjectTemplateResponses, GetPropertyBreakdownData, GetPropertyBreakdownErrors, GetPropertyBreakdownResponse, GetPropertyBreakdownResponses, GetPropertyTimelineData, GetPropertyTimelineErrors, GetPropertyTimelineResponse, GetPropertyTimelineResponses, GetProviderConnectionsData, GetProviderConnectionsErrors, GetProviderConnectionsResponse, GetProviderConnectionsResponses, GetProviderMetadataData, GetProviderMetadataErrors, GetProviderMetadataResponse, GetProviderMetadataResponses, GetProvidersMetadataData, GetProvidersMetadataErrors, GetProvidersMetadataResponse, GetProvidersMetadataResponses, GetProxyLogByIdData, GetProxyLogByIdError, GetProxyLogByIdErrors, GetProxyLogByIdResponse, GetProxyLogByIdResponses, GetProxyLogByRequestIdData, GetProxyLogByRequestIdError, GetProxyLogByRequestIdErrors, GetProxyLogByRequestIdResponse, GetProxyLogByRequestIdResponses, GetProxyLogsData, GetProxyLogsError, GetProxyLogsErrors, GetProxyLogsResponse, GetProxyLogsResponses, GetPublicBranchesData, GetPublicBranchesErrors, GetPublicBranchesResponse, GetPublicBranchesResponses, GetPublicIpData, GetPublicIpErrors, GetPublicIpResponses, GetPublicRepositoryData, GetPublicRepositoryErrors, GetPublicRepositoryResponse, GetPublicRepositoryResponses, GetQuotaData, GetQuotaError, GetQuotaErrors, GetQuotaResponse, GetQuotaResponses, GetRecentActivityData, GetRecentActivityErrors, GetRecentActivityResponse, GetRecentActivityResponses, GetRemoteExternalImageData, GetRemoteExternalImageErrors, GetRemoteExternalImageResponse, GetRemoteExternalImageResponses, GetRepositoryBranchesData, GetRepositoryBranchesErrors, GetRepositoryBranchesResponse, GetRepositoryBranchesResponses, GetRepositoryByIdData, GetRepositoryByIdErrors, GetRepositoryByIdResponse, GetRepositoryByIdResponses, GetRepositoryByNameData, GetRepositoryByNameErrors, GetRepositoryByNameResponse, GetRepositoryByNameResponses, GetRepositoryPresetByNameData, GetRepositoryPresetByNameErrors, GetRepositoryPresetByNameResponse, GetRepositoryPresetByNameResponses, GetRepositoryPresetLiveData, GetRepositoryPresetLiveErrors, GetRepositoryPresetLiveResponse, GetRepositoryPresetLiveResponses, GetRepositoryTagsData, GetRepositoryTagsErrors, GetRepositoryTagsResponse, GetRepositoryTagsResponses, GetRequest, GetResolvedEnvironmentVariablesData, GetResolvedEnvironmentVariablesErrors, GetResolvedEnvironmentVariablesResponse, GetResolvedEnvironmentVariablesResponses, GetResolvedEnvironmentVariableValueData, GetResolvedEnvironmentVariableValueErrors, GetResolvedEnvironmentVariableValueResponse, GetResolvedEnvironmentVariableValueResponses, GetResponse, GetRestoreCapabilitiesData, GetRestoreCapabilitiesError, GetRestoreCapabilitiesErrors, GetRestoreCapabilitiesResponse, GetRestoreCapabilitiesResponses, GetRestoreRunData, GetRestoreRunError, GetRestoreRunErrors, GetRestoreRunResponse, GetRestoreRunResponses, GetRouteData, GetRouteErrors, GetRouteResponse, GetRouteResponses, GetRunData, GetRunErrors, GetRunResponse, GetRunResponses, GetRunWithLogsData, GetRunWithLogsErrors, GetRunWithLogsResponse, GetRunWithLogsResponses, GetS3CredentialsData, GetS3CredentialsErrors, GetS3CredentialsResponse, GetS3CredentialsResponses, GetS3SourceData, GetS3SourceError, GetS3SourceErrors, GetS3SourceResponse, GetS3SourceResponses, GetSandboxData, GetSandboxErrors, GetSandboxResponse, GetSandboxResponses, GetSandboxStatusData, GetSandboxStatusErrors, GetSandboxStatusResponse, GetSandboxStatusResponses, GetScanByDeploymentData, GetScanByDeploymentError, GetScanByDeploymentErrors, GetScanByDeploymentResponse, GetScanByDeploymentResponses, GetScanData, GetScanError, GetScanErrors, GetScanResponse, GetScanResponses, GetScanVulnerabilitiesData, GetScanVulnerabilitiesError, GetScanVulnerabilitiesErrors, GetScanVulnerabilitiesResponse, GetScanVulnerabilitiesResponses, GetServiceBySlugData, GetServiceBySlugErrors, GetServiceBySlugResponse, GetServiceBySlugResponses, GetServiceData, GetServiceEnvironmentVariableData, GetServiceEnvironmentVariableErrors, GetServiceEnvironmentVariableResponse, GetServiceEnvironmentVariableResponses, GetServiceEnvironmentVariablesData, GetServiceEnvironmentVariablesErrors, GetServiceEnvironmentVariablesResponse, GetServiceEnvironmentVariablesResponses, GetServiceErrors, GetServiceHealthStatusData, GetServiceHealthStatusErrors, GetServiceHealthStatusResponse, GetServiceHealthStatusResponses, GetServicePreviewEnvironmentVariableNamesData, GetServicePreviewEnvironmentVariableNamesErrors, GetServicePreviewEnvironmentVariableNamesResponse, GetServicePreviewEnvironmentVariableNamesResponses, GetServicePreviewEnvironmentVariablesMaskedData, GetServicePreviewEnvironmentVariablesMaskedErrors, GetServicePreviewEnvironmentVariablesMaskedResponse, GetServicePreviewEnvironmentVariablesMaskedResponses, GetServiceResponse, GetServiceResponses, GetServiceRuntimeData, GetServiceRuntimeErrors, GetServiceRuntimeResponse, GetServiceRuntimeResponses, GetServiceStatsData, GetServiceStatsErrors, GetServiceStatsResponse, GetServiceStatsResponses, GetServiceTypeParametersData, GetServiceTypeParametersErrors, GetServiceTypeParametersResponses, GetServiceTypesData, GetServiceTypesErrors, GetServiceTypesResponse, GetServiceTypesResponses, GetSessionDetailsData, GetSessionDetailsErrors, GetSessionDetailsResponse, GetSessionDetailsResponses, GetSessionEventsData, GetSessionEventsErrors, GetSessionEventsResponse, GetSessionEventsResponses, GetSessionLogsData, GetSessionLogsErrors, GetSessionLogsResponse, GetSessionLogsResponses, GetSessionReplayData, GetSessionReplayError, GetSessionReplayErrors, GetSessionReplayEventsData, GetSessionReplayEventsError, GetSessionReplayEventsErrors, GetSessionReplayEventsResponse, GetSessionReplayEventsResponses, GetSessionReplayResponse, GetSessionReplayResponse2, GetSessionReplayResponses, GetSettingsData, GetSettingsErrors, GetSettingsResponse, GetSettingsResponses, GetSkillData, GetSkillErrors, GetSkillResponse, GetSkillResponses, GetSlowQueriesData, GetSlowQueriesErrors, GetSlowQueriesResponse, GetSlowQueriesResponses, GetStaticBundleData, GetStaticBundleErrors, GetStaticBundleResponse, GetStaticBundleResponses, GetStatusOverviewData, GetStatusOverviewErrors, GetStatusOverviewResponse, GetStatusOverviewResponses, GetTagsByRepositoryIdData, GetTagsByRepositoryIdErrors, GetTagsByRepositoryIdResponse, GetTagsByRepositoryIdResponses, GetTeamData, GetTeamErrors, GetTeamResponse, GetTeamResponses, GetTimeBucketStatsData, GetTimeBucketStatsError, GetTimeBucketStatsErrors, GetTimeBucketStatsResponse, GetTimeBucketStatsResponses, GetTodayStatsData, GetTodayStatsError, GetTodayStatsErrors, GetTodayStatsResponse, GetTodayStatsResponses, GetTraceData, GetTraceError, GetTraceErrors, GetTraceResponse, GetTraceResponses, GetUnifiedTraceData, GetUnifiedTraceError, GetUnifiedTraceErrors, GetUnifiedTraceResponse, GetUnifiedTraceResponses, GetUniqueCountsData, GetUniqueCountsErrors, GetUniqueCountsResponse, GetUniqueCountsResponses, GetUniqueEventsData, GetUniqueEventsErrors, GetUniqueEventsQuery, GetUniqueEventsResponse, GetUniqueEventsResponses, GetUpdateStatusData, GetUpdateStatusErrors, GetUpdateStatusResponse, GetUpdateStatusResponses, GetUptimeHistoryData, GetUptimeHistoryErrors, GetUptimeHistoryResponse, GetUptimeHistoryResponses, GetUsageByProviderData, GetUsageByProviderError, GetUsageByProviderErrors, GetUsageByProviderResponse, GetUsageByProviderResponses, GetUsageRecentData, GetUsageRecentError, GetUsageRecentErrors, GetUsageRecentResponse, GetUsageRecentResponses, GetUsageSummaryData, GetUsageSummaryError, GetUsageSummaryErrors, GetUsageSummaryResponse, GetUsageSummaryResponses, GetUsageTimeseriesData, GetUsageTimeseriesError, GetUsageTimeseriesErrors, GetUsageTimeseriesResponse, GetUsageTimeseriesResponses, GetUsageTopModelsData, GetUsageTopModelsError, GetUsageTopModelsErrors, GetUsageTopModelsResponse, GetUsageTopModelsResponses, GetVisitorByGuidData, GetVisitorByGuidErrors, GetVisitorByGuidResponse, GetVisitorByGuidResponses, GetVisitorByIdData, GetVisitorByIdErrors, GetVisitorByIdResponse, GetVisitorByIdResponses, GetVisitorDetailsData, GetVisitorDetailsErrors, GetVisitorDetailsResponse, GetVisitorDetailsResponses, GetVisitorFacetsData, GetVisitorFacetsErrors, GetVisitorFacetsResponse, GetVisitorFacetsResponses, GetVisitorInfoData, GetVisitorInfoErrors, GetVisitorInfoResponse, GetVisitorInfoResponses, GetVisitorJourneyData, GetVisitorJourneyErrors, GetVisitorJourneyResponse, GetVisitorJourneyResponses, GetVisitorsData, GetVisitorsErrors, GetVisitorSessionsData, GetVisitorSessionsError, GetVisitorSessionsErrors, GetVisitorSessionsQuery, GetVisitorSessionsResponse, GetVisitorSessionsResponse2, GetVisitorSessionsResponses, GetVisitorsResponse, GetVisitorsResponses, GetVisitorStatsData, GetVisitorStatsErrors, GetVisitorStatsResponse, GetVisitorStatsResponses, GetWebhookData, GetWebhookErrors, GetWebhookResponse, GetWebhookResponses, GitPushEvent, GitRefResponse, GitSourcePlan, GlobalConversationResponse, GlobalEventStatsResponse, GlobalMrrResponse, GlobalRecentEventResponse, GlobalRevenueSummaryResponse, GrantProjectAccessData, GrantProjectAccessErrors, GrantProjectAccessResponse, GrantProjectAccessResponses, GroupedPageMetric, GroupedPageMetricsQuery, GroupedPageMetricsResponse, HandleGitProviderOauthCallbackData, HandleGitProviderOauthCallbackErrors, HasAnalyticsEventsData, HasAnalyticsEventsErrors, HasAnalyticsEventsResponse, HasAnalyticsEventsResponse2, HasAnalyticsEventsResponses, HasErrorGroupsData, HasErrorGroupsErrors, HasErrorGroupsResponse, HasErrorGroupsResponse2, HasErrorGroupsResponses, HasEventsQuery, HasEventsResponse, HasMetricsQuery, HasMetricsResponse, HasPerformanceMetricsData, HasPerformanceMetricsError, HasPerformanceMetricsErrors, HasPerformanceMetricsResponse, HasPerformanceMetricsResponses, HealthCheckConfiguration, HealthCheckEntryResponse, HealthResponse, HealthStatus, HealthSummary, HeartbeatApiRequest, HeartbeatResponse, HierarchyLevel, HistogramSummary, HostnameChange, HostnamePreviewResponse, HourlyPageSessions, HourlyVisitsQuery, HttpChallengeDebugResponse, ImportCredentials, ImportExecutionStatus, ImportExternalServiceData, ImportExternalServiceErrors, ImportExternalServiceRequest, ImportExternalServiceResponse, ImportExternalServiceResponses, ImportOutcomeResponse, ImportPlan, ImportRowErrorResponse, ImportSelector, ImportSource, ImportSourceCapabilities, ImportSourceInfo, ImportStatusResponse, IncidentBucket, IncidentBucketedResponse, IncidentResponse, IncidentUpdateResponse, IncrRequest, IncrResponse, IngestLogsByPathData, IngestLogsByPathError, IngestLogsByPathErrors, IngestLogsByPathResponses, IngestLogsData, IngestLogsError, IngestLogsErrors, IngestLogsResponses, IngestMetricsByPathData, IngestMetricsByPathError, IngestMetricsByPathErrors, IngestMetricsByPathResponses, IngestMetricsData, IngestMetricsError, IngestMetricsErrors, IngestMetricsResponses, IngestSentryEnvelopeData, IngestSentryEnvelopeErrors, IngestSentryEnvelopeResponses, IngestSentryEventData, IngestSentryEventErrors, IngestSentryEventResponse, IngestSentryEventResponses, IngestTracesByPathData, IngestTracesByPathError, IngestTracesByPathErrors, IngestTracesByPathResponses, IngestTracesData, IngestTracesError, IngestTracesErrors, IngestTracesResponses, InitAuthResponse, InitSessionReplayData, InitSessionReplayError, InitSessionReplayErrors, InitSessionReplayResponse, InitSessionReplayResponses, Insight, InsightSeverity, InsightsResponse, InsightStatus, InspectDropArchiveData, InspectDropArchiveErrors, InspectDropArchiveResponse, InspectDropArchiveResponses, IntegrationResponse, IpAccessControlQuery, IpAccessControlResponse, JobLogsData, JobLogsErrors, JobLogsResponses, JobStatusData, JobStatusErrors, JobStatusResponse, JobStatusResponse2, JobStatusResponses, JobSummaryResponse, JoinTokenStatusResponse, JourneyEvent, JourneySession, KeysRequest, KeysResponse, KillJobBody, KillJobData, KillJobErrors, KillJobResponse, KillJobResponses, KnownAiAgentsResponse, KvDelData, KvDelErrors, KvDelResponse, KvDelResponses, KvDisableData, KvDisableErrors, KvDisableResponse, KvDisableResponses, KvEnableData, KvEnableErrors, KvEnableResponse, KvEnableResponses, KvExpireData, KvExpireErrors, KvExpireResponse, KvExpireResponses, KvGetData, KvGetErrors, KvGetResponse, KvGetResponses, KvIncrData, KvIncrErrors, KvIncrResponse, KvIncrResponses, KvKeysData, KvKeysErrors, KvKeysResponse, KvKeysResponses, KvSetData, KvSetErrors, KvSetResponse, KvSetResponses, KvStatusData, KvStatusErrors, KvStatusResponse, KvStatusResponse2, KvStatusResponses, KvTtlData, KvTtlErrors, KvTtlResponse, KvTtlResponses, KvUpdateData, KvUpdateErrors, KvUpdateResponse, KvUpdateResponses, LatestRunForSourceData, LatestRunForSourceErrors, LatestRunForSourceResponse, LatestRunForSourceResponses, LemonSqueezyConfig, LetsEncryptSettings, LineContext, LinkCustomDomainToCertificateData, LinkCustomDomainToCertificateErrors, LinkCustomDomainToCertificateResponse, LinkCustomDomainToCertificateResponses, LinkServiceRequest, LinkServiceToProjectData, LinkServiceToProjectErrors, LinkServiceToProjectResponse, LinkServiceToProjectResponses, ListAgentRunsData, ListAgentRunsErrors, ListAgentRunsResponse, ListAgentRunsResponses, ListAgentsData, ListAgentsErrors, ListAgentsResponse, ListAgentsResponse2, ListAgentsResponses, ListAiProvidersData, ListAiProvidersErrors, ListAiProvidersResponse, ListAiProvidersResponses, ListAlertRulesData, ListAlertRulesErrors, ListAlertRulesResponse, ListAlertRulesResponses, ListAlertsData, ListAlertsError, ListAlertsErrors, ListAlertsResponse, ListAlertsResponses, ListAllConversationsData, ListAllConversationsErrors, ListAllConversationsResponse, ListAllConversationsResponses, ListAllRunsData, ListAllRunsErrors, ListAllRunsResponse, ListAllRunsResponses, ListApiKeysData, ListApiKeysErrors, ListApiKeysQuery, ListApiKeysResponse, ListApiKeysResponses, ListAuditLogsData, ListAuditLogsErrors, ListAuditLogsQuery, ListAuditLogsResponse, ListAuditLogsResponses, ListAvailableContainersData, ListAvailableContainersErrors, ListAvailableContainersResponse, ListAvailableContainersResponses, ListBackupAlertsData, ListBackupAlertsError, ListBackupAlertsErrors, ListBackupAlertsResponse, ListBackupAlertsResponses, ListBackupChildrenData, ListBackupChildrenError, ListBackupChildrenErrors, ListBackupChildrenResponse, ListBackupChildrenResponses, ListBackupSchedulesData, ListBackupSchedulesError, ListBackupSchedulesErrors, ListBackupSchedulesResponse, ListBackupSchedulesResponses, ListBackupsForScheduleData, ListBackupsForScheduleErrors, ListBackupsForScheduleResponse, ListBackupsForScheduleResponses, ListBlobsQuery, ListBlobsResponse, ListCommitsByRepositoryIdData, ListCommitsByRepositoryIdErrors, ListCommitsByRepositoryIdResponse, ListCommitsByRepositoryIdResponses, ListConnectionsData, ListConnectionsErrors, ListConnectionsResponse, ListConnectionsResponses, ListContainersAtPathData, ListContainersAtPathErrors, ListContainersAtPathResponse, ListContainersAtPathResponses, ListContainersData, ListContainersErrors, ListContainersResponse, ListContainersResponses, ListConversationsData, ListConversationsErrors, ListConversationsResponse, ListConversationsResponses, ListCustomDomainsForProjectData, ListCustomDomainsForProjectErrors, ListCustomDomainsForProjectResponse, ListCustomDomainsForProjectResponses, ListCustomDomainsResponse, ListDashboardsData, ListDashboardsError, ListDashboardsErrors, ListDashboardsResponse, ListDashboardsResponses, ListDeliveriesData, ListDeliveriesErrors, ListDeliveriesResponse, ListDeliveriesResponses, ListDeploymentContainerLogsData, ListDeploymentContainerLogsErrors, ListDeploymentContainerLogsResponse, ListDeploymentContainerLogsResponses, ListDeploymentTokensData, ListDeploymentTokensErrors, ListDeploymentTokensQuery, ListDeploymentTokensResponse, ListDeploymentTokensResponses, ListDnsProvidersData, ListDnsProvidersErrors, ListDnsProvidersResponse, ListDnsProvidersResponses, ListDomainsData, ListDomainsErrors, ListDomainsResponse, ListDomainsResponse2, ListDomainsResponses, ListDsnsData, ListDsnsErrors, ListDsnsResponse, ListDsnsResponses, ListEmailDomainsData, ListEmailDomainsErrors, ListEmailDomainsResponse, ListEmailDomainsResponses, ListEmailProvidersData, ListEmailProvidersErrors, ListEmailProvidersResponse, ListEmailProvidersResponses, ListEmailsData, ListEmailsErrors, ListEmailsResponse, ListEmailsResponses, ListEnrollmentTokensData, ListEnrollmentTokensErrors, ListEnrollmentTokensResponse, ListEnrollmentTokensResponses, ListEntitiesData, ListEntitiesErrors, ListEntitiesQuery, ListEntitiesResponse, ListEntitiesResponses, ListErrorEventsData, ListErrorEventsErrors, ListErrorEventsQuery, ListErrorEventsResponse, ListErrorEventsResponses, ListErrorGroupsData, ListErrorGroupsErrors, ListErrorGroupsQuery, ListErrorGroupsResponse, ListErrorGroupsResponses, ListEventsData, ListEventsResponse, ListEventsResponses, ListEventTypesData, ListEventTypesResponse, ListEventTypesResponses, ListExternalImagesData, ListExternalImagesErrors, ListExternalImagesResponse, ListExternalImagesResponses, ListExternalPluginsData, ListExternalPluginsErrors, ListExternalPluginsResponse, ListExternalPluginsResponses, ListExternalServiceBackupsData, ListExternalServiceBackupsError, ListExternalServiceBackupsErrors, ListExternalServiceBackupsResponse, ListExternalServiceBackupsResponses, ListFlagsData, ListFlagsErrors, ListFlagsResponse, ListFlagsResponses, ListFunnelsData, ListFunnelsErrors, ListFunnelsResponse, ListFunnelsResponses, ListGitProvidersData, ListGitProvidersErrors, ListGitProvidersResponse, ListGitProvidersResponses, ListGlobalMcpsData, ListGlobalMcpsErrors, ListGlobalMcpsResponse, ListGlobalMcpsResponses, ListGlobalSkillsData, ListGlobalSkillsErrors, ListGlobalSkillsResponse, ListGlobalSkillsResponses, ListIncidentsData, ListIncidentsErrors, ListIncidentsResponses, ListInsightsData, ListInsightsError, ListInsightsErrors, ListInsightsResponse, ListInsightsResponses, ListIpAccessControlData, ListIpAccessControlError, ListIpAccessControlErrors, ListIpAccessControlResponse, ListIpAccessControlResponses, ListJobsData, ListJobsErrors, ListJobsResponse, ListJobsResponse2, ListJobsResponses, ListKnownAiAgentsData, ListKnownAiAgentsError, ListKnownAiAgentsErrors, ListKnownAiAgentsResponse, ListKnownAiAgentsResponses, ListManagedDomainsData, ListManagedDomainsErrors, ListManagedDomainsResponse, ListManagedDomainsResponses, ListMcpsData, ListMcpsErrors, ListMcpsResponse, ListMcpsResponse2, ListMcpsResponses, ListMetricLabelKeysData, ListMetricLabelKeysError, ListMetricLabelKeysErrors, ListMetricLabelKeysResponse, ListMetricLabelKeysResponses, ListMetricLabelValuesData, ListMetricLabelValuesError, ListMetricLabelValuesErrors, ListMetricLabelValuesResponse, ListMetricLabelValuesResponses, ListMetricNamesData, ListMetricNamesError, ListMetricNamesErrors, ListMetricNamesResponse, ListMetricNamesResponses, ListModelsData, ListModelsError, ListModelsErrors, ListModelsResponse, ListModelsResponses, ListMonitorsData, ListMonitorsErrors, ListMonitorsResponse, ListMonitorsResponses, ListNotificationProvidersData, ListNotificationProvidersErrors, ListNotificationProvidersResponse, ListNotificationProvidersResponses, ListOidcProvidersData, ListOidcProvidersResponse, ListOidcProvidersResponses, ListOidcProviderUsersData, ListOidcProviderUsersErrors, ListOidcProviderUsersResponse, ListOidcProviderUsersResponses, ListOidcRoleMappingsData, ListOidcRoleMappingsResponse, ListOidcRoleMappingsResponses, ListOnDemandCertsData, ListOnDemandCertsErrors, ListOnDemandCertsResponse, ListOnDemandCertsResponse2, ListOnDemandCertsResponses, ListOrdersData, ListOrdersErrors, ListOrdersResponse, ListOrdersResponse2, ListOrdersResponses, ListPeersData, ListPeersErrors, ListPeersResponse, ListPeersResponses, ListPendingActionsData, ListPendingActionsErrors, ListPendingActionsResponse, ListPendingActionsResponses, ListPgUpgradesData, ListPgUpgradesErrors, ListPgUpgradesResponse, ListPgUpgradesResponses, ListPresetsData, ListPresetsErrors, ListPresetsResponse, ListPresetsResponse2, ListPresetsResponses, ListProjectAccessData, ListProjectAccessErrors, ListProjectAccessResponse, ListProjectAccessResponses, ListProjectAlarmsData, ListProjectAlarmsErrors, ListProjectAlarmsResponse, ListProjectAlarmsResponses, ListProjectScansData, ListProjectScansError, ListProjectScansErrors, ListProjectScansResponse, ListProjectScansResponses, ListProjectSecretsData, ListProjectSecretsErrors, ListProjectSecretsResponse, ListProjectSecretsResponses, ListProjectServicesData, ListProjectServicesErrors, ListProjectServicesResponse, ListProjectServicesResponses, ListProjectTemplatesData, ListProjectTemplatesErrors, ListProjectTemplatesResponse, ListProjectTemplatesResponses, ListProjectTemplateTagsData, ListProjectTemplateTagsErrors, ListProjectTemplateTagsResponse, ListProjectTemplateTagsResponses, ListProviderKeysData, ListProviderKeysError, ListProviderKeysErrors, ListProviderKeysResponse, ListProviderKeysResponses, ListProviderZonesData, ListProviderZonesErrors, ListProviderZonesResponse, ListProviderZonesResponses, ListPublicProvidersData, ListPublicProvidersResponse, ListPublicProvidersResponses, ListReleaseFilesData, ListReleaseFilesErrors, ListReleaseFilesResponse, ListReleaseFilesResponses, ListReleasesData, ListReleasesErrors, ListReleasesResponse, ListReleasesResponses, ListRemoteExternalImagesData, ListRemoteExternalImagesErrors, ListRemoteExternalImagesResponse, ListRemoteExternalImagesResponses, ListRepositoriesByConnectionData, ListRepositoriesByConnectionErrors, ListRepositoriesByConnectionResponse, ListRepositoriesByConnectionResponses, ListRepositoriesByProviderData, ListRepositoriesByProviderErrors, ListRepositoriesByProviderResponse, ListRepositoriesByProviderResponses, ListRestoreRunsForServiceData, ListRestoreRunsForServiceResponse, ListRestoreRunsForServiceResponses, ListRootContainersData, ListRootContainersErrors, ListRootContainersResponse, ListRootContainersResponses, ListRoutesData, ListRoutesErrors, ListRoutesResponse, ListRoutesResponses, ListRunsResponse, ListS3SourcesData, ListS3SourcesError, ListS3SourcesErrors, ListS3SourcesResponse, ListS3SourcesResponses, ListSandboxesData, ListSandboxesResponse, ListSandboxesResponse2, ListSandboxesResponses, ListScansQuery, ListScheduleRunJobsData, ListScheduleRunJobsError, ListScheduleRunJobsErrors, ListScheduleRunJobsResponse, ListScheduleRunJobsResponses, ListScheduleRunsData, ListScheduleRunsError, ListScheduleRunsErrors, ListScheduleRunsResponse, ListScheduleRunsResponses, ListScheduleServicesData, ListScheduleServicesError, ListScheduleServicesErrors, ListScheduleServicesResponse, ListScheduleServicesResponses, ListSecretsData, ListSecretsErrors, ListSecretsResponse, ListSecretsResponse2, ListSecretsResponses, ListServiceHealthStatusesData, ListServiceHealthStatusesErrors, ListServiceHealthStatusesResponse, ListServiceHealthStatusesResponses, ListServiceProjectsData, ListServiceProjectsErrors, ListServiceProjectsResponse, ListServiceProjectsResponses, ListServiceSchedulesData, ListServiceSchedulesError, ListServiceSchedulesErrors, ListServiceSchedulesResponse, ListServiceSchedulesResponses, ListServicesData, ListServicesErrors, ListServicesResponse, ListServicesResponses, ListSkillsData, ListSkillsErrors, ListSkillsResponse, ListSkillsResponse2, ListSkillsResponses, ListSourceBackupsData, ListSourceBackupsError, ListSourceBackupsErrors, ListSourceBackupsResponse, ListSourceBackupsResponses, ListSourceFilesData, ListSourceFilesErrors, ListSourceFilesResponse, ListSourceFilesResponses, ListSourceMapsData, ListSourceMapsErrors, ListSourceMapsResponse, ListSourceMapsResponses, ListSourcesData, ListSourcesErrors, ListSourcesResponse, ListSourcesResponses, ListStaticBundlesData, ListStaticBundlesErrors, ListStaticBundlesResponse, ListStaticBundlesResponses, ListSyncedRepositoriesData, ListSyncedRepositoriesErrors, ListSyncedRepositoriesResponse, ListSyncedRepositoriesResponses, ListTagsResponse, ListTeamMembersData, ListTeamMembersErrors, ListTeamMembersResponse, ListTeamMembersResponses, ListTeamProjectsData, ListTeamProjectsErrors, ListTeamProjectsResponse, ListTeamProjectsResponses, ListTeamsData, ListTeamsErrors, ListTeamsResponse, ListTeamsResponses, ListTemplatesQuery, ListTemplatesResponse, ListUsersData, ListUsersErrors, ListUsersResponse, ListUsersResponses, ListVulnerabilitiesQuery, ListWebhooksData, ListWebhooksErrors, ListWebhooksResponse, ListWebhooksResponses, LiveVisitorInfo, LiveVisitorsListResponse, LocationCount, LocationGranularity, LocationInfo, LoginData, LoginErrors, LoginRequest, LoginResponse, LoginResponses, LogLevel, LogoutData, LogoutErrors, LogoutResponses, LogRecord, LogSearchLine, LogSeverity, LogSource, LogsQuery, LogsResponse, LogStream, LookupDnsARecordsData, LookupDnsARecordsError, LookupDnsARecordsErrors, LookupDnsARecordsResponse, LookupDnsARecordsResponses, ManagedDomainResponse, ManualAction, ManualActionTiming, McpDefinitionResponse, MessageContent, MessagePart, MessageResponse, MeteredMode, MetricAggregation, MetricBucket, MetricDataPoint, MetricsOverTimeResponse, MetricsQuery, MetricsRangeQuery, MetricsStatusResponse, MetricsStoreKind, MetricsSummaryResponse, MetricType, MfaRequiredResponse, MfaSetupResponse, MfaVerificationRequest, MigrationStep, MigrationSummary, MintEnrollmentTokenData, MintEnrollmentTokenErrors, MintEnrollmentTokenRequest, MintEnrollmentTokenResponse, MintEnrollmentTokenResponse2, MintEnrollmentTokenResponses, MiscResult, MkdirBody, MkdirData, MkdirErrors, MkdirResponse, MkdirResponses, ModelInfo, ModelListResponse, ModelPricing, ModelUsage, MonitoringSettings, MonitoringSettingsMasked, MonitorResponse, MonitorStatus, MrrBucketResponse, MultiNodeSettings, MultiNodeSettingsMasked, MxResult, NavEntry, NavSection, NetworkConfiguration, NetworkMode, NixpacksPresetConfig, NixpacksProvider, NodeContainerListResponse, NodeContainerResponse, NodeCostInfo, NodeHeartbeatData, NodeHeartbeatErrors, NodeHeartbeatResponse, NodeHeartbeatResponses, NodeInfoResponse, NodeListResponse, NodeMetricsGetRangeData, NodeMetricsGetRangeErrors, NodeMetricsGetRangeResponse, NodeMetricsGetRangeResponses, NotificationPreferencesResponse, NotificationProviderResponse, ObservabilityCompressionSettings, ObservabilityEvent, ObservabilityFullEventData, ObservabilityFullEventError, ObservabilityFullEventErrors, ObservabilityFullEventResponse, ObservabilityFullEventResponses, ObservabilityListEventsData, ObservabilityListEventsError, ObservabilityListEventsErrors, ObservabilityListEventsResponse, ObservabilityListEventsResponses, ObservabilityRetentionSettings, OidcCallbackData, OidcProviderResponse, OidcProvidersListResponse, OidcProviderSummary, OidcProviderUserResponse, OidcRoleMappingResponse, OidcTestConnectionResponse, OnDemandCertAttemptResponse, OnDemandCertRow, OnDemandTlsSettings, OpenAiError, OpenAiErrorResponse, OperatingSystemCount, OperationResultResponse, OperationResultsResponse, OtelDashboardResponse, OtelDashboardsResponse, OtelMetricAlertRuleResponse, OtelMetricAlertsResponse, OtelMetricLabelKeysResponse, OtelMetricLabelValuesResponse, OtelMetricNamesResponse, OtelMetricsResponse, OutlierAlgorithm, OutlierParams, OverprovisioningAssessment, OverprovisioningVerdict, PageActivityBucket, PageCountryStats, PageFlowEntry, PageFlowQuery, PageFlowResponse, PageHourlySessionsQuery, PageHourlySessionsResponse, PagePathDetailQuery, PagePathDetailResponse, PagePathInfo, PagePathSparkline, PagePathSparklinePoint, PagePathsQuery, PagePathsResponse, PagePathsSparklineQuery, PagePathsSparklineResponse, PagePathVisitorsQuery, PagePathVisitorsResponse, PageReferrerStats, PagesComparisonResponse, PageSessionComparison, PageSessionStats, PageSessionStatsQuery, PageTransition, PageVisit, PageVisitorSession, PaginatedEmailsResponse, PaginatedEntitiesResponse, PaginatedErrorEventsResponse, PaginatedErrorGroupsResponse, PaginatedEventsResponse, PaginatedExternalImagesResponse, PaginatedProjectList, PaginatedStaticBundlesResponse, Pagination, PaginationMeta, PaginationParams, PasswordProtectionConfig, PatchAdminGateData, PatchAdminGateErrors, PatchAdminGateResponse, PatchAdminGateResponses, PatchPreviewGatewaySettingsData, PatchPreviewGatewaySettingsResponse, PatchPreviewGatewaySettingsResponses, PatchSettingsRequest, PathVisitors, PathVisitorsAnalyticsQuery, PathVisitorsResponse, PauseDeploymentData, PauseDeploymentErrors, PauseDeploymentResponse, PauseDeploymentResponses, PauseSandboxData, PauseSandboxErrors, PauseSandboxResponse, PauseSandboxResponses, PeerEntry, PeerListResponse, PendingActionResponse, PerformanceMetricsQuery, PerformanceMetricsResponse, PermissionInfo, PgUpgradeLogResponse, PgUpgradeResponse, PipelineStats, PipelineStatsResponse, PlanComplexity, PlanMetadata, PlanRestoreData, PlanRestoreError, PlanRestoreErrors, PlanRestoreResponse, PlanRestoreResponses, PlanSourceBackup, PlanTarget, PlatformInfo, PluginManifest, PortMapping, PostDnsAckData, PostDnsAckErrors, PostDnsAckResponse, PostDnsAckResponses, PostgresWalHealth, PresetConfigSchema, PresetInfo, PresetResponse, PreviewAlertData, PreviewAlertError, PreviewAlertErrors, PreviewAlertResponse, PreviewAlertResponses, PreviewFunnelMetricsData, PreviewFunnelMetricsErrors, PreviewFunnelMetricsResponse, PreviewFunnelMetricsResponses, PreviewGatewaySettings, PreviewGatewaySettingsMasked, PreviewGatewaySettingsResponse, PreviewHostnameModeData, PreviewHostnameModeErrors, PreviewHostnameModeResponse, PreviewHostnameModeResponses, PreviewShareLinkBody, PreviewShareLinkResponse, PricingResponse, ProblemDetails, ProjectAccessResponse, ProjectConfiguration, ProjectDashboardAnalytics, ProjectDsnResponse, ProjectHealthSummary, ProjectInfo, ProjectMonitorHealth, ProjectPresetResponse, ProjectQuery, ProjectRef, ProjectResponse, ProjectSecretEnvironmentInfo, ProjectSecretResponse, ProjectServiceInfo, ProjectsHealthResponse, ProjectsMonitorHealthResponse, ProjectStatisticsResponse, ProjectStatsBreakdown, ProjectType, ProjectUsageInfoResponse, PromoteClusterMemberData, PromoteClusterMemberErrors, PromoteClusterMemberResponses, PromoteDeploymentData, PromoteDeploymentErrors, PromoteDeploymentRequest, PromoteDeploymentResponse, PromoteDeploymentResponses, PropertyBreakdownItem, PropertyBreakdownQuery, PropertyBreakdownResponse, PropertyColumn, PropertyTimelineItem, PropertyTimelineQuery, PropertyTimelineResponse, Protocol, ProviderCatalogDto, ProviderCatalogResponse, ProviderConfig, ProviderConfigMasked, ProviderDeletionCheckResponse, ProviderDescriptor, ProviderKeyResponse, ProviderMetadata, ProviderResponse, ProviderUsage, ProvisionDomainData, ProvisionDomainErrors, ProvisionDomainResponse, ProvisionDomainResponses, ProvisionResponse, ProxyLogResponse, ProxyLogsPaginatedResponse, PublicHostnameStrategy, PublicPresetResponse, PublicRepositoryInfo, PurgeLogsRequest, PurgeProjectLogsData, PurgeProjectLogsError, PurgeProjectLogsErrors, PurgeProjectLogsResponses, PushedExternalImageResponse, PushExternalImageData, PushExternalImageErrors, PushExternalImageResponse, PushExternalImageResponses, PushImageRequest, QueryDataData, QueryDataErrors, QueryDataRequest, QueryDataResponse, QueryDataResponse2, QueryDataResponses, QueryGenaiTracesData, QueryGenaiTracesError, QueryGenaiTracesErrors, QueryGenaiTracesResponse, QueryGenaiTracesResponses, QueryLogsData, QueryLogsError, QueryLogsErrors, QueryLogsResponse, QueryLogsResponses, QueryMetricsData, QueryMetricsError, QueryMetricsErrors, QueryMetricsResponse, QueryMetricsResponses, QueryTracesData, QueryTracesError, QueryTracesErrors, QueryTracesResponse, QueryTracesResponses, QueryTraceSummariesData, QueryTraceSummariesError, QueryTraceSummariesErrors, QueryTraceSummariesResponse, QueryTraceSummariesResponses, QuotaResponse, RateLimitConfig, RateLimitSettings, ReachabilityStatus, ReadFileData, ReadFileErrors, ReadFileResponse, ReadFileResponse2, ReadFileResponses, ReAnalyzeData, ReAnalyzeErrors, ReAnalyzeResponses, RecentActivityQuery, RecentActivityResponse, RecentEventResponse, RecentQueryParams, RecordConsoleEventData, RecordConsoleEventErrors, RecordConsoleEventResponses, RecordEventMetricsData, RecordEventMetricsErrors, RecordEventMetricsResponse, RecordEventMetricsResponses, RecordExposureRequest, RecordExposureResponse, RecordFlagExposureData, RecordFlagExposureErrors, RecordFlagExposureResponse, RecordFlagExposureResponses, RecordListResponse, RecordSpeedMetricsData, RecordSpeedMetricsError, RecordSpeedMetricsErrors, RecordSpeedMetricsResponse, RecordSpeedMetricsResponses, RecoveryTarget, ReferrerCount, ReferrersAnalyticsQuery, RefreshRouteTableData, RefreshRouteTableErrors, RefreshRouteTableResponse, RefreshRouteTableResponses, RegenerateDsnData, RegenerateDsnErrors, RegenerateDsnRequest, RegenerateDsnResponse, RegenerateDsnResponses, RegisterExternalImageData, RegisterExternalImageErrors, RegisterExternalImageResponse, RegisterExternalImageResponses, RegisterImageRequest, RegisterNodeApiRequest, RegisterNodeData, RegisterNodeErrors, RegisterNodeResponse, RegisterNodeResponse2, RegisterNodeResponses, RegisterRequest, ReinstallGitlabWebhookData, ReinstallGitlabWebhookErrors, ReinstallGitlabWebhookResponse, ReinstallGitlabWebhookResponses, ReinstallWebhookResponse, RejectPendingActionData, RejectPendingActionErrors, RejectPendingActionResponse, RejectPendingActionResponses, ReleaseListResponse, ReloadPluginsData, ReloadPluginsErrors, ReloadPluginsResponse, ReloadPluginsResponses, ReloadResponse, RemoteDeploymentResponse, RemoveClusterMemberData, RemoveClusterMemberErrors, RemoveClusterMemberResponse, RemoveClusterMemberResponses, RemoveManagedDomainData, RemoveManagedDomainErrors, RemoveManagedDomainResponse, RemoveManagedDomainResponses, RemoveNodeResponse, RemoveRoleData, RemoveRoleErrors, RemoveRoleResponse, RemoveRoleResponses, RemoveTeamMemberData, RemoveTeamMemberErrors, RemoveTeamMemberResponse, RemoveTeamMemberResponses, RenameConversationData, RenameConversationErrors, RenameConversationRequest, RenameConversationResponse, RenameConversationResponses, RenewDomainData, RenewDomainErrors, RenewDomainResponse, RenewDomainResponses, RepositoryListQuery, RepositoryListResponse, RepositoryPresetResponse, RepositoryResponse, RepositorySyncStartedResponse, RequestPasswordResetData, RequestPasswordResetErrors, RequestPasswordResetResponse, RequestPasswordResetResponses, RequestRow, ResetPasswordData, ResetPasswordErrors, ResetPasswordRequest, ResetPasswordResponse, ResetPasswordResponses, ResetPgStatStatementsRequest, ResetPgStatStatementsResponse, ResizeSandboxBody, ResizeSandboxData, ResizeSandboxErrors, ResizeSandboxResponse, ResizeSandboxResponses, ResolveAlarmData, ResolveAlarmErrors, ResolveAlarmResponses, ResolvedEnvVarResponse, ResolvedEnvVarSource, ResourceCounts, ResourceFootprint, ResourceInfo, ResourceLimitApplyResult, ResourceLimits, ResourceLimitsResponse, ResourceLimitsUpdateResponse, ResourcesBody, RestartContainerData, RestartContainerErrors, RestartContainerResponse, RestartContainerResponses, RestartPreviewGatewayData, RestartPreviewGatewayResponse, RestartPreviewGatewayResponses, RestartSandboxData, RestartSandboxErrors, RestartSandboxResponse, RestartSandboxResponses, RestoreCapabilities, RestoreCapabilitiesResponse, RestoreFlagData, RestoreFlagErrors, RestoreFlagResponse, RestoreFlagResponses, RestorePlan, RestoreRequestMode, RestoreRunView, RestoreUserData, RestoreUserErrors, RestoreUserResponse, RestoreUserResponses, ResumeDeploymentData, ResumeDeploymentErrors, ResumeDeploymentResponse, ResumeDeploymentResponses, ResumeSandboxData, ResumeSandboxErrors, ResumeSandboxResponse, ResumeSandboxResponses, RetentionCleanupFailure, RetentionCleanupReport, RetryClusterData, RetryClusterErrors, RetryClusterRequest, RetryClusterResponse, RetryClusterResponses, RetryDeliveryData, RetryDeliveryErrors, RetryDeliveryResponse, RetryDeliveryResponses, RetryPgUpgradeData, RetryPgUpgradeErrors, RetryPgUpgradeResponse, RetryPgUpgradeResponses, RetryRunData, RetryRunErrors, RetryRunResponse, RetryRunResponses, RevealGlobalMcpConfigData, RevealGlobalMcpConfigErrors, RevealGlobalMcpConfigResponse, RevealGlobalMcpConfigResponses, RevealMcpConfigData, RevealMcpConfigErrors, RevealMcpConfigResponse, RevealMcpConfigResponses, RevealNotificationProviderConfigData, RevealNotificationProviderConfigErrors, RevealNotificationProviderConfigResponse, RevealNotificationProviderConfigResponses, RevealServiceParameterData, RevealServiceParameterErrors, RevealServiceParameterResponse, RevealServiceParameterResponses, RevenueCreateIntegrationData, RevenueCreateIntegrationErrors, RevenueCreateIntegrationResponse, RevenueCreateIntegrationResponses, RevenueDeleteIntegrationData, RevenueDeleteIntegrationResponse, RevenueDeleteIntegrationResponses, RevenueGlobalEventsData, RevenueGlobalEventsResponse, RevenueGlobalEventsResponses, RevenueImportInvoicesCsvData, RevenueImportInvoicesCsvErrors, RevenueImportInvoicesCsvResponse, RevenueImportInvoicesCsvResponses, RevenueImportSubscriptionsCsvData, RevenueImportSubscriptionsCsvErrors, RevenueImportSubscriptionsCsvResponse, RevenueImportSubscriptionsCsvResponses, RevenueListIntegrationsData, RevenueListIntegrationsResponse, RevenueListIntegrationsResponses, RevenueListProvidersData, RevenueListProvidersResponse, RevenueListProvidersResponses, RevenueMetricsCustomersData, RevenueMetricsCustomersResponse, RevenueMetricsCustomersResponses, RevenueMetricsGlobalMrrData, RevenueMetricsGlobalMrrResponse, RevenueMetricsGlobalMrrResponses, RevenueMetricsGlobalSummaryData, RevenueMetricsGlobalSummaryResponse, RevenueMetricsGlobalSummaryResponses, RevenueMetricsMrrData, RevenueMetricsMrrResponse, RevenueMetricsMrrResponses, RevenueMetricsSummaryData, RevenueMetricsSummaryResponse, RevenueMetricsSummaryResponses, RevenueRecentEventsData, RevenueRecentEventsResponse, RevenueRecentEventsResponses, RevenueRotateTokenData, RevenueRotateTokenResponse, RevenueRotateTokenResponses, RevenueRow, RevenueUpdateConfigData, RevenueUpdateConfigErrors, RevenueUpdateConfigResponse, RevenueUpdateConfigResponses, RevenueUpdateSecretData, RevenueUpdateSecretErrors, RevenueUpdateSecretResponse, RevenueUpdateSecretResponses, RevokeDsnData, RevokeDsnErrors, RevokeDsnResponse, RevokeDsnResponses, RevokeEnrollmentTokenData, RevokeEnrollmentTokenErrors, RevokeEnrollmentTokenResponse, RevokeEnrollmentTokenResponses, RevokeJoinTokenData, RevokeJoinTokenErrors, RevokeJoinTokenResponse, RevokeJoinTokenResponses, RevokeProjectAccessData, RevokeProjectAccessErrors, RevokeProjectAccessResponse, RevokeProjectAccessResponses, RiskLevel, RoleInfo, RollbackPgUpgradeData, RollbackPgUpgradeErrors, RollbackPgUpgradeResponse, RollbackPgUpgradeResponses, RollbackToDeploymentData, RollbackToDeploymentErrors, RollbackToDeploymentResponse, RollbackToDeploymentResponses, RootfsCacheEntry, RootfsGcData, RootfsGcReport, RootfsGcResponses, RootfsReport, RootfsReportData, RootfsReportResponses, RootfsVmEntry, RotateApiKeyData, RotateApiKeyErrors, RotateApiKeyResponse, RotateApiKeyResponses, RotateDeploymentTokenData, RotateDeploymentTokenErrors, RotateDeploymentTokenResponse, RotateDeploymentTokenResponses, RouteRefreshResponse, RouteResponse, RouteRole, RouteUser, RouteUserWithRoles, RunBackupForSourceData, RunBackupForSourceError, RunBackupForSourceErrors, RunBackupForSourceResponse, RunBackupForSourceResponses, RunBackupRequest, RunConnectionHealthCheckData, RunConnectionHealthCheckErrors, RunConnectionHealthCheckResponse, RunConnectionHealthCheckResponses, RunExternalServiceBackupData, RunExternalServiceBackupError, RunExternalServiceBackupErrors, RunExternalServiceBackupRequest, RunExternalServiceBackupResponse, RunExternalServiceBackupResponses, RunScheduleNowData, RunScheduleNowError, RunScheduleNowErrors, RunScheduleNowResponse, RunScheduleNowResponses, S3ConnectionTestResponse, S3CredentialsResponse, S3SourceResponse, S3SourceResponseWritable, SandboxCreatePreviewLinkData, SandboxCreatePreviewLinkErrors, SandboxCreatePreviewLinkResponse, SandboxCreatePreviewLinkResponses, SandboxDomainResponse, SandboxEvent, SandboxEventsResponse, SandboxInner, SandboxResponse, SandboxRoute, SandboxStatusResponse, SaveAgentTokenData, SaveAgentTokenErrors, SaveAgentTokenRequest, SaveAgentTokenResponse, SaveAgentTokenResponse2, SaveAgentTokenResponses, SaveAiProviderCredentialData, SaveAiProviderCredentialErrors, SaveAiProviderCredentialResponse, SaveAiProviderCredentialResponses, SaveCredentialRequest, SaveCredentialResponse, ScalewayCredentialsRequest, ScanResponse, ScheduleRunEntry, ScheduleRunJobEntry, ScheduleRunListResponse, ScheduleRunResponse, ScheduleRunSummary, ScheduleRunSummaryList, ScreenshotSettings, SearchLogsData, SearchLogsError, SearchLogsErrors, SearchLogsRequest, SearchLogsResponse, SearchLogsResponse2, SearchLogsResponses, SearchMode, Seasonality, SecretResponse, SecurityConfig, SecurityHeadersConfig, SecurityHeadersSettings, SendEmailData, SendEmailErrors, SendEmailRequestBody, SendEmailResponse, SendEmailResponseBody, SendEmailResponses, SendMessageRequest, SensitiveConfigValueResponse, SensitiveMcpConfigValueResponse, SensitiveValueResponse, SentryChunkUploadResponse, SentryCreateReleaseRequest, SentryEventRequest, SentryEventResponse, SentryReleaseFileResponse, SentryReleaseProjectRef, SentryReleaseResponse, SeriesStateEntry, ServiceAccessInfo, ServiceAction, ServiceAlertRuleResponse, ServiceBackupEntryResponse, ServiceBackupListResponse, ServiceCreateAlertRuleRequest, ServiceHealthResponse, ServiceHealthStatusBatchResponse, ServiceHealthStatusEntryResponse, ServiceMemberInfo, ServiceParameter, ServicePlan, ServiceResourceLimits, ServiceRuntimeReport, ServiceStatsReport, ServiceTypeInfo, ServiceTypeRoute, ServiceUpdateAlertRuleRequest, SesCredentialsRequest, SessionDetails, SessionDetailsQuery, SessionEvent, SessionEventDto, SessionEventsQuery, SessionEventsResponse, SessionLogsQuery, SessionLogsResponse, SessionReplayEventsRequest, SessionReplayInfoDto, SessionReplayInitRequest, SessionReplayInitResponse, SessionReplayWithEventsDto, SessionReplayWithVisitorDto, SessionRequestLog, SessionSummary, SetDefaultS3SourceData, SetDefaultS3SourceError, SetDefaultS3SourceErrors, SetDefaultS3SourceResponse, SetDefaultS3SourceResponses, SetFlagEnvironmentData, SetFlagEnvironmentErrors, SetFlagEnvironmentRequest, SetFlagEnvironmentResponse, SetFlagEnvironmentResponses, SetPreviewPasswordBody, SetPreviewPasswordData, SetPreviewPasswordErrors, SetPreviewPasswordResponse, SetPreviewPasswordResponse2, SetPreviewPasswordResponses, SetRequest, SetResponse, SettingsUpdateResponse, SetupDnsChallengeData, SetupDnsChallengeErrors, SetupDnsChallengeRequest, SetupDnsChallengeResponse, SetupDnsChallengeResponse2, SetupDnsChallengeResponses, SetupDnsData, SetupDnsErrors, SetupDnsRequest, SetupDnsResponse, SetupDnsResponse2, SetupDnsResponses, SetupEmailTrackingData, SetupEmailTrackingErrors, SetupEmailTrackingResponse, SetupEmailTrackingResponses, SetupMfaData, SetupMfaErrors, SetupMfaResponse, SetupMfaResponses, SiblingRef, SkillDefinitionResponse, SlackConfig, SleepEnvironmentData, SleepEnvironmentErrors, SleepEnvironmentResponse, SleepEnvironmentResponses, SlowQueriesResponse, SlowQueryRow, SmartFilter, SmokeTestAgentData, SmokeTestAgentErrors, SmokeTestAgentResponse, SmokeTestAgentResponses, SmokeTestResponse, SmtpCredentialsRequest, SmtpEncryptionRoute, SmtpResult, SourceArchiveUpload, SourceBackupEntry, SourceBackupIndexResponse, SourceBody, SourceFileListResponse, SourceFileResponse, SourceMapListResponse, SourceMapResponse, SourceSandboxData, SourceSandboxErrors, SourceSandboxResponse, SourceSandboxResponses, SourceType, SpanEvent, SpanKind, SpanRecord, SpanRow, SpanStatusCode, SpeedMetricsPayload, SpeedSegmentFilters, StaleSlot, StartAnalysisData, StartAnalysisErrors, StartAnalysisRequest, StartAnalysisResponse, StartAnalysisResponses, StartContainerData, StartContainerErrors, StartContainerResponse, StartContainerResponses, StartFixData, StartFixErrors, StartFixResponses, StartGitProviderOauthData, StartGitProviderOauthErrors, StartOidcLoginBySlugData, StartOidcLoginBySlugErrors, StartPgUpgradeData, StartPgUpgradeErrors, StartPgUpgradeRequest, StartPgUpgradeResponse, StartPgUpgradeResponses, StartRestoreData, StartRestoreError, StartRestoreErrors, StartRestoreRequest, StartRestoreResponse, StartRestoreResponses, StartServiceData, StartServiceErrors, StartServiceResponse, StartServiceResponses, StaticBundleResponse, StaticParams, StaticPresetConfig, StatPathData, StatPathErrors, StatPathResponse, StatPathResponses, StatResponse, StatsFilters, StatusBucket, StatusBucketedResponse, StatusCodeCount, StatusCodesQuery, StatusPageOverview, StepConversionResponse, StepResourceType, StepResult, StepUpResponse, StopContainerData, StopContainerErrors, StopContainerResponse, StopContainerResponses, StopSandboxData, StopSandboxErrors, StopSandboxResponse, StopSandboxResponses, StopSequence, StopServiceData, StopServiceErrors, StopServiceResponse, StopServiceResponses, StorageQuota, StreamContainerMetricsData, StreamContainerMetricsErrors, StreamContainerMetricsResponses, StreamEventsData, StreamEventsErrors, StreamEventsResponses, StreamRunEventsData, StreamRunEventsErrors, StreamRunEventsResponses, StripeConfig, SyncedRepositoryListQuery, SyncRepositoriesData, SyncRepositoriesErrors, SyncRepositoriesResponse, SyncRepositoriesResponses, SyntaxResult, TagInfo, TagListResponse, TailDeploymentJobLogsData, TailDeploymentJobLogsErrors, TailLogsData, TailLogsError, TailLogsErrors, TailLogsRequest, TailLogsResponses, TargetRecommendation, TeamListResponse, TeamMemberResponse, TeamResponse, TeamRole, TeardownDeploymentData, TeardownDeploymentErrors, TeardownDeploymentResponse, TeardownDeploymentResponses, TeardownEnvironmentData, TeardownEnvironmentErrors, TeardownEnvironmentResponse, TeardownEnvironmentResponses, TemplateResponse, TestEmailRequest, TestEmailResponse, TestNotificationProviderData, TestNotificationProviderErrors, TestNotificationProviderResponse, TestNotificationProviderResponses, TestOidcProviderData, TestOidcProviderResponse, TestOidcProviderResponses, TestProviderConnectionData, TestProviderConnectionErrors, TestProviderConnectionResponse, TestProviderConnectionResponses, TestProviderData, TestProviderErrors, TestProviderKeyByIdData, TestProviderKeyByIdError, TestProviderKeyByIdErrors, TestProviderKeyByIdResponse, TestProviderKeyByIdResponses, TestProviderKeyInlineData, TestProviderKeyInlineError, TestProviderKeyInlineErrors, TestProviderKeyInlineResponse, TestProviderKeyInlineResponses, TestProviderKeyRequest, TestProviderKeyResponse, TestProviderResponse, TestProviderResponse2, TestProviderResponses, TestS3ConnectionPreviewData, TestS3ConnectionPreviewError, TestS3ConnectionPreviewErrors, TestS3ConnectionPreviewResponse, TestS3ConnectionPreviewResponses, TestS3SourceConnectionData, TestS3SourceConnectionError, TestS3SourceConnectionErrors, TestS3SourceConnectionResponse, TestS3SourceConnectionResponses, TimeBucketStats, TimeBucketStatsResponse, TimeseriesBucket, TimeseriesQueryParams, TlsMode, TodayStatsResponse, ToggleDeploymentMetricsRequest, ToggleServiceMetricsRequest, TokenRenewalRequest, ToolCallEvent, ToolInfo, ToolResultEvent, TopModelsQueryParams, TraceProjectRef, TracesResponse, TraceSummariesResponse, TraceSummary, TrackClickData, TrackClickErrors, TrackedLinkResponse, TrackingEventResponse, TrackOpenData, TrackOpenErrors, TrackOpenResponses, TriggerAgentData, TriggerAgentErrors, TriggerAgentRequest, TriggerAgentResponse, TriggerAgentResponses, TriggerDigestResponse, TriggerPipelinePayload, TriggerPipelineResponse, TriggerProjectPipelineData, TriggerProjectPipelineErrors, TriggerProjectPipelineResponse, TriggerProjectPipelineResponses, TriggerScanData, TriggerScanError, TriggerScanErrors, TriggerScanRequest, TriggerScanResponse, TriggerScanResponse2, TriggerScanResponses, TriggerServiceHealthCheckData, TriggerServiceHealthCheckErrors, TriggerServiceHealthCheckResponse, TriggerServiceHealthCheckResponses, TriggerWeeklyDigestData, TriggerWeeklyDigestErrors, TriggerWeeklyDigestResponse, TriggerWeeklyDigestResponses, TtlRequest, TtlResponse, TxtRecord, UiManifest, UiRoute, UndrainNodeResponse, UnifiedTrace, UniqueCountsQuery, UniqueCountsResponse, UnlinkServiceFromProjectData, UnlinkServiceFromProjectErrors, UnlinkServiceFromProjectResponse, UnlinkServiceFromProjectResponses, UnsupportedFeature, UpdateAdminGateRequest, UpdateAgentData, UpdateAgentErrors, UpdateAgentResponse, UpdateAgentResponses, UpdateAiProviderData, UpdateAiProviderErrors, UpdateAiProviderRequest, UpdateAiProviderResponse, UpdateAiProviderResponse2, UpdateAiProviderResponses, UpdateAlertData, UpdateAlertError, UpdateAlertErrors, UpdateAlertResponse, UpdateAlertResponses, UpdateAlertRuleData, UpdateAlertRuleErrors, UpdateAlertRuleRequest, UpdateAlertRuleResponse, UpdateAlertRuleResponses, UpdateApiKeyData, UpdateApiKeyErrors, UpdateApiKeyRequest, UpdateApiKeyResponse, UpdateApiKeyResponses, UpdateAutomaticDeployData, UpdateAutomaticDeployErrors, UpdateAutomaticDeployRequest, UpdateAutomaticDeployResponse, UpdateAutomaticDeployResponses, UpdateBackupScheduleData, UpdateBackupScheduleError, UpdateBackupScheduleErrors, UpdateBackupScheduleRequest, UpdateBackupScheduleResponse, UpdateBackupScheduleResponses, UpdateBlobRequest, UpdateBlobResponse, UpdateCloudflareProviderData, UpdateCloudflareProviderErrors, UpdateCloudflareProviderRequest, UpdateCloudflareProviderResponse, UpdateCloudflareProviderResponses, UpdateConfigBody, UpdateConnectionTokenData, UpdateConnectionTokenErrors, UpdateConnectionTokenResponse, UpdateConnectionTokenResponses, UpdateCustomDomainData, UpdateCustomDomainErrors, UpdateCustomDomainRequest, UpdateCustomDomainResponse, UpdateCustomDomainResponses, UpdateDashboardData, UpdateDashboardError, UpdateDashboardErrors, UpdateDashboardRequest, UpdateDashboardResponse, UpdateDashboardResponses, UpdateDeploymentConfigRequest, UpdateDeploymentTokenData, UpdateDeploymentTokenErrors, UpdateDeploymentTokenRequest, UpdateDeploymentTokenResponse, UpdateDeploymentTokenResponses, UpdateDnsProviderRequest, UpdateEmailProviderData, UpdateEmailProviderErrors, UpdateEmailProviderRequest, UpdateEmailProviderResponse, UpdateEmailProviderResponses, UpdateEnvironmentSettingsData, UpdateEnvironmentSettingsErrors, UpdateEnvironmentSettingsRequest, UpdateEnvironmentSettingsResponse, UpdateEnvironmentSettingsResponses, UpdateEnvironmentSubdomainData, UpdateEnvironmentSubdomainErrors, UpdateEnvironmentSubdomainRequest, UpdateEnvironmentSubdomainResponse, UpdateEnvironmentSubdomainResponses, UpdateEnvironmentVariableData, UpdateEnvironmentVariableErrors, UpdateEnvironmentVariableRequest, UpdateEnvironmentVariableResponse, UpdateEnvironmentVariableResponses, UpdateErrorGroupData, UpdateErrorGroupErrors, UpdateErrorGroupRequest, UpdateErrorGroupResponses, UpdateExternalServiceRequest, UpdateFlagData, UpdateFlagErrors, UpdateFlagRequest, UpdateFlagResponse, UpdateFlagResponses, UpdateFunnelData, UpdateFunnelErrors, UpdateFunnelResponses, UpdateGitProviderCredentialsData, UpdateGitProviderCredentialsErrors, UpdateGitProviderCredentialsResponse, UpdateGitProviderCredentialsResponses, UpdateGitSettingsData, UpdateGitSettingsErrors, UpdateGitSettingsRequest, UpdateGitSettingsResponse, UpdateGitSettingsResponses, UpdateGlobalMcpData, UpdateGlobalMcpErrors, UpdateGlobalMcpResponse, UpdateGlobalMcpResponses, UpdateGlobalSkillData, UpdateGlobalSkillErrors, UpdateGlobalSkillResponse, UpdateGlobalSkillResponses, UpdateIncidentStatusData, UpdateIncidentStatusErrors, UpdateIncidentStatusRequest, UpdateIncidentStatusResponse, UpdateIncidentStatusResponses, UpdateIpAccessControlData, UpdateIpAccessControlError, UpdateIpAccessControlErrors, UpdateIpAccessControlRequest, UpdateIpAccessControlResponse, UpdateIpAccessControlResponses, UpdateKvRequest, UpdateKvResponse, UpdateManagedDomainApiRequest, UpdateManagedDomainData, UpdateManagedDomainErrors, UpdateManagedDomainResponse, UpdateManagedDomainResponses, UpdateMcpData, UpdateMcpErrors, UpdateMcpRequest, UpdateMcpResponse, UpdateMcpResponses, UpdateMemberRoleRequest, UpdateMetricAlertRequest, UpdateNotificationEmailProviderData, UpdateNotificationEmailProviderErrors, UpdateNotificationEmailProviderRequest, UpdateNotificationEmailProviderResponse, UpdateNotificationEmailProviderResponses, UpdateNotificationProviderData, UpdateNotificationProviderErrors, UpdateNotificationProviderResponse, UpdateNotificationProviderResponses, UpdateOidcProviderData, UpdateOidcProviderRequest, UpdateOidcProviderResponse, UpdateOidcProviderResponses, UpdatePreferencesData, UpdatePreferencesErrors, UpdatePreferencesRequest, UpdatePreferencesResponse, UpdatePreferencesResponses, UpdateProjectData, UpdateProjectDeploymentConfigData, UpdateProjectDeploymentConfigErrors, UpdateProjectDeploymentConfigResponse, UpdateProjectDeploymentConfigResponses, UpdateProjectErrors, UpdateProjectResponse, UpdateProjectResponses, UpdateProjectSecretData, UpdateProjectSecretErrors, UpdateProjectSecretRequest, UpdateProjectSecretResponse, UpdateProjectSecretResponses, UpdateProjectSettingsData, UpdateProjectSettingsErrors, UpdateProjectSettingsRequest, UpdateProjectSettingsResponse, UpdateProjectSettingsResponses, UpdateProviderCredentialsRequest, UpdateProviderData, UpdateProviderErrors, UpdateProviderKeyData, UpdateProviderKeyError, UpdateProviderKeyErrors, UpdateProviderKeyRequest, UpdateProviderKeyResponse, UpdateProviderKeyResponses, UpdateProviderRequest, UpdateProviderResponse, UpdateProviderResponses, UpdateRouteData, UpdateRouteErrors, UpdateRouteRequest, UpdateRouteResponse, UpdateRouteResponses, UpdateS3SourceData, UpdateS3SourceError, UpdateS3SourceErrors, UpdateS3SourceRequest, UpdateS3SourceResponse, UpdateS3SourceResponses, UpdateSecretBody, UpdateSelfData, UpdateSelfErrors, UpdateSelfRequest, UpdateSelfResponse, UpdateSelfResponses, UpdateServiceData, UpdateServiceErrors, UpdateServiceResourcesData, UpdateServiceResourcesErrors, UpdateServiceResourcesResponse, UpdateServiceResourcesResponses, UpdateServiceResponse, UpdateServiceResponses, UpdateSessionDurationData, UpdateSessionDurationError, UpdateSessionDurationErrors, UpdateSessionDurationRequest, UpdateSessionDurationResponse, UpdateSessionDurationResponse2, UpdateSessionDurationResponses, UpdateSettingsData, UpdateSettingsErrors, UpdateSettingsResponse, UpdateSettingsResponses, UpdateSkillData, UpdateSkillErrors, UpdateSkillRequest, UpdateSkillResponse, UpdateSkillResponses, UpdateSlackProviderData, UpdateSlackProviderErrors, UpdateSlackProviderRequest, UpdateSlackProviderResponse, UpdateSlackProviderResponses, UpdateSpeedMetricsData, UpdateSpeedMetricsError, UpdateSpeedMetricsErrors, UpdateSpeedMetricsPayload, UpdateSpeedMetricsResponse, UpdateSpeedMetricsResponses, UpdateStatusResponse, UpdateTeamData, UpdateTeamErrors, UpdateTeamMemberRoleData, UpdateTeamMemberRoleErrors, UpdateTeamMemberRoleResponse, UpdateTeamMemberRoleResponses, UpdateTeamRequest, UpdateTeamResponse, UpdateTeamResponses, UpdateTokenRequest, UpdateTokenResponse, UpdateUserData, UpdateUserErrors, UpdateUserRequest, UpdateUserResponse, UpdateUserResponses, UpdateWebhookData, UpdateWebhookErrors, UpdateWebhookProviderData, UpdateWebhookProviderErrors, UpdateWebhookProviderRequest, UpdateWebhookProviderResponse, UpdateWebhookProviderResponses, UpdateWebhookRequestBody, UpdateWebhookResponse, UpdateWebhookResponses, UpgradeExternalServiceRequest, UpgradePreviewGatewayData, UpgradePreviewGatewayResponse, UpgradePreviewGatewayResponses, UpgradeRequest, UpgradeServiceData, UpgradeServiceErrors, UpgradeServiceResponse, UpgradeServiceResponses, UploadGlobalSkillData, UploadGlobalSkillErrors, UploadGlobalSkillResponse, UploadGlobalSkillResponses, UploadReleaseFileData, UploadReleaseFileErrors, UploadReleaseFileResponse, UploadReleaseFileResponses, UploadSkillData, UploadSkillErrors, UploadSkillResponse, UploadSkillResponses, UploadSourceFileData, UploadSourceFileErrors, UploadSourceFileResponse, UploadSourceFileResponses, UploadSourceMapData, UploadSourceMapErrors, UploadSourceMapResponse, UploadSourceMapResponses, UploadStaticBundleData, UploadStaticBundleErrors, UploadStaticBundleResponse, UploadStaticBundleResponses, UpsertAgentRequest, UpsertSecretData, UpsertSecretErrors, UpsertSecretRequest, UpsertSecretResponse, UpsertSecretResponses, UptimeDataPoint, UptimeHistoryResponse, UsageFilter, UsageInfo, UsageLogEntry, UsageLogPage, UsageQueryParams, UsageSource, UsageSummary, UserResponse, ValidateConnectionData, ValidateConnectionErrors, ValidateConnectionResponse, ValidateConnectionResponses, ValidateEmailData, ValidateEmailErrors, ValidateEmailRequest, ValidateEmailResponse, ValidateEmailResponse2, ValidateEmailResponses, ValidationLevel, ValidationReport, ValidationResponse, ValidationResult, ValidationStatus, ValidationSummary, VerifyAndEnableMfaData, VerifyAndEnableMfaErrors, VerifyAndEnableMfaResponse, VerifyAndEnableMfaResponses, VerifyDomainData, VerifyDomainErrors, VerifyDomainResponse, VerifyDomainResponses, VerifyEmailData, VerifyEmailErrors, VerifyEmailResponse, VerifyEmailResponses, VerifyManagedDomainData, VerifyManagedDomainErrors, VerifyManagedDomainResponse, VerifyManagedDomainResponses, VerifyMfaChallengeData, VerifyMfaChallengeErrors, VerifyMfaChallengeResponse, VerifyMfaChallengeResponses, VerifyMfaRequest, VerifyStepUpData, VerifyStepUpErrors, VerifyStepUpRequest, VerifyStepUpResponse, VerifyStepUpResponses, ViewItem, ViewsOverTime, ViewsOverTimeQuery, VisitorDetails, VisitorFacets, VisitorFacetsQuery, VisitorFacetValue, VisitorInfo, VisitorJourneyQuery, VisitorJourneyResponse, VisitorLocationsQuery, VisitorRecord, VisitorSegmentFilters, VisitorSessionsQuery, VisitorSessionsResponse, VisitorsListQuery, VisitorsResponse, VisitorStats, VisitorWithGeolocation, VolumeMount, VolumeType, VulnerabilityResponse, WakeEnvironmentData, WakeEnvironmentErrors, WakeEnvironmentResponse, WakeEnvironmentResponses, WalWarning, WalWarningSeverity, WebhookConfig, WebhookDeliveryResponse, WebhookResponse, WebhookTriggerData, WebhookTriggerErrors, WebhookTriggerRequest, WebhookTriggerResponse, WebhookTriggerResponse2, WebhookTriggerResponses, WorkflowDryRunData, WorkflowDryRunErrors, WorkflowDryRunRequest, WorkflowDryRunResponse, WorkflowDryRunResponses, WorkloadDescriptor, WorkloadId, WorkloadStatus, WorkloadType, WriteFileBody, WriteFileData, WriteFileErrors, WriteFileResponse, WriteFileResponses, WriteFilesBody, WriteFilesData, WriteFilesErrors, WriteFilesResponse, WriteFilesResponse2, WriteFilesResponses, ZoneListResponse } from './types.gen'; +export { acknowledgeAlarm, activateAiProvider, activateApiKey, activateConnection, activateProvider, addClusterMember, addContext, addEnvironmentDomain, addEvents, addManagedDomain, addSessionReplayEvents, addTeamMember, adminDrainNode, adminDrainStatus, adminGetNode, adminListNodeContainers, adminListNodes, adminRemoveNode, adminUndrainNode, applyHostnameMode, archiveConversation, archiveFlag, assignRole, attachScheduleServices, blobCopy, blobDelete, blobDisable, blobDownload, blobEnable, blobHead, blobList, blobPut, blobStatus, blobUpdate, cancel, cancelBackup, cancelDeployment, cancelDomainOrder, cancelPgUpgrade, cancelRun, cancelScheduleRun, changePasswordSelf, changeProjectSource, changeRequiredPassword, chatCompletions, checkAnalyticsHasEvents, checkCommitExists, checkDomainStatus, checkExplorerSupport, checkIpBlocked, checkProviderDeletionSafety, chunkUploadOptions, cleanupExpiredBackups, clearPreviewPassword, cliDeviceApprove, cliDeviceDeny, cliDeviceLookup, cliDevicePoll, cliDeviceStart, cliLogout, cmd, cmdKill, cmdLogs, confirmPendingAction, containerMetricsGetHistory, createAgent, createAlert, createAlertRule, createApiKey, createBackupSchedule, createBitbucketProvider, createCloudflareProvider, createConversation, createCustomDomain, createDashboard, createDeploymentToken, createDnsProvider, createDomain, createDsn, createEmailDomain, createEmailProvider, createEnvironment, createEnvironmentVariable, createFlag, createFunnel, createGenericProvider, createGiteaPatProvider, createGithubPatProvider, createGitlabOauthProvider, createGitlabPatProvider, createGitProvider, createGlobalMcp, createGlobalSkill, createIncident, createIpAccessControl, createMcp, createMonitor, createNotificationEmailProvider, createNotificationProvider, createOidcProvider, createOidcRoleMapping, createOrRecreateOrder, createPlan, createPr, createProject, createProjectFromTemplate, createProjectRelease, createProjectSecret, createProviderKey, createRelease, createRoute, createS3Source, createSandbox, createService, createSkill, createSlackProvider, createTeam, createUser, createWebhook, createWebhookProvider, deactivateApiKey, deactivateConnection, deactivateProvider, deleteAgent, deleteAlert, deleteAlertRule, deleteApiKey, deleteBackup, deleteBackupSchedule, deleteConnection, deleteCustomDomain, deleteDashboard, deleteDeploymentToken, deleteDnsProvider, deleteDomain, deleteEmailDomain, deleteEmailProvider, deleteEnvironment, deleteEnvironmentDomain, deleteEnvironmentVariable, deleteExternalImage, deleteFunnel, deleteGitProvider, deleteGlobalMcp, deleteGlobalSkill, deleteIpAccessControl, deleteMcp, deleteMonitor, deleteNotificationProvider, deleteOidcProvider, deleteOidcRoleMapping, deletePreferences, deleteProject, deleteProjectSecret, deleteProviderKey, deleteProviderSafely, deleteReleaseSourceFiles, deleteReleaseSourceMaps, deleteRoute, deleteS3Source, deleteScan, deleteSecret, deleteService, deleteSessionReplay, deleteSkill, deleteSourceMap, deleteStaticBundle, deleteTeam, deleteUser, deleteWebhook, deployFromImage, deployFromImageUpload, deployFromStatic, deployFromUploadedSource, deploymentMetricsGetLatest, deploymentMetricsGetRange, deploymentMetricsToggle, destroySandbox, detachScheduleService, detectPublicPresets, disableBackupSchedule, disableMfa, disconnectCloud, discoverWorkloads, domain, downloadGlobalSkillArchive, downloadObject, downloadSkillArchive, emailStatus, embeddings, enableBackupSchedule, enrichVisitor, enrollCloud, exec, execDetached, executeDeploymentOperation, executeImport, extendTimeout, externalServiceEnablePgStatStatements, externalServiceMetricsByDatabase, externalServiceMetricsCreateAlertRule, externalServiceMetricsDeleteAlertRule, externalServiceMetricsGetAlertRules, externalServiceMetricsGetLatest, externalServiceMetricsGetRange, externalServiceMetricsStatus, externalServiceMetricsToggle, externalServiceMetricsUpdateAlertRule, externalServiceResetPgStatStatements, finalizeOrder, finalizeProjectRelease, findConversation, generateJoinToken, generatePresetDockerfile, getAccessInfo, getActiveVisitors, getActivityGraph, getAdminGate, getAgent, getAggregatedBuckets, getAiAgentBreakdown, getAiAgentPages, getAiAgentTimeline, getAiPageBreakdown, getAiStatusBreakdown, getAlert, getAlertRule, getAllRepositoriesByName, getAnalyticsActiveVisitors, getAnalyticsEventsCount, getAnalyticsSessionEvents, getAnalyticsVisitorSessions, getApiKey, getApiKeyPermissions, getAuditLog, getBackup, getBackupSchedule, getBranchesByRepositoryId, getBucketedIncidents, getBucketedStatus, getChallengeToken, getChatReadiness, getCliStatus, getCloudCapability, getCloudStatus, getClusterHealth, getClusterMember, getCmd, getContainerDetail, getContainerEnvironmentVariable, getContainerInfo, getContainerLogs, getContainerLogsById, getContainerMetrics, getConversation, getConversationDetail, getConversations, getCronById, getCronExecutions, getCrossProjectTraceSiblings, getCurrentMonitorStatus, getCurrentUser, getCustomDomain, getDashboard, getDashboardProjectsAnalytics, getDelivery, getDeployment, getDeploymentContainerLogContent, getDeploymentJobLogs, getDeploymentJobs, getDeploymentOperations, getDeploymentOperationStatus, getDeploymentToken, getDiskStatus, getDnsChanges, getDnsProvider, getDomain, getDomainByHost, getDomainById, getDomainByName, getDomainDnsRecords, getDomainOrder, getEmail, getEmailEvents, getEmailLinks, getEmailProvider, getEmailStats, getEmailTracking, getEmailTrackingStatus, getEntityInfo, getEnvironment, getEnvironmentCrons, getEnvironmentDomains, getEnvironments, getEnvironmentVariables, getEnvironmentVariableValue, getErrorDashboardStats, getErrorEvent, getErrorGroup, getErrorStats, getErrorTimeSeries, getEventDetail, getEventEntries, getEventsCount, getEventsTimeline, getEventTypeBreakdown, getEventVisitors, getExternalImage, getFile, getFlag, getFlagSnapshot, getFunnelMetrics, getGenaiTrace, getGeneralStats, getGitProvider, getGlobalEvents, getGlobalEventStats, getGlobalMcp, getGlobalSandboxStatus, getGlobalSkill, getGroupedPageMetrics, getHealth, getHourlyVisits, getHttpChallengeDebug, getImportStatus, getIncident, getIncidentUpdates, getIpAccessControl, getIpGeolocation, getJoinTokenStatus, getLastDeployment, getLatestScan, getLatestScansPerEnvironment, getLiveVisitorsList, getLogContext, getMcp, getMetricsOverTime, getMonitor, getNotificationProvider, getOnDemandCertStatus, getOrCreateDsn, getPageFlow, getPageHourlySessions, getPagePathDetail, getPagePaths, getPagePathsSparklines, getPagePathVisitors, getPendingAction, getPerformanceMetrics, getPgUpgrade, getPgUpgradeLogs, getPipelineStats, getPlatformInfo, getPostgresWalHealth, getPreferences, getPreviewGatewayLogs, getPreviewGatewaySettings, getPreviewGatewayStatus, getPricing, getPrivateIp, getProject, getProjectAlarmsSummary, getProjectBySlug, getProjectDeployments, getProjects, getProjectServiceEnvironmentVariables, getProjectSessionReplays, getProjectsHealth, getProjectsMonitorHealth, getProjectStatistics, getProjectTemplate, getPropertyBreakdown, getPropertyTimeline, getProviderConnections, getProviderMetadata, getProvidersMetadata, getProxyLogById, getProxyLogByRequestId, getProxyLogs, getPublicBranches, getPublicIp, getPublicRepository, getQuota, getRecentActivity, getRemoteExternalImage, getRepositoryBranches, getRepositoryById, getRepositoryByName, getRepositoryPresetByName, getRepositoryPresetLive, getRepositoryTags, getResolvedEnvironmentVariables, getResolvedEnvironmentVariableValue, getRestoreCapabilities, getRestoreRun, getRoute, getRun, getRunWithLogs, getS3Credentials, getS3Source, getSandbox, getSandboxStatus, getScan, getScanByDeployment, getScanVulnerabilities, getService, getServiceBySlug, getServiceEnvironmentVariable, getServiceEnvironmentVariables, getServiceHealthStatus, getServicePreviewEnvironmentVariableNames, getServicePreviewEnvironmentVariablesMasked, getServiceRuntime, getServiceStats, getServiceTypeParameters, getServiceTypes, getSessionDetails, getSessionEvents, getSessionLogs, getSessionReplay, getSessionReplayEvents, getSettings, getSkill, getSlowQueries, getStaticBundle, getStatusOverview, getTagsByRepositoryId, getTeam, getTimeBucketStats, getTodayStats, getTrace, getUnifiedTrace, getUniqueCounts, getUniqueEvents, getUpdateStatus, getUptimeHistory, getUsageByProvider, getUsageRecent, getUsageSummary, getUsageTimeseries, getUsageTopModels, getVisitorByGuid, getVisitorById, getVisitorDetails, getVisitorFacets, getVisitorInfo, getVisitorJourney, getVisitors, getVisitorSessions, getVisitorStats, getWebhook, grantProjectAccess, handleGitProviderOauthCallback, hasAnalyticsEvents, hasErrorGroups, hasPerformanceMetrics, importExternalService, ingestLogs, ingestLogsByPath, ingestMetrics, ingestMetricsByPath, ingestSentryEnvelope, ingestSentryEvent, ingestTraces, ingestTracesByPath, initSessionReplay, inspectDropArchive, jobLogs, jobStatus, killJob, kvDel, kvDisable, kvEnable, kvExpire, kvGet, kvIncr, kvKeys, kvSet, kvStatus, kvTtl, kvUpdate, latestRunForSource, linkCustomDomainToCertificate, linkServiceToProject, listAgentRuns, listAgents, listAiProviders, listAlertRules, listAlerts, listAllConversations, listAllRuns, listApiKeys, listAuditLogs, listAvailableContainers, listBackupAlerts, listBackupChildren, listBackupSchedules, listBackupsForSchedule, listCommitsByRepositoryId, listConnections, listContainers, listContainersAtPath, listConversations, listCustomDomainsForProject, listDashboards, listDeliveries, listDeploymentContainerLogs, listDeploymentTokens, listDnsProviders, listDomains, listDsns, listEmailDomains, listEmailProviders, listEmails, listEnrollmentTokens, listEntities, listErrorEvents, listErrorGroups, listEvents, listEventTypes, listExternalImages, listExternalPlugins, listExternalServiceBackups, listFlags, listFunnels, listGitProviders, listGlobalMcps, listGlobalSkills, listIncidents, listInsights, listIpAccessControl, listJobs, listKnownAiAgents, listManagedDomains, listMcps, listMetricLabelKeys, listMetricLabelValues, listMetricNames, listModels, listMonitors, listNotificationProviders, listOidcProviders, listOidcProviderUsers, listOidcRoleMappings, listOnDemandCerts, listOrders, listPeers, listPendingActions, listPgUpgrades, listPresets, listProjectAccess, listProjectAlarms, listProjectScans, listProjectSecrets, listProjectServices, listProjectTemplates, listProjectTemplateTags, listProviderKeys, listProviderZones, listPublicProviders, listReleaseFiles, listReleases, listRemoteExternalImages, listRepositoriesByConnection, listRepositoriesByProvider, listRestoreRunsForService, listRootContainers, listRoutes, listS3Sources, listSandboxes, listScheduleRunJobs, listScheduleRuns, listScheduleServices, listSecrets, listServiceHealthStatuses, listServiceProjects, listServices, listServiceSchedules, listSkills, listSourceBackups, listSourceFiles, listSourceMaps, listSources, listStaticBundles, listSyncedRepositories, listTeamMembers, listTeamProjects, listTeams, listUsers, listWebhooks, login, logout, lookupDnsARecords, mintEnrollmentToken, mkdir, nodeHeartbeat, nodeMetricsGetRange, observabilityFullEvent, observabilityListEvents, oidcCallback, type Options, patchAdminGate, patchPreviewGatewaySettings, pauseDeployment, pauseSandbox, planRestore, postDnsAck, previewAlert, previewFunnelMetrics, previewHostnameMode, promoteClusterMember, promoteDeployment, provisionDomain, purgeProjectLogs, pushExternalImage, queryData, queryGenaiTraces, queryLogs, queryMetrics, queryTraces, queryTraceSummaries, readFile, reAnalyze, recordConsoleEvent, recordEventMetrics, recordFlagExposure, recordSpeedMetrics, refreshRouteTable, regenerateDsn, registerExternalImage, registerNode, reinstallGitlabWebhook, rejectPendingAction, reloadPlugins, removeClusterMember, removeManagedDomain, removeRole, removeTeamMember, renameConversation, renewDomain, requestPasswordReset, resetPassword, resizeSandbox, resolveAlarm, restartContainer, restartPreviewGateway, restartSandbox, restoreFlag, restoreUser, resumeDeployment, resumeSandbox, retryCluster, retryDelivery, retryPgUpgrade, retryRun, revealGlobalMcpConfig, revealMcpConfig, revealNotificationProviderConfig, revealServiceParameter, revenueCreateIntegration, revenueDeleteIntegration, revenueGlobalEvents, revenueImportInvoicesCsv, revenueImportSubscriptionsCsv, revenueListIntegrations, revenueListProviders, revenueMetricsCustomers, revenueMetricsGlobalMrr, revenueMetricsGlobalSummary, revenueMetricsMrr, revenueMetricsSummary, revenueRecentEvents, revenueRotateToken, revenueUpdateConfig, revenueUpdateSecret, revokeDsn, revokeEnrollmentToken, revokeJoinToken, revokeProjectAccess, rollbackPgUpgrade, rollbackToDeployment, rootfsGc, rootfsReport, rotateApiKey, rotateDeploymentToken, runBackupForSource, runConnectionHealthCheck, runExternalServiceBackup, runScheduleNow, sandboxCreatePreviewLink, saveAgentToken, saveAiProviderCredential, searchLogs, sendEmail, setDefaultS3Source, setFlagEnvironment, setPreviewPassword, setupDns, setupDnsChallenge, setupEmailTracking, setupMfa, sleepEnvironment, smokeTestAgent, sourceSandbox, startAnalysis, startContainer, startFix, startGitProviderOauth, startOidcLoginBySlug, startPgUpgrade, startRestore, startService, statPath, stopContainer, stopSandbox, stopService, streamContainerMetrics, streamEvents, streamRunEvents, syncRepositories, tailDeploymentJobLogs, tailLogs, teardownDeployment, teardownEnvironment, testNotificationProvider, testOidcProvider, testProvider, testProviderConnection, testProviderKeyById, testProviderKeyInline, testS3ConnectionPreview, testS3SourceConnection, trackClick, trackOpen, triggerAgent, triggerProjectPipeline, triggerScan, triggerServiceHealthCheck, triggerWeeklyDigest, unlinkServiceFromProject, updateAgent, updateAiProvider, updateAlert, updateAlertRule, updateApiKey, updateAutomaticDeploy, updateBackupSchedule, updateCloudflareProvider, updateConnectionToken, updateCustomDomain, updateDashboard, updateDeploymentToken, updateEmailProvider, updateEnvironmentSettings, updateEnvironmentSubdomain, updateEnvironmentVariable, updateErrorGroup, updateFlag, updateFunnel, updateGitProviderCredentials, updateGitSettings, updateGlobalMcp, updateGlobalSkill, updateIncidentStatus, updateIpAccessControl, updateManagedDomain, updateMcp, updateNotificationEmailProvider, updateNotificationProvider, updateOidcProvider, updatePreferences, updateProject, updateProjectDeploymentConfig, updateProjectSecret, updateProjectSettings, updateProvider, updateProviderKey, updateRoute, updateS3Source, updateSelf, updateService, updateServiceResources, updateSessionDuration, updateSettings, updateSkill, updateSlackProvider, updateSpeedMetrics, updateTeam, updateTeamMemberRole, updateUser, updateWebhook, updateWebhookProvider, upgradePreviewGateway, upgradeService, uploadGlobalSkill, uploadReleaseFile, uploadSkill, uploadSourceFile, uploadSourceMap, uploadStaticBundle, upsertSecret, validateConnection, validateEmail, verifyAndEnableMfa, verifyDomain, verifyEmail, verifyManagedDomain, verifyMfaChallenge, verifyStepUp, wakeEnvironment, webhookTrigger, workflowDryRun, writeFile, writeFiles } from './sdk.gen'; +export type { AcknowledgeAlarmData, AcknowledgeAlarmErrors, AcknowledgeAlarmResponses, AcmeOrderResponse, ActivateAiProviderData, ActivateAiProviderErrors, ActivateAiProviderResponse, ActivateAiProviderResponses, ActivateApiKeyData, ActivateApiKeyErrors, ActivateApiKeyResponse, ActivateApiKeyResponses, ActivateConnectionData, ActivateConnectionErrors, ActivateConnectionResponses, ActivateProviderData, ActivateProviderErrors, ActivateProviderResponse, ActivateProviderResponses, ActiveVisitor, ActiveVisitorsQuery, ActiveVisitorsResponse, ActivityDay, ActivityEvent, ActivityGraphQuery, ActivityGraphResponse, AddClusterMemberData, AddClusterMemberErrors, AddClusterMemberRequest, AddClusterMemberResponse, AddClusterMemberResponses, AddContextData, AddContextErrors, AddContextRequest, AddContextResponses, AddEnvironmentDomainData, AddEnvironmentDomainErrors, AddEnvironmentDomainRequest, AddEnvironmentDomainResponse, AddEnvironmentDomainResponses, AddEventsData, AddEventsError, AddEventsErrors, AddEventsRequest, AddEventsResponse, AddEventsResponse2, AddEventsResponses, AddManagedDomainApiRequest, AddManagedDomainData, AddManagedDomainErrors, AddManagedDomainResponse, AddManagedDomainResponses, AddSessionReplayEventsData, AddSessionReplayEventsError, AddSessionReplayEventsErrors, AddSessionReplayEventsResponse, AddSessionReplayEventsResponses, AddTeamMemberData, AddTeamMemberErrors, AddTeamMemberResponse, AddTeamMemberResponses, AdminDrainNodeData, AdminDrainNodeErrors, AdminDrainNodeResponse, AdminDrainNodeResponses, AdminDrainStatusData, AdminDrainStatusErrors, AdminDrainStatusResponse, AdminDrainStatusResponses, AdminGateResponse, AdminGateSource, AdminGetNodeData, AdminGetNodeErrors, AdminGetNodeResponse, AdminGetNodeResponses, AdminListNodeContainersData, AdminListNodeContainersErrors, AdminListNodeContainersResponse, AdminListNodeContainersResponses, AdminListNodesData, AdminListNodesErrors, AdminListNodesResponse, AdminListNodesResponses, AdminRemoveNodeData, AdminRemoveNodeErrors, AdminRemoveNodeResponse, AdminRemoveNodeResponses, AdminUndrainNodeData, AdminUndrainNodeErrors, AdminUndrainNodeResponse, AdminUndrainNodeResponses, AgentConfigResponse, AgentRunLogResponse, AgentRunResponse, AgentRunWithLogsResponse, AgentSandboxSettings, AgentSandboxSettingsMasked, AggregatedBucketItem, AggregatedBucketsQuery, AggregatedBucketsResponse, AggregationLevel, AggregationTemporality, AiAgentBreakdownResponse, AiAgentBreakdownRow, AiAgentDescriptor, AiAgentPageRow, AiAgentPagesResponse, AiAgentTimelineResponse, AiAgentTimelineRow, AiChatLimitsSettings, AiConfigSettings, AiPageBreakdownResponse, AiPageBreakdownRow, AiStatusBreakdownResponse, AiStatusBreakdownRow, AlarmListResponse, AlarmResponse, AlarmSummaryResponse, AlertRuleResponse, AllocEntry, AnalyticsSessionEventsResponse, AnnotatedSpan, AnomalyAlgorithm, AnomalyParams, AnomalyPreviewPointResponse, AnomalyPreviewRequest, AnomalyPreviewResponse, ApiKeyListResponse, ApiKeyResponse, ApplyHostnameModeData, ApplyHostnameModeErrors, ApplyHostnameModeRequest, ApplyHostnameModeResponse, ApplyHostnameModeResponses, AppSettings, AppSettingsResponse, ArchiveConversationData, ArchiveConversationErrors, ArchiveConversationResponse, ArchiveConversationResponses, ArchiveFlagData, ArchiveFlagErrors, ArchiveFlagResponse, ArchiveFlagResponse2, ArchiveFlagResponses, ArchiveMode, AssignRoleData, AssignRoleErrors, AssignRoleRequest, AssignRoleResponses, AttachScheduleServicesData, AttachScheduleServicesError, AttachScheduleServicesErrors, AttachScheduleServicesRequest, AttachScheduleServicesResponse, AttachScheduleServicesResponse2, AttachScheduleServicesResponses, AuditLogIpInfo, AuditLogResponse, AuditLogUserInfo, AuthFlavorDto, AuthResponse, AuthStatusResponse, AuthTokenResponse, AutofixerRunResponse, AutofixerRunWithLogsResponse, AutofixRunConfig, AutoWatchParams, AvailableContainerInfo, AvailablePermissions, BackupAlertListResponse, BackupAlertResponse, BackupResponse, BackupScheduleResponse, BitbucketAuthInput, BlobCopyData, BlobCopyError, BlobCopyErrors, BlobCopyResponse, BlobCopyResponses, BlobDeleteData, BlobDeleteError, BlobDeleteErrors, BlobDeleteResponse, BlobDeleteResponses, BlobDisableData, BlobDisableErrors, BlobDisableResponse, BlobDisableResponses, BlobDownloadData, BlobDownloadError, BlobDownloadErrors, BlobDownloadResponses, BlobEnableData, BlobEnableErrors, BlobEnableResponse, BlobEnableResponses, BlobHeadData, BlobHeadError, BlobHeadErrors, BlobHeadResponses, BlobListData, BlobListError, BlobListErrors, BlobListResponse, BlobListResponses, BlobPutData, BlobPutError, BlobPutErrors, BlobPutResponse, BlobPutResponses, BlobResponse, BlobStatusData, BlobStatusErrors, BlobStatusResponse, BlobStatusResponse2, BlobStatusResponses, BlobUpdateData, BlobUpdateErrors, BlobUpdateResponse, BlobUpdateResponses, BranchInfo, BranchListResponse, BrowserCount, BrowsersQuery, BuildConfiguration, BuildLimitsSettings, CancelBackupData, CancelBackupError, CancelBackupErrors, CancelBackupResponse, CancelBackupResponse2, CancelBackupResponses, CancelData, CancelDeploymentData, CancelDeploymentErrors, CancelDeploymentResponse, CancelDeploymentResponses, CancelDomainOrderData, CancelDomainOrderErrors, CancelDomainOrderResponse, CancelDomainOrderResponses, CancelErrors, CancelPgUpgradeData, CancelPgUpgradeErrors, CancelPgUpgradeResponse, CancelPgUpgradeResponses, CancelResponses, CancelRunData, CancelRunErrors, CancelRunResponse, CancelRunResponses, CancelScheduleRunData, CancelScheduleRunError, CancelScheduleRunErrors, CancelScheduleRunResponse, CancelScheduleRunResponses, CertStatusResponse, ChallengeConfig, ChallengeError, ChallengeValidationStatus, ChangePasswordRequest, ChangePasswordSelfData, ChangePasswordSelfErrors, ChangePasswordSelfResponse, ChangePasswordSelfResponses, ChangeProjectSourceData, ChangeProjectSourceErrors, ChangeProjectSourceRequest, ChangeProjectSourceResponse, ChangeProjectSourceResponses, ChangeRequiredPasswordData, ChangeRequiredPasswordErrors, ChangeRequiredPasswordResponse, ChangeRequiredPasswordResponses, ChatCompletionChoice, ChatCompletionRequest, ChatCompletionResponse, ChatCompletionsData, ChatCompletionsError, ChatCompletionsErrors, ChatCompletionsResponse, ChatCompletionsResponses, ChatMessage, ChatReadinessResponse, CheckAnalyticsHasEventsData, CheckAnalyticsHasEventsErrors, CheckAnalyticsHasEventsResponse, CheckAnalyticsHasEventsResponses, CheckCommitExistsData, CheckCommitExistsErrors, CheckCommitExistsResponse, CheckCommitExistsResponses, CheckDomainStatusData, CheckDomainStatusErrors, CheckDomainStatusResponse, CheckDomainStatusResponses, CheckExplorerSupportData, CheckExplorerSupportErrors, CheckExplorerSupportResponse, CheckExplorerSupportResponses, CheckIpBlockedData, CheckIpBlockedError, CheckIpBlockedErrors, CheckIpBlockedResponses, CheckProviderDeletionSafetyData, CheckProviderDeletionSafetyErrors, CheckProviderDeletionSafetyResponse, CheckProviderDeletionSafetyResponses, ChildBackupEntryResponse, ChildBackupListResponse, ChunkUploadOptionsData, ChunkUploadOptionsResponse, ChunkUploadOptionsResponses, CleanupExpiredBackupsData, CleanupExpiredBackupsError, CleanupExpiredBackupsErrors, CleanupExpiredBackupsRequest, CleanupExpiredBackupsResponse, CleanupExpiredBackupsResponses, ClearPreviewPasswordData, ClearPreviewPasswordErrors, ClearPreviewPasswordResponse, ClearPreviewPasswordResponses, CliDeviceApproveData, CliDeviceApproveErrors, CliDeviceApproveRequest, CliDeviceApproveResponse, CliDeviceApproveResponse2, CliDeviceApproveResponses, CliDeviceDenyData, CliDeviceDenyErrors, CliDeviceDenyResponse, CliDeviceDenyResponses, CliDeviceLookupData, CliDeviceLookupErrors, CliDeviceLookupResponse, CliDeviceLookupResponse2, CliDeviceLookupResponses, CliDevicePollData, CliDevicePollErrors, CliDevicePollRequest, CliDevicePollResponse, CliDevicePollResponse2, CliDevicePollResponses, CliDeviceStartData, CliDeviceStartErrors, CliDeviceStartRequest, CliDeviceStartResponse, CliDeviceStartResponse2, CliDeviceStartResponses, ClientOptions, CliLoginRequest, CliLogoutData, CliLogoutErrors, CliLogoutResponse, CliLogoutResponses, CloudCapability, CloudflareConfig, CloudProvider, CloudSettings, CloudStatus, ClusterCapacity, ClusterDnsSettings, ClusterHealthReportResponse, ClusterMemberHealthResponse, ClusterMemberRequest, CmdBody, CmdData, CmdErrors, CmdInner, CmdKillBody, CmdKillData, CmdKillErrors, CmdKillResponse, CmdKillResponses, CmdLogsData, CmdLogsErrors, CmdLogsResponses, CmdResponse, CmdResponse2, CmdResponses, CommitExistsResponse, CommitInfo, CommitListResponse, Comparator, ComposePublicPort, ConfirmPendingActionData, ConfirmPendingActionErrors, ConfirmPendingActionResponse, ConfirmPendingActionResponses, ConnectionListQuery, ConnectionListResponse, ConnectionResponse, ConnectionTestResult, ConsoleEventPayload, ContainerActionResponse, ContainerDetailResponse, ContainerEnvironmentVariableValueResponse, ContainerInfoResponse, ContainerInventoryItem, ContainerListResponse, ContainerLogSettings, ContainerLogsQuery, ContainerMetricHistoryPoint, ContainerMetricsGetHistoryData, ContainerMetricsGetHistoryErrors, ContainerMetricsGetHistoryResponse, ContainerMetricsGetHistoryResponses, ContainerMetricsHistoryQuery, ContainerMetricsResponse, ContainerResponse, ContainerRuntimeInfo, ContainerStatsSample, ContentPart, ContextLine, ContextLogsRequest, ContextLogsResponse, ConversationDetailResponse, ConversationResponse, ConversationsQueryParams, ConversationSummary, CopyBlobRequest, CostAnalysis, CreateAgentData, CreateAgentErrors, CreateAgentResponse, CreateAgentResponses, CreateAlertData, CreateAlertError, CreateAlertErrors, CreateAlertResponse, CreateAlertResponses, CreateAlertRuleData, CreateAlertRuleErrors, CreateAlertRuleRequest, CreateAlertRuleResponse, CreateAlertRuleResponses, CreateApiKeyData, CreateApiKeyErrors, CreateApiKeyRequest, CreateApiKeyResponse, CreateApiKeyResponse2, CreateApiKeyResponses, CreateBackupScheduleData, CreateBackupScheduleError, CreateBackupScheduleErrors, CreateBackupScheduleRequest, CreateBackupScheduleResponse, CreateBackupScheduleResponses, CreateBitbucketProviderData, CreateBitbucketProviderErrors, CreateBitbucketProviderResponse, CreateBitbucketProviderResponses, CreateBitbucketRequest, CreateCloudflareProviderData, CreateCloudflareProviderErrors, CreateCloudflareProviderRequest, CreateCloudflareProviderResponse, CreateCloudflareProviderResponses, CreateConversationData, CreateConversationErrors, CreateConversationRequest, CreateConversationResponse, CreateConversationResponses, CreateCustomDomainData, CreateCustomDomainErrors, CreateCustomDomainResponse, CreateCustomDomainResponses, CreateDashboardData, CreateDashboardError, CreateDashboardErrors, CreateDashboardRequest, CreateDashboardResponse, CreateDashboardResponses, CreateDeploymentTokenData, CreateDeploymentTokenErrors, CreateDeploymentTokenRequest, CreateDeploymentTokenResponse, CreateDeploymentTokenResponse2, CreateDeploymentTokenResponses, CreateDnsProviderData, CreateDnsProviderErrors, CreateDnsProviderRequest, CreateDnsProviderResponse, CreateDnsProviderResponses, CreateDomainData, CreateDomainErrors, CreateDomainRequest, CreateDomainResponse, CreateDomainResponses, CreatedResource, CreateDsnData, CreateDsnErrors, CreateDsnRequest, CreateDsnResponse, CreateDsnResponses, CreateEmailDomainData, CreateEmailDomainErrors, CreateEmailDomainRequest, CreateEmailDomainResponse, CreateEmailDomainResponses, CreateEmailProviderData, CreateEmailProviderErrors, CreateEmailProviderRequest, CreateEmailProviderResponse, CreateEmailProviderResponses, CreateEnvironmentData, CreateEnvironmentErrors, CreateEnvironmentRequest, CreateEnvironmentResponse, CreateEnvironmentResponses, CreateEnvironmentVariableData, CreateEnvironmentVariableErrors, CreateEnvironmentVariableRequest, CreateEnvironmentVariableResponse, CreateEnvironmentVariableResponses, CreateExternalServiceRequest, CreateFlagData, CreateFlagErrors, CreateFlagRequest, CreateFlagResponse, CreateFlagResponses, CreateFunnelData, CreateFunnelErrors, CreateFunnelRequest, CreateFunnelResponse, CreateFunnelResponse2, CreateFunnelResponses, CreateFunnelStep, CreateGenericProviderData, CreateGenericProviderErrors, CreateGenericProviderResponse, CreateGenericProviderResponses, CreateGenericRequest, CreateGiteaPatProviderData, CreateGiteaPatProviderErrors, CreateGiteaPatProviderResponse, CreateGiteaPatProviderResponses, CreateGiteaPatRequest, CreateGithubPatProviderData, CreateGithubPatProviderErrors, CreateGithubPatProviderResponse, CreateGithubPatProviderResponses, CreateGitHubPatRequest, CreateGitlabOauthProviderData, CreateGitlabOauthProviderErrors, CreateGitlabOauthProviderResponse, CreateGitlabOauthProviderResponses, CreateGitLabOAuthRequest, CreateGitlabPatProviderData, CreateGitlabPatProviderErrors, CreateGitlabPatProviderResponse, CreateGitlabPatProviderResponses, CreateGitLabPatRequest, CreateGitProviderData, CreateGitProviderErrors, CreateGitProviderResponse, CreateGitProviderResponses, CreateGlobalMcpData, CreateGlobalMcpErrors, CreateGlobalMcpResponse, CreateGlobalMcpResponses, CreateGlobalSkillData, CreateGlobalSkillErrors, CreateGlobalSkillResponse, CreateGlobalSkillResponses, CreateIncidentData, CreateIncidentErrors, CreateIncidentRequest, CreateIncidentResponse, CreateIncidentResponses, CreateIntegrationBody, CreateIpAccessControlData, CreateIpAccessControlError, CreateIpAccessControlErrors, CreateIpAccessControlRequest, CreateIpAccessControlResponse, CreateIpAccessControlResponses, CreateMcpData, CreateMcpErrors, CreateMcpRequest, CreateMcpResponse, CreateMcpResponses, CreateMetricAlertRequest, CreateMonitorData, CreateMonitorErrors, CreateMonitorRequest, CreateMonitorResponse, CreateMonitorResponses, CreateNotificationEmailProviderData, CreateNotificationEmailProviderErrors, CreateNotificationEmailProviderRequest, CreateNotificationEmailProviderResponse, CreateNotificationEmailProviderResponses, CreateNotificationProviderData, CreateNotificationProviderErrors, CreateNotificationProviderResponse, CreateNotificationProviderResponses, CreateOidcProviderData, CreateOidcProviderErrors, CreateOidcProviderRequest, CreateOidcProviderResponse, CreateOidcProviderResponses, CreateOidcRoleMappingData, CreateOidcRoleMappingRequest, CreateOidcRoleMappingResponse, CreateOidcRoleMappingResponses, CreateOrRecreateOrderData, CreateOrRecreateOrderErrors, CreateOrRecreateOrderResponse, CreateOrRecreateOrderResponses, CreatePlanData, CreatePlanErrors, CreatePlanRequest, CreatePlanResponse, CreatePlanResponse2, CreatePlanResponses, CreatePrData, CreatePrErrors, CreateProjectAccessRequest, CreateProjectData, CreateProjectErrors, CreateProjectFromTemplateData, CreateProjectFromTemplateErrors, CreateProjectFromTemplateRequest, CreateProjectFromTemplateResponse, CreateProjectFromTemplateResponse2, CreateProjectFromTemplateResponses, CreateProjectReleaseData, CreateProjectReleaseErrors, CreateProjectReleaseResponse, CreateProjectReleaseResponses, CreateProjectRequest, CreateProjectResponse, CreateProjectResponses, CreateProjectSecretData, CreateProjectSecretErrors, CreateProjectSecretRequest, CreateProjectSecretResponse, CreateProjectSecretResponses, CreateProviderKeyData, CreateProviderKeyError, CreateProviderKeyErrors, CreateProviderKeyRequest, CreateProviderKeyResponse, CreateProviderKeyResponses, CreateProviderRequest, CreatePrResponse, CreatePrResponse2, CreatePrResponses, CreateReleaseData, CreateReleaseErrors, CreateReleaseResponse, CreateReleaseResponses, CreateRouteData, CreateRouteErrors, CreateRouteRequest, CreateRouteResponse, CreateRouteResponses, CreateS3SourceData, CreateS3SourceError, CreateS3SourceErrors, CreateS3SourceRequest, CreateS3SourceResponse, CreateS3SourceResponses, CreateSandboxBody, CreateSandboxData, CreateSandboxErrors, CreateSandboxResponse, CreateSandboxResponses, CreateServiceData, CreateServiceErrors, CreateServiceResponse, CreateServiceResponses, CreateSkillData, CreateSkillErrors, CreateSkillRequest, CreateSkillResponse, CreateSkillResponses, CreateSlackProviderData, CreateSlackProviderErrors, CreateSlackProviderRequest, CreateSlackProviderResponse, CreateSlackProviderResponses, CreateTeamData, CreateTeamErrors, CreateTeamMemberRequest, CreateTeamRequest, CreateTeamResponse, CreateTeamResponses, CreateUserData, CreateUserErrors, CreateUserRequest, CreateUserResponse, CreateUserResponses, CreateWebhookData, CreateWebhookErrors, CreateWebhookProviderData, CreateWebhookProviderErrors, CreateWebhookProviderRequest, CreateWebhookProviderResponse, CreateWebhookProviderResponses, CreateWebhookRequestBody, CreateWebhookResponse, CreateWebhookResponses, CronExecutionInfo, CronInfo, CrossProjectSiblingRef, CrossProjectTraceResponse, CurrentStatusResponse, CustomDomainRequest, CustomDomainResponse, CustomerMovementResponse, DashboardLayout, DashboardProjectsAnalyticsQuery, DashboardProjectsAnalyticsResponse, DashboardSection, DashboardTile, DatabaseMetricsResponse, DatabaseMetricsRow, DataImplication, DataImplicationSeverity, DeactivateApiKeyData, DeactivateApiKeyErrors, DeactivateApiKeyResponse, DeactivateApiKeyResponses, DeactivateConnectionData, DeactivateConnectionErrors, DeactivateConnectionResponses, DeactivateProviderData, DeactivateProviderErrors, DeactivateProviderResponses, DeleteAgentData, DeleteAgentErrors, DeleteAgentResponse, DeleteAgentResponses, DeleteAlertData, DeleteAlertError, DeleteAlertErrors, DeleteAlertResponse, DeleteAlertResponses, DeleteAlertRuleData, DeleteAlertRuleErrors, DeleteAlertRuleResponse, DeleteAlertRuleResponses, DeleteApiKeyData, DeleteApiKeyErrors, DeleteApiKeyResponse, DeleteApiKeyResponses, DeleteBackupData, DeleteBackupError, DeleteBackupErrors, DeleteBackupResponse, DeleteBackupResponses, DeleteBackupScheduleData, DeleteBackupScheduleError, DeleteBackupScheduleErrors, DeleteBackupScheduleResponse, DeleteBackupScheduleResponses, DeleteBlobRequest, DeleteBlobResponse, DeleteConnectionData, DeleteConnectionErrors, DeleteConnectionResponse, DeleteConnectionResponses, DeleteCustomDomainData, DeleteCustomDomainErrors, DeleteCustomDomainResponse, DeleteCustomDomainResponses, DeleteDashboardData, DeleteDashboardError, DeleteDashboardErrors, DeleteDashboardResponse, DeleteDashboardResponses, DeleteDeploymentTokenData, DeleteDeploymentTokenErrors, DeleteDeploymentTokenResponse, DeleteDeploymentTokenResponses, DeleteDnsProviderData, DeleteDnsProviderErrors, DeleteDnsProviderResponse, DeleteDnsProviderResponses, DeleteDomainData, DeleteDomainErrors, DeleteDomainResponse, DeleteDomainResponses, DeleteEmailDomainData, DeleteEmailDomainErrors, DeleteEmailDomainResponse, DeleteEmailDomainResponses, DeleteEmailProviderData, DeleteEmailProviderErrors, DeleteEmailProviderResponse, DeleteEmailProviderResponses, DeleteEnvironmentData, DeleteEnvironmentDomainData, DeleteEnvironmentDomainErrors, DeleteEnvironmentDomainResponse, DeleteEnvironmentDomainResponses, DeleteEnvironmentErrors, DeleteEnvironmentResponse, DeleteEnvironmentResponses, DeleteEnvironmentVariableData, DeleteEnvironmentVariableErrors, DeleteEnvironmentVariableResponse, DeleteEnvironmentVariableResponses, DeleteExternalImageData, DeleteExternalImageErrors, DeleteExternalImageResponse, DeleteExternalImageResponses, DeleteFunnelData, DeleteFunnelErrors, DeleteFunnelResponses, DeleteGitProviderData, DeleteGitProviderErrors, DeleteGitProviderResponse, DeleteGitProviderResponses, DeleteGlobalMcpData, DeleteGlobalMcpErrors, DeleteGlobalMcpResponse, DeleteGlobalMcpResponses, DeleteGlobalSkillData, DeleteGlobalSkillErrors, DeleteGlobalSkillResponse, DeleteGlobalSkillResponses, DeleteIpAccessControlData, DeleteIpAccessControlError, DeleteIpAccessControlErrors, DeleteIpAccessControlResponse, DeleteIpAccessControlResponses, DeleteMcpData, DeleteMcpErrors, DeleteMcpResponse, DeleteMcpResponses, DeleteMonitorData, DeleteMonitorErrors, DeleteMonitorResponse, DeleteMonitorResponses, DeleteNotificationProviderData, DeleteNotificationProviderErrors, DeleteNotificationProviderResponse, DeleteNotificationProviderResponses, DeleteOidcProviderData, DeleteOidcProviderResponse, DeleteOidcProviderResponses, DeleteOidcRoleMappingData, DeleteOidcRoleMappingResponse, DeleteOidcRoleMappingResponses, DeletePreferencesData, DeletePreferencesErrors, DeletePreferencesResponse, DeletePreferencesResponses, DeleteProjectData, DeleteProjectErrors, DeleteProjectResponse, DeleteProjectResponses, DeleteProjectSecretData, DeleteProjectSecretErrors, DeleteProjectSecretResponse, DeleteProjectSecretResponses, DeleteProviderKeyData, DeleteProviderKeyError, DeleteProviderKeyErrors, DeleteProviderKeyResponse, DeleteProviderKeyResponses, DeleteProviderSafelyData, DeleteProviderSafelyErrors, DeleteProviderSafelyResponse, DeleteProviderSafelyResponses, DeleteReleaseSourceFilesData, DeleteReleaseSourceFilesErrors, DeleteReleaseSourceFilesResponse, DeleteReleaseSourceFilesResponses, DeleteReleaseSourceMapsData, DeleteReleaseSourceMapsErrors, DeleteReleaseSourceMapsResponse, DeleteReleaseSourceMapsResponses, DeleteResponse, DeleteRouteData, DeleteRouteErrors, DeleteRouteResponse, DeleteRouteResponses, DeleteS3SourceData, DeleteS3SourceError, DeleteS3SourceErrors, DeleteS3SourceResponse, DeleteS3SourceResponses, DeleteScanData, DeleteScanError, DeleteScanErrors, DeleteScanResponse, DeleteScanResponses, DeleteSecretData, DeleteSecretErrors, DeleteSecretResponse, DeleteSecretResponses, DeleteServiceData, DeleteServiceErrors, DeleteServiceResponse, DeleteServiceResponses, DeleteSessionReplayData, DeleteSessionReplayError, DeleteSessionReplayErrors, DeleteSessionReplayResponses, DeleteSkillData, DeleteSkillErrors, DeleteSkillResponse, DeleteSkillResponses, DeleteSourceMapData, DeleteSourceMapErrors, DeleteSourceMapResponse, DeleteSourceMapResponses, DeleteStaticBundleData, DeleteStaticBundleErrors, DeleteStaticBundleResponse, DeleteStaticBundleResponses, DeleteTeamData, DeleteTeamErrors, DeleteTeamResponse, DeleteTeamResponses, DeleteUserData, DeleteUserErrors, DeleteUserResponse, DeleteUserResponses, DeleteWebhookData, DeleteWebhookErrors, DeleteWebhookResponse, DeleteWebhookResponses, DelRequest, DelResponse, DeployFromImageData, DeployFromImageErrors, DeployFromImageRequest, DeployFromImageResponse, DeployFromImageResponses, DeployFromImageUploadData, DeployFromImageUploadErrors, DeployFromImageUploadQuery, DeployFromImageUploadResponse, DeployFromImageUploadResponses, DeployFromStaticData, DeployFromStaticErrors, DeployFromStaticRequest, DeployFromStaticResponse, DeployFromStaticResponses, DeployFromUploadedSourceData, DeployFromUploadedSourceErrors, DeployFromUploadedSourceResponse, DeployFromUploadedSourceResponses, DeploymentConfig, DeploymentConfigSnapshot, DeploymentConfiguration, DeploymentContainerLogContentResponse, DeploymentContainerLogResponse, DeploymentContainerLogsListResponse, DeploymentEnvironmentResponse, DeploymentJobResponse, DeploymentJobsResponse, DeploymentListResponse, DeploymentMetadata, DeploymentMetricsGetLatestData, DeploymentMetricsGetLatestErrors, DeploymentMetricsGetLatestResponse, DeploymentMetricsGetLatestResponses, DeploymentMetricsGetRangeData, DeploymentMetricsGetRangeErrors, DeploymentMetricsGetRangeResponse, DeploymentMetricsGetRangeResponses, DeploymentMetricsToggleData, DeploymentMetricsToggleErrors, DeploymentMetricsToggleResponses, DeploymentResponse, DeploymentStateResponse, DeploymentStrategy, DeploymentTokenListResponse, DeploymentTokenResponse, DestroySandboxData, DestroySandboxErrors, DestroySandboxResponse, DestroySandboxResponses, DetachScheduleServiceData, DetachScheduleServiceError, DetachScheduleServiceErrors, DetachScheduleServiceResponse, DetachScheduleServiceResponses, DetectionConfig, DetectPublicPresetsData, DetectPublicPresetsErrors, DetectPublicPresetsResponse, DetectPublicPresetsResponses, DeviceCount, DigestSections, Direction, DisableBackupScheduleData, DisableBackupScheduleErrors, DisableBackupScheduleResponse, DisableBackupScheduleResponses, DisableBlobResponse, DisableKvResponse, DisableMfaData, DisableMfaErrors, DisableMfaRequest, DisableMfaResponse, DisableMfaResponses, DisconnectCloudData, DisconnectCloudResponse, DisconnectCloudResponses, DiscoverRequest, DiscoverResponse, DiscoverWorkloadsData, DiscoverWorkloadsErrors, DiscoverWorkloadsResponse, DiscoverWorkloadsResponses, DiskInfo, DiskSpaceAlert, DiskSpaceAlertSettings, DiskSpaceCheckResult, DnsAckRequest, DnsAckResponse, DnsChallengeRecordResult, DnsChangesResponse, DnsCompletionResponse, DnsLookupError, DnsLookupRequest, DnsLookupResponse, DnsProviderCredentials, DnsProviderResponse, DnsProviderSettings, DnsProviderSettingsMasked, DnsProviderType, DnsRecord, DnsRecordChange, DnsRecordContent, DnsRecordResponse, DnsRecordSetupResult, DnsRecordStatusResponse, DnsZone, DockerComposePresetConfig, DockerfilePresetConfig, DockerfileVariant, DockerRegistrySettings, DockerRegistrySettingsMasked, DomainAction, DomainChallengeResponse, DomainData, DomainEnvironmentResponse, DomainError, DomainErrors, DomainPlan, DomainResponse, DomainResponse2, DomainResponses, DownloadGlobalSkillArchiveData, DownloadGlobalSkillArchiveErrors, DownloadGlobalSkillArchiveResponse, DownloadGlobalSkillArchiveResponses, DownloadObjectData, DownloadObjectErrors, DownloadObjectResponse, DownloadObjectResponses, DownloadSkillArchiveData, DownloadSkillArchiveErrors, DownloadSkillArchiveResponse, DownloadSkillArchiveResponses, DrainNodeResponse, DrainStatusResponse, DropArchiveUpload, DropInspectionResponse, DropOffPoint, DropPresetCandidate, EmailConfig, EmailDomainResponse, EmailDomainWithDnsResponse, EmailProviderResponse, EmailProviderTypeRoute, EmailRequest, EmailResponse, EmailStatsResponse, EmailStatusData, EmailStatusErrors, EmailStatusResponse, EmailStatusResponse2, EmailStatusResponses, EmailTrackingResponse, EmailTrackingSetupResponse, EmailTrackingStatusResponse, EmbeddingData, EmbeddingInput, EmbeddingRequest, EmbeddingResponse, EmbeddingsData, EmbeddingsError, EmbeddingsErrors, EmbeddingsResponse, EmbeddingsResponses, EmbeddingUsage, EnableBackupScheduleData, EnableBackupScheduleErrors, EnableBackupScheduleResponse, EnableBackupScheduleResponses, EnableBlobRequest, EnableBlobResponse, EnableKvRequest, EnableKvResponse, EnablePgStatStatementsResponse, EndpointDto, EnqueuedJob, EnrichVisitorData, EnrichVisitorErrors, EnrichVisitorRequest, EnrichVisitorResponse, EnrichVisitorResponse2, EnrichVisitorResponses, EnrollCloudData, EnrollCloudRequest, EnrollCloudResponse, EnrollCloudResponses, EnrollmentTokenInfo, EnrollmentTokenListResponse, EntityInfoResponse, EntityResponse, EnvironmentConfiguration, EnvironmentDomainResponse, EnvironmentInfo, EnvironmentResponse, EnvironmentVariable, EnvironmentVariableInfo, EnvironmentVariableResponse, EnvironmentVariableValueResponse, EnvVarInput, EnvVarIntegrationInfo, EnvVarResponse, EnvVarTemplateResponse, ErrorDashboardStatsQuery, ErrorDashboardStatsResponse, ErrorEventResponse, ErrorGroupResponse, ErrorGroupStatsResponse, ErrorResponse, ErrorRow, ErrorTimeSeriesDataResponse, ErrorTimeSeriesQuery, EventActivityBucket, EventBreakdown, EventBrowserStats, EventCount, EventCountryStats, EventDetailQuery, EventDetailResponse, EventEntriesQuery, EventEntriesResponse, EventEntryInfo, EventKind, EventMetricsPayload, EventReferrerStats, EventsCountQuery, EventsResponse, EventTimeline, EventTimelineQuery, EventType, EventTypeBreakdown, EventTypeBreakdownQuery, EventTypeResponse, EventTypesResponse, EventVisitorInfo, EventVisitorsQuery, EventVisitorsResponse, ExecBody, ExecData, ExecDetachedData, ExecDetachedErrors, ExecDetachedResponse, ExecDetachedResponse2, ExecDetachedResponses, ExecErrors, ExecResponse, ExecResponse2, ExecResponses, ExecuteDeploymentOperationData, ExecuteDeploymentOperationErrors, ExecuteDeploymentOperationResponse, ExecuteDeploymentOperationResponses, ExecuteImportData, ExecuteImportErrors, ExecuteImportRequest, ExecuteImportResponse, ExecuteImportResponse2, ExecuteImportResponses, ExecuteOperationRequest, ExpireRequest, ExpireResponse, ExplorerSupportResponse, ExtendTimeoutBody, ExtendTimeoutData, ExtendTimeoutErrors, ExtendTimeoutResponse, ExtendTimeoutResponses, ExternalImageResponse, ExternalServiceBackupResponse, ExternalServiceDetails, ExternalServiceEnablePgStatStatementsData, ExternalServiceEnablePgStatStatementsErrors, ExternalServiceEnablePgStatStatementsResponse, ExternalServiceEnablePgStatStatementsResponses, ExternalServiceInfo, ExternalServiceMetricsByDatabaseData, ExternalServiceMetricsByDatabaseErrors, ExternalServiceMetricsByDatabaseResponse, ExternalServiceMetricsByDatabaseResponses, ExternalServiceMetricsCreateAlertRuleData, ExternalServiceMetricsCreateAlertRuleErrors, ExternalServiceMetricsCreateAlertRuleResponse, ExternalServiceMetricsCreateAlertRuleResponses, ExternalServiceMetricsDeleteAlertRuleData, ExternalServiceMetricsDeleteAlertRuleErrors, ExternalServiceMetricsDeleteAlertRuleResponse, ExternalServiceMetricsDeleteAlertRuleResponses, ExternalServiceMetricsGetAlertRulesData, ExternalServiceMetricsGetAlertRulesErrors, ExternalServiceMetricsGetAlertRulesResponse, ExternalServiceMetricsGetAlertRulesResponses, ExternalServiceMetricsGetLatestData, ExternalServiceMetricsGetLatestErrors, ExternalServiceMetricsGetLatestResponse, ExternalServiceMetricsGetLatestResponses, ExternalServiceMetricsGetRangeData, ExternalServiceMetricsGetRangeErrors, ExternalServiceMetricsGetRangeResponse, ExternalServiceMetricsGetRangeResponses, ExternalServiceMetricsStatusData, ExternalServiceMetricsStatusErrors, ExternalServiceMetricsStatusResponse, ExternalServiceMetricsStatusResponses, ExternalServiceMetricsToggleData, ExternalServiceMetricsToggleErrors, ExternalServiceMetricsToggleResponses, ExternalServiceMetricsUpdateAlertRuleData, ExternalServiceMetricsUpdateAlertRuleErrors, ExternalServiceMetricsUpdateAlertRuleResponse, ExternalServiceMetricsUpdateAlertRuleResponses, ExternalServiceResetPgStatStatementsData, ExternalServiceResetPgStatStatementsErrors, ExternalServiceResetPgStatStatementsResponse, ExternalServiceResetPgStatStatementsResponses, ExternalServiceSummary, FieldResponse, FinalizeOrderData, FinalizeOrderErrors, FinalizeOrderResponse, FinalizeOrderResponses, FinalizeProjectReleaseData, FinalizeProjectReleaseErrors, FinalizeProjectReleaseResponse, FinalizeProjectReleaseResponses, FindConversationData, FindConversationErrors, FindConversationResponse, FindConversationResponses, FiringSeriesEntry, FlagEnvironmentResponse, FlagListResponse, FlagResponse, FlagSnapshot, FlagSnapshotResponse, FlagValueType, ForecastAlgorithm, ForecastParams, FullError, FullEvent, FullRequest, FunnelMetricsResponse, FunnelResponse, GatewayStatus, GenAiEvent, GenAiSpanDetail, GenAiTraceDetailResponse, GenAiTraceSummariesResponse, GenAiTraceSummary, GeneralStatsQuery, GeneralStatsResponse, GenerateDockerfileRequest, GenerateDockerfileResponse, GenerateJoinTokenData, GenerateJoinTokenErrors, GenerateJoinTokenResponse, GenerateJoinTokenResponse2, GenerateJoinTokenResponses, GeneratePresetDockerfileData, GeneratePresetDockerfileErrors, GeneratePresetDockerfileResponse, GeneratePresetDockerfileResponses, GeoLocationResponse, GeoRestrictionsConfig, GetAccessInfoData, GetAccessInfoErrors, GetAccessInfoResponse, GetAccessInfoResponses, GetActiveVisitorsData, GetActiveVisitorsErrors, GetActiveVisitorsResponse, GetActiveVisitorsResponses, GetActivityGraphData, GetActivityGraphErrors, GetActivityGraphResponse, GetActivityGraphResponses, GetAdminGateData, GetAdminGateErrors, GetAdminGateResponse, GetAdminGateResponses, GetAgentData, GetAgentErrors, GetAgentResponse, GetAgentResponses, GetAggregatedBucketsData, GetAggregatedBucketsErrors, GetAggregatedBucketsResponse, GetAggregatedBucketsResponses, GetAiAgentBreakdownData, GetAiAgentBreakdownError, GetAiAgentBreakdownErrors, GetAiAgentBreakdownResponse, GetAiAgentBreakdownResponses, GetAiAgentPagesData, GetAiAgentPagesError, GetAiAgentPagesErrors, GetAiAgentPagesResponse, GetAiAgentPagesResponses, GetAiAgentTimelineData, GetAiAgentTimelineError, GetAiAgentTimelineErrors, GetAiAgentTimelineResponse, GetAiAgentTimelineResponses, GetAiPageBreakdownData, GetAiPageBreakdownError, GetAiPageBreakdownErrors, GetAiPageBreakdownResponse, GetAiPageBreakdownResponses, GetAiStatusBreakdownData, GetAiStatusBreakdownError, GetAiStatusBreakdownErrors, GetAiStatusBreakdownResponse, GetAiStatusBreakdownResponses, GetAlertData, GetAlertError, GetAlertErrors, GetAlertResponse, GetAlertResponses, GetAlertRuleData, GetAlertRuleErrors, GetAlertRuleResponse, GetAlertRuleResponses, GetAllRepositoriesByNameData, GetAllRepositoriesByNameErrors, GetAllRepositoriesByNameResponse, GetAllRepositoriesByNameResponses, GetAnalyticsActiveVisitorsData, GetAnalyticsActiveVisitorsErrors, GetAnalyticsActiveVisitorsResponse, GetAnalyticsActiveVisitorsResponses, GetAnalyticsEventsCountData, GetAnalyticsEventsCountErrors, GetAnalyticsEventsCountResponse, GetAnalyticsEventsCountResponses, GetAnalyticsSessionEventsData, GetAnalyticsSessionEventsErrors, GetAnalyticsSessionEventsResponse, GetAnalyticsSessionEventsResponses, GetAnalyticsVisitorSessionsData, GetAnalyticsVisitorSessionsErrors, GetAnalyticsVisitorSessionsResponse, GetAnalyticsVisitorSessionsResponses, GetApiKeyData, GetApiKeyErrors, GetApiKeyPermissionsData, GetApiKeyPermissionsErrors, GetApiKeyPermissionsResponse, GetApiKeyPermissionsResponses, GetApiKeyResponse, GetApiKeyResponses, GetAuditLogData, GetAuditLogErrors, GetAuditLogResponse, GetAuditLogResponses, GetBackupData, GetBackupError, GetBackupErrors, GetBackupResponse, GetBackupResponses, GetBackupScheduleData, GetBackupScheduleErrors, GetBackupScheduleResponse, GetBackupScheduleResponses, GetBranchesByRepositoryIdData, GetBranchesByRepositoryIdErrors, GetBranchesByRepositoryIdResponse, GetBranchesByRepositoryIdResponses, GetBucketedIncidentsData, GetBucketedIncidentsErrors, GetBucketedIncidentsResponse, GetBucketedIncidentsResponses, GetBucketedStatusData, GetBucketedStatusErrors, GetBucketedStatusResponse, GetBucketedStatusResponses, GetChallengeTokenData, GetChallengeTokenErrors, GetChallengeTokenResponse, GetChallengeTokenResponses, GetChatReadinessData, GetChatReadinessErrors, GetChatReadinessResponse, GetChatReadinessResponses, GetCliStatusData, GetCliStatusErrors, GetCliStatusResponses, GetCloudCapabilityData, GetCloudCapabilityResponse, GetCloudCapabilityResponses, GetCloudStatusData, GetCloudStatusResponse, GetCloudStatusResponses, GetClusterHealthData, GetClusterHealthErrors, GetClusterHealthResponse, GetClusterHealthResponses, GetClusterMemberData, GetClusterMemberErrors, GetClusterMemberResponse, GetClusterMemberResponses, GetCmdData, GetCmdErrors, GetCmdResponse, GetCmdResponses, GetContainerDetailData, GetContainerDetailErrors, GetContainerDetailResponse, GetContainerDetailResponses, GetContainerEnvironmentVariableData, GetContainerEnvironmentVariableErrors, GetContainerEnvironmentVariableResponse, GetContainerEnvironmentVariableResponses, GetContainerInfoData, GetContainerInfoErrors, GetContainerInfoResponse, GetContainerInfoResponses, GetContainerLogsByIdData, GetContainerLogsByIdErrors, GetContainerLogsData, GetContainerLogsErrors, GetContainerMetricsData, GetContainerMetricsErrors, GetContainerMetricsResponse, GetContainerMetricsResponses, GetConversationData, GetConversationDetailData, GetConversationDetailError, GetConversationDetailErrors, GetConversationDetailResponse, GetConversationDetailResponses, GetConversationErrors, GetConversationResponse, GetConversationResponses, GetConversationsData, GetConversationsError, GetConversationsErrors, GetConversationsResponse, GetConversationsResponses, GetCronByIdData, GetCronByIdErrors, GetCronByIdResponse, GetCronByIdResponses, GetCronExecutionsData, GetCronExecutionsErrors, GetCronExecutionsResponse, GetCronExecutionsResponses, GetCrossProjectTraceSiblingsData, GetCrossProjectTraceSiblingsError, GetCrossProjectTraceSiblingsErrors, GetCrossProjectTraceSiblingsResponse, GetCrossProjectTraceSiblingsResponses, GetCurrentMonitorStatusData, GetCurrentMonitorStatusErrors, GetCurrentMonitorStatusResponse, GetCurrentMonitorStatusResponses, GetCurrentUserData, GetCurrentUserErrors, GetCurrentUserResponse, GetCurrentUserResponses, GetCustomDomainData, GetCustomDomainErrors, GetCustomDomainResponse, GetCustomDomainResponses, GetDashboardData, GetDashboardError, GetDashboardErrors, GetDashboardProjectsAnalyticsData, GetDashboardProjectsAnalyticsErrors, GetDashboardProjectsAnalyticsResponse, GetDashboardProjectsAnalyticsResponses, GetDashboardResponse, GetDashboardResponses, GetDeliveryData, GetDeliveryErrors, GetDeliveryResponse, GetDeliveryResponses, GetDeploymentContainerLogContentData, GetDeploymentContainerLogContentErrors, GetDeploymentContainerLogContentResponse, GetDeploymentContainerLogContentResponses, GetDeploymentData, GetDeploymentErrors, GetDeploymentJobLogsData, GetDeploymentJobLogsErrors, GetDeploymentJobLogsResponse, GetDeploymentJobLogsResponses, GetDeploymentJobsData, GetDeploymentJobsErrors, GetDeploymentJobsResponse, GetDeploymentJobsResponses, GetDeploymentOperationsData, GetDeploymentOperationsErrors, GetDeploymentOperationsResponse, GetDeploymentOperationsResponses, GetDeploymentOperationStatusData, GetDeploymentOperationStatusErrors, GetDeploymentOperationStatusResponse, GetDeploymentOperationStatusResponses, GetDeploymentResponse, GetDeploymentResponses, GetDeploymentsParams, GetDeploymentTokenData, GetDeploymentTokenErrors, GetDeploymentTokenResponse, GetDeploymentTokenResponses, GetDiskStatusData, GetDiskStatusErrors, GetDiskStatusResponse, GetDiskStatusResponses, GetDnsChangesData, GetDnsChangesErrors, GetDnsChangesResponse, GetDnsChangesResponses, GetDnsProviderData, GetDnsProviderErrors, GetDnsProviderResponse, GetDnsProviderResponses, GetDomainByHostData, GetDomainByHostErrors, GetDomainByHostResponse, GetDomainByHostResponses, GetDomainByIdData, GetDomainByIdErrors, GetDomainByIdResponse, GetDomainByIdResponses, GetDomainByNameData, GetDomainByNameErrors, GetDomainByNameResponse, GetDomainByNameResponses, GetDomainData, GetDomainDnsRecordsData, GetDomainDnsRecordsErrors, GetDomainDnsRecordsResponse, GetDomainDnsRecordsResponses, GetDomainErrors, GetDomainOrderData, GetDomainOrderErrors, GetDomainOrderResponse, GetDomainOrderResponses, GetDomainResponse, GetDomainResponses, GetEmailData, GetEmailErrors, GetEmailEventsData, GetEmailEventsErrors, GetEmailEventsResponse, GetEmailEventsResponses, GetEmailLinksData, GetEmailLinksErrors, GetEmailLinksResponse, GetEmailLinksResponses, GetEmailProviderData, GetEmailProviderErrors, GetEmailProviderResponse, GetEmailProviderResponses, GetEmailResponse, GetEmailResponses, GetEmailStatsData, GetEmailStatsErrors, GetEmailStatsResponse, GetEmailStatsResponses, GetEmailTrackingData, GetEmailTrackingErrors, GetEmailTrackingResponse, GetEmailTrackingResponses, GetEmailTrackingStatusData, GetEmailTrackingStatusErrors, GetEmailTrackingStatusResponse, GetEmailTrackingStatusResponses, GetEntityInfoData, GetEntityInfoErrors, GetEntityInfoResponse, GetEntityInfoResponses, GetEnvironmentCronsData, GetEnvironmentCronsErrors, GetEnvironmentCronsResponse, GetEnvironmentCronsResponses, GetEnvironmentData, GetEnvironmentDomainsData, GetEnvironmentDomainsErrors, GetEnvironmentDomainsResponse, GetEnvironmentDomainsResponses, GetEnvironmentErrors, GetEnvironmentResponse, GetEnvironmentResponses, GetEnvironmentsData, GetEnvironmentsErrors, GetEnvironmentsResponse, GetEnvironmentsResponses, GetEnvironmentVariablesData, GetEnvironmentVariablesErrors, GetEnvironmentVariablesQuery, GetEnvironmentVariablesResponse, GetEnvironmentVariablesResponses, GetEnvironmentVariableValueData, GetEnvironmentVariableValueErrors, GetEnvironmentVariableValueResponse, GetEnvironmentVariableValueResponses, GetErrorDashboardStatsData, GetErrorDashboardStatsErrors, GetErrorDashboardStatsResponse, GetErrorDashboardStatsResponses, GetErrorEventData, GetErrorEventErrors, GetErrorEventResponse, GetErrorEventResponses, GetErrorGroupData, GetErrorGroupErrors, GetErrorGroupResponse, GetErrorGroupResponses, GetErrorStatsData, GetErrorStatsErrors, GetErrorStatsResponse, GetErrorStatsResponses, GetErrorTimeSeriesData, GetErrorTimeSeriesErrors, GetErrorTimeSeriesResponse, GetErrorTimeSeriesResponses, GetEventDetailData, GetEventDetailErrors, GetEventDetailResponse, GetEventDetailResponses, GetEventEntriesData, GetEventEntriesErrors, GetEventEntriesResponse, GetEventEntriesResponses, GetEventsCountData, GetEventsCountErrors, GetEventsCountResponse, GetEventsCountResponses, GetEventsTimelineData, GetEventsTimelineErrors, GetEventsTimelineResponse, GetEventsTimelineResponses, GetEventTypeBreakdownData, GetEventTypeBreakdownErrors, GetEventTypeBreakdownResponse, GetEventTypeBreakdownResponses, GetEventVisitorsData, GetEventVisitorsErrors, GetEventVisitorsResponse, GetEventVisitorsResponses, GetExternalImageData, GetExternalImageErrors, GetExternalImageResponse, GetExternalImageResponses, GetFileData, GetFileErrors, GetFileResponse, GetFileResponses, GetFlagData, GetFlagErrors, GetFlagResponse, GetFlagResponses, GetFlagSnapshotData, GetFlagSnapshotErrors, GetFlagSnapshotResponse, GetFlagSnapshotResponses, GetFunnelMetricsData, GetFunnelMetricsErrors, GetFunnelMetricsQuery, GetFunnelMetricsResponse, GetFunnelMetricsResponses, GetGenaiTraceData, GetGenaiTraceError, GetGenaiTraceErrors, GetGenaiTraceResponse, GetGenaiTraceResponses, GetGeneralStatsData, GetGeneralStatsErrors, GetGeneralStatsResponse, GetGeneralStatsResponses, GetGitProviderData, GetGitProviderErrors, GetGitProviderResponse, GetGitProviderResponses, GetGlobalEventsData, GetGlobalEventsErrors, GetGlobalEventsResponse, GetGlobalEventsResponses, GetGlobalEventStatsData, GetGlobalEventStatsErrors, GetGlobalEventStatsResponse, GetGlobalEventStatsResponses, GetGlobalMcpData, GetGlobalMcpErrors, GetGlobalMcpResponse, GetGlobalMcpResponses, GetGlobalSandboxStatusData, GetGlobalSandboxStatusErrors, GetGlobalSandboxStatusResponse, GetGlobalSandboxStatusResponses, GetGlobalSkillData, GetGlobalSkillErrors, GetGlobalSkillResponse, GetGlobalSkillResponses, GetGroupedPageMetricsData, GetGroupedPageMetricsError, GetGroupedPageMetricsErrors, GetGroupedPageMetricsResponse, GetGroupedPageMetricsResponses, GetHealthData, GetHealthError, GetHealthErrors, GetHealthResponse, GetHealthResponses, GetHourlyVisitsData, GetHourlyVisitsErrors, GetHourlyVisitsResponse, GetHourlyVisitsResponses, GetHttpChallengeDebugData, GetHttpChallengeDebugErrors, GetHttpChallengeDebugResponse, GetHttpChallengeDebugResponses, GetImportStatusData, GetImportStatusErrors, GetImportStatusResponse, GetImportStatusResponses, GetIncidentData, GetIncidentErrors, GetIncidentResponse, GetIncidentResponses, GetIncidentUpdatesData, GetIncidentUpdatesErrors, GetIncidentUpdatesResponse, GetIncidentUpdatesResponses, GetIpAccessControlData, GetIpAccessControlError, GetIpAccessControlErrors, GetIpAccessControlResponse, GetIpAccessControlResponses, GetIpGeolocationData, GetIpGeolocationError, GetIpGeolocationErrors, GetIpGeolocationResponse, GetIpGeolocationResponses, GetJoinTokenStatusData, GetJoinTokenStatusErrors, GetJoinTokenStatusResponse, GetJoinTokenStatusResponses, GetLastDeploymentData, GetLastDeploymentErrors, GetLastDeploymentResponse, GetLastDeploymentResponses, GetLatestScanData, GetLatestScanError, GetLatestScanErrors, GetLatestScanResponse, GetLatestScanResponses, GetLatestScansPerEnvironmentData, GetLatestScansPerEnvironmentError, GetLatestScansPerEnvironmentErrors, GetLatestScansPerEnvironmentResponse, GetLatestScansPerEnvironmentResponses, GetLiveVisitorsListData, GetLiveVisitorsListErrors, GetLiveVisitorsListResponse, GetLiveVisitorsListResponses, GetLogContextData, GetLogContextError, GetLogContextErrors, GetLogContextResponse, GetLogContextResponses, GetMcpData, GetMcpErrors, GetMcpResponse, GetMcpResponses, GetMetricsOverTimeData, GetMetricsOverTimeError, GetMetricsOverTimeErrors, GetMetricsOverTimeResponse, GetMetricsOverTimeResponses, GetMonitorData, GetMonitorErrors, GetMonitorResponse, GetMonitorResponses, GetNotificationProviderData, GetNotificationProviderErrors, GetNotificationProviderResponse, GetNotificationProviderResponses, GetOnDemandCertStatusData, GetOnDemandCertStatusErrors, GetOnDemandCertStatusResponse, GetOnDemandCertStatusResponses, GetOrCreateDsnData, GetOrCreateDsnErrors, GetOrCreateDsnRequest, GetOrCreateDsnResponse, GetOrCreateDsnResponses, GetPageFlowData, GetPageFlowErrors, GetPageFlowResponse, GetPageFlowResponses, GetPageHourlySessionsData, GetPageHourlySessionsErrors, GetPageHourlySessionsResponse, GetPageHourlySessionsResponses, GetPagePathDetailData, GetPagePathDetailErrors, GetPagePathDetailResponse, GetPagePathDetailResponses, GetPagePathsData, GetPagePathsErrors, GetPagePathsResponse, GetPagePathsResponses, GetPagePathsSparklinesData, GetPagePathsSparklinesErrors, GetPagePathsSparklinesResponse, GetPagePathsSparklinesResponses, GetPagePathVisitorsData, GetPagePathVisitorsErrors, GetPagePathVisitorsResponse, GetPagePathVisitorsResponses, GetPendingActionData, GetPendingActionErrors, GetPendingActionResponse, GetPendingActionResponses, GetPerformanceMetricsData, GetPerformanceMetricsError, GetPerformanceMetricsErrors, GetPerformanceMetricsResponse, GetPerformanceMetricsResponses, GetPgUpgradeData, GetPgUpgradeErrors, GetPgUpgradeLogsData, GetPgUpgradeLogsErrors, GetPgUpgradeLogsResponse, GetPgUpgradeLogsResponses, GetPgUpgradeResponse, GetPgUpgradeResponses, GetPipelineStatsData, GetPipelineStatsError, GetPipelineStatsErrors, GetPipelineStatsResponse, GetPipelineStatsResponses, GetPlatformInfoData, GetPlatformInfoErrors, GetPlatformInfoResponse, GetPlatformInfoResponses, GetPostgresWalHealthData, GetPostgresWalHealthErrors, GetPostgresWalHealthResponse, GetPostgresWalHealthResponses, GetPreferencesData, GetPreferencesErrors, GetPreferencesResponse, GetPreferencesResponses, GetPreviewGatewayLogsData, GetPreviewGatewayLogsResponse, GetPreviewGatewayLogsResponses, GetPreviewGatewaySettingsData, GetPreviewGatewaySettingsResponse, GetPreviewGatewaySettingsResponses, GetPreviewGatewayStatusData, GetPreviewGatewayStatusResponse, GetPreviewGatewayStatusResponses, GetPricingData, GetPricingError, GetPricingErrors, GetPricingResponse, GetPricingResponses, GetPrivateIpData, GetPrivateIpErrors, GetPrivateIpResponses, GetProjectAlarmsSummaryData, GetProjectAlarmsSummaryErrors, GetProjectAlarmsSummaryResponse, GetProjectAlarmsSummaryResponses, GetProjectBySlugData, GetProjectBySlugErrors, GetProjectBySlugResponse, GetProjectBySlugResponses, GetProjectData, GetProjectDeploymentsData, GetProjectDeploymentsErrors, GetProjectDeploymentsResponse, GetProjectDeploymentsResponses, GetProjectErrors, GetProjectResponse, GetProjectResponses, GetProjectsData, GetProjectSecretsQuery, GetProjectsErrors, GetProjectServiceEnvironmentVariablesData, GetProjectServiceEnvironmentVariablesErrors, GetProjectServiceEnvironmentVariablesResponse, GetProjectServiceEnvironmentVariablesResponses, GetProjectSessionReplaysData, GetProjectSessionReplaysError, GetProjectSessionReplaysErrors, GetProjectSessionReplaysQuery, GetProjectSessionReplaysResponse, GetProjectSessionReplaysResponse2, GetProjectSessionReplaysResponses, GetProjectsHealthData, GetProjectsHealthError, GetProjectsHealthErrors, GetProjectsHealthResponse, GetProjectsHealthResponses, GetProjectsMonitorHealthData, GetProjectsMonitorHealthErrors, GetProjectsMonitorHealthResponse, GetProjectsMonitorHealthResponses, GetProjectsResponse, GetProjectsResponses, GetProjectStatisticsData, GetProjectStatisticsErrors, GetProjectStatisticsResponse, GetProjectStatisticsResponses, GetProjectTemplateData, GetProjectTemplateErrors, GetProjectTemplateResponse, GetProjectTemplateResponses, GetPropertyBreakdownData, GetPropertyBreakdownErrors, GetPropertyBreakdownResponse, GetPropertyBreakdownResponses, GetPropertyTimelineData, GetPropertyTimelineErrors, GetPropertyTimelineResponse, GetPropertyTimelineResponses, GetProviderConnectionsData, GetProviderConnectionsErrors, GetProviderConnectionsResponse, GetProviderConnectionsResponses, GetProviderMetadataData, GetProviderMetadataErrors, GetProviderMetadataResponse, GetProviderMetadataResponses, GetProvidersMetadataData, GetProvidersMetadataErrors, GetProvidersMetadataResponse, GetProvidersMetadataResponses, GetProxyLogByIdData, GetProxyLogByIdError, GetProxyLogByIdErrors, GetProxyLogByIdResponse, GetProxyLogByIdResponses, GetProxyLogByRequestIdData, GetProxyLogByRequestIdError, GetProxyLogByRequestIdErrors, GetProxyLogByRequestIdResponse, GetProxyLogByRequestIdResponses, GetProxyLogsData, GetProxyLogsError, GetProxyLogsErrors, GetProxyLogsResponse, GetProxyLogsResponses, GetPublicBranchesData, GetPublicBranchesErrors, GetPublicBranchesResponse, GetPublicBranchesResponses, GetPublicIpData, GetPublicIpErrors, GetPublicIpResponses, GetPublicRepositoryData, GetPublicRepositoryErrors, GetPublicRepositoryResponse, GetPublicRepositoryResponses, GetQuotaData, GetQuotaError, GetQuotaErrors, GetQuotaResponse, GetQuotaResponses, GetRecentActivityData, GetRecentActivityErrors, GetRecentActivityResponse, GetRecentActivityResponses, GetRemoteExternalImageData, GetRemoteExternalImageErrors, GetRemoteExternalImageResponse, GetRemoteExternalImageResponses, GetRepositoryBranchesData, GetRepositoryBranchesErrors, GetRepositoryBranchesResponse, GetRepositoryBranchesResponses, GetRepositoryByIdData, GetRepositoryByIdErrors, GetRepositoryByIdResponse, GetRepositoryByIdResponses, GetRepositoryByNameData, GetRepositoryByNameErrors, GetRepositoryByNameResponse, GetRepositoryByNameResponses, GetRepositoryPresetByNameData, GetRepositoryPresetByNameErrors, GetRepositoryPresetByNameResponse, GetRepositoryPresetByNameResponses, GetRepositoryPresetLiveData, GetRepositoryPresetLiveErrors, GetRepositoryPresetLiveResponse, GetRepositoryPresetLiveResponses, GetRepositoryTagsData, GetRepositoryTagsErrors, GetRepositoryTagsResponse, GetRepositoryTagsResponses, GetRequest, GetResolvedEnvironmentVariablesData, GetResolvedEnvironmentVariablesErrors, GetResolvedEnvironmentVariablesResponse, GetResolvedEnvironmentVariablesResponses, GetResolvedEnvironmentVariableValueData, GetResolvedEnvironmentVariableValueErrors, GetResolvedEnvironmentVariableValueResponse, GetResolvedEnvironmentVariableValueResponses, GetResponse, GetRestoreCapabilitiesData, GetRestoreCapabilitiesError, GetRestoreCapabilitiesErrors, GetRestoreCapabilitiesResponse, GetRestoreCapabilitiesResponses, GetRestoreRunData, GetRestoreRunError, GetRestoreRunErrors, GetRestoreRunResponse, GetRestoreRunResponses, GetRouteData, GetRouteErrors, GetRouteResponse, GetRouteResponses, GetRunData, GetRunErrors, GetRunResponse, GetRunResponses, GetRunWithLogsData, GetRunWithLogsErrors, GetRunWithLogsResponse, GetRunWithLogsResponses, GetS3CredentialsData, GetS3CredentialsErrors, GetS3CredentialsResponse, GetS3CredentialsResponses, GetS3SourceData, GetS3SourceError, GetS3SourceErrors, GetS3SourceResponse, GetS3SourceResponses, GetSandboxData, GetSandboxErrors, GetSandboxResponse, GetSandboxResponses, GetSandboxStatusData, GetSandboxStatusErrors, GetSandboxStatusResponse, GetSandboxStatusResponses, GetScanByDeploymentData, GetScanByDeploymentError, GetScanByDeploymentErrors, GetScanByDeploymentResponse, GetScanByDeploymentResponses, GetScanData, GetScanError, GetScanErrors, GetScanResponse, GetScanResponses, GetScanVulnerabilitiesData, GetScanVulnerabilitiesError, GetScanVulnerabilitiesErrors, GetScanVulnerabilitiesResponse, GetScanVulnerabilitiesResponses, GetServiceBySlugData, GetServiceBySlugErrors, GetServiceBySlugResponse, GetServiceBySlugResponses, GetServiceData, GetServiceEnvironmentVariableData, GetServiceEnvironmentVariableErrors, GetServiceEnvironmentVariableResponse, GetServiceEnvironmentVariableResponses, GetServiceEnvironmentVariablesData, GetServiceEnvironmentVariablesErrors, GetServiceEnvironmentVariablesResponse, GetServiceEnvironmentVariablesResponses, GetServiceErrors, GetServiceHealthStatusData, GetServiceHealthStatusErrors, GetServiceHealthStatusResponse, GetServiceHealthStatusResponses, GetServicePreviewEnvironmentVariableNamesData, GetServicePreviewEnvironmentVariableNamesErrors, GetServicePreviewEnvironmentVariableNamesResponse, GetServicePreviewEnvironmentVariableNamesResponses, GetServicePreviewEnvironmentVariablesMaskedData, GetServicePreviewEnvironmentVariablesMaskedErrors, GetServicePreviewEnvironmentVariablesMaskedResponse, GetServicePreviewEnvironmentVariablesMaskedResponses, GetServiceResponse, GetServiceResponses, GetServiceRuntimeData, GetServiceRuntimeErrors, GetServiceRuntimeResponse, GetServiceRuntimeResponses, GetServiceStatsData, GetServiceStatsErrors, GetServiceStatsResponse, GetServiceStatsResponses, GetServiceTypeParametersData, GetServiceTypeParametersErrors, GetServiceTypeParametersResponses, GetServiceTypesData, GetServiceTypesErrors, GetServiceTypesResponse, GetServiceTypesResponses, GetSessionDetailsData, GetSessionDetailsErrors, GetSessionDetailsResponse, GetSessionDetailsResponses, GetSessionEventsData, GetSessionEventsErrors, GetSessionEventsResponse, GetSessionEventsResponses, GetSessionLogsData, GetSessionLogsErrors, GetSessionLogsResponse, GetSessionLogsResponses, GetSessionReplayData, GetSessionReplayError, GetSessionReplayErrors, GetSessionReplayEventsData, GetSessionReplayEventsError, GetSessionReplayEventsErrors, GetSessionReplayEventsResponse, GetSessionReplayEventsResponses, GetSessionReplayResponse, GetSessionReplayResponse2, GetSessionReplayResponses, GetSettingsData, GetSettingsErrors, GetSettingsResponse, GetSettingsResponses, GetSkillData, GetSkillErrors, GetSkillResponse, GetSkillResponses, GetSlowQueriesData, GetSlowQueriesErrors, GetSlowQueriesResponse, GetSlowQueriesResponses, GetStaticBundleData, GetStaticBundleErrors, GetStaticBundleResponse, GetStaticBundleResponses, GetStatusOverviewData, GetStatusOverviewErrors, GetStatusOverviewResponse, GetStatusOverviewResponses, GetTagsByRepositoryIdData, GetTagsByRepositoryIdErrors, GetTagsByRepositoryIdResponse, GetTagsByRepositoryIdResponses, GetTeamData, GetTeamErrors, GetTeamResponse, GetTeamResponses, GetTimeBucketStatsData, GetTimeBucketStatsError, GetTimeBucketStatsErrors, GetTimeBucketStatsResponse, GetTimeBucketStatsResponses, GetTodayStatsData, GetTodayStatsError, GetTodayStatsErrors, GetTodayStatsResponse, GetTodayStatsResponses, GetTraceData, GetTraceError, GetTraceErrors, GetTraceResponse, GetTraceResponses, GetUnifiedTraceData, GetUnifiedTraceError, GetUnifiedTraceErrors, GetUnifiedTraceResponse, GetUnifiedTraceResponses, GetUniqueCountsData, GetUniqueCountsErrors, GetUniqueCountsResponse, GetUniqueCountsResponses, GetUniqueEventsData, GetUniqueEventsErrors, GetUniqueEventsQuery, GetUniqueEventsResponse, GetUniqueEventsResponses, GetUpdateStatusData, GetUpdateStatusErrors, GetUpdateStatusResponse, GetUpdateStatusResponses, GetUptimeHistoryData, GetUptimeHistoryErrors, GetUptimeHistoryResponse, GetUptimeHistoryResponses, GetUsageByProviderData, GetUsageByProviderError, GetUsageByProviderErrors, GetUsageByProviderResponse, GetUsageByProviderResponses, GetUsageRecentData, GetUsageRecentError, GetUsageRecentErrors, GetUsageRecentResponse, GetUsageRecentResponses, GetUsageSummaryData, GetUsageSummaryError, GetUsageSummaryErrors, GetUsageSummaryResponse, GetUsageSummaryResponses, GetUsageTimeseriesData, GetUsageTimeseriesError, GetUsageTimeseriesErrors, GetUsageTimeseriesResponse, GetUsageTimeseriesResponses, GetUsageTopModelsData, GetUsageTopModelsError, GetUsageTopModelsErrors, GetUsageTopModelsResponse, GetUsageTopModelsResponses, GetVisitorByGuidData, GetVisitorByGuidErrors, GetVisitorByGuidResponse, GetVisitorByGuidResponses, GetVisitorByIdData, GetVisitorByIdErrors, GetVisitorByIdResponse, GetVisitorByIdResponses, GetVisitorDetailsData, GetVisitorDetailsErrors, GetVisitorDetailsResponse, GetVisitorDetailsResponses, GetVisitorFacetsData, GetVisitorFacetsErrors, GetVisitorFacetsResponse, GetVisitorFacetsResponses, GetVisitorInfoData, GetVisitorInfoErrors, GetVisitorInfoResponse, GetVisitorInfoResponses, GetVisitorJourneyData, GetVisitorJourneyErrors, GetVisitorJourneyResponse, GetVisitorJourneyResponses, GetVisitorsData, GetVisitorsErrors, GetVisitorSessionsData, GetVisitorSessionsError, GetVisitorSessionsErrors, GetVisitorSessionsQuery, GetVisitorSessionsResponse, GetVisitorSessionsResponse2, GetVisitorSessionsResponses, GetVisitorsResponse, GetVisitorsResponses, GetVisitorStatsData, GetVisitorStatsErrors, GetVisitorStatsResponse, GetVisitorStatsResponses, GetWebhookData, GetWebhookErrors, GetWebhookResponse, GetWebhookResponses, GitPushEvent, GitRefResponse, GitSourcePlan, GlobalConversationResponse, GlobalEventStatsResponse, GlobalMrrResponse, GlobalRecentEventResponse, GlobalRevenueSummaryResponse, GrantProjectAccessData, GrantProjectAccessErrors, GrantProjectAccessResponse, GrantProjectAccessResponses, GroupedPageMetric, GroupedPageMetricsQuery, GroupedPageMetricsResponse, HandleGitProviderOauthCallbackData, HandleGitProviderOauthCallbackErrors, HasAnalyticsEventsData, HasAnalyticsEventsErrors, HasAnalyticsEventsResponse, HasAnalyticsEventsResponse2, HasAnalyticsEventsResponses, HasErrorGroupsData, HasErrorGroupsErrors, HasErrorGroupsResponse, HasErrorGroupsResponse2, HasErrorGroupsResponses, HasEventsQuery, HasEventsResponse, HasMetricsQuery, HasMetricsResponse, HasPerformanceMetricsData, HasPerformanceMetricsError, HasPerformanceMetricsErrors, HasPerformanceMetricsResponse, HasPerformanceMetricsResponses, HealthCheckConfiguration, HealthCheckEntryResponse, HealthResponse, HealthStatus, HealthSummary, HeartbeatApiRequest, HeartbeatResponse, HierarchyLevel, HistogramSummary, HostnameChange, HostnamePreviewResponse, HourlyPageSessions, HourlyVisitsQuery, HttpChallengeDebugResponse, ImportCredentials, ImportExecutionStatus, ImportExternalServiceData, ImportExternalServiceErrors, ImportExternalServiceRequest, ImportExternalServiceResponse, ImportExternalServiceResponses, ImportOutcomeResponse, ImportPlan, ImportRowErrorResponse, ImportSelector, ImportSource, ImportSourceCapabilities, ImportSourceInfo, ImportStatusResponse, IncidentBucket, IncidentBucketedResponse, IncidentResponse, IncidentUpdateResponse, IncrRequest, IncrResponse, IngestLogsByPathData, IngestLogsByPathError, IngestLogsByPathErrors, IngestLogsByPathResponses, IngestLogsData, IngestLogsError, IngestLogsErrors, IngestLogsResponses, IngestMetricsByPathData, IngestMetricsByPathError, IngestMetricsByPathErrors, IngestMetricsByPathResponses, IngestMetricsData, IngestMetricsError, IngestMetricsErrors, IngestMetricsResponses, IngestSentryEnvelopeData, IngestSentryEnvelopeErrors, IngestSentryEnvelopeResponses, IngestSentryEventData, IngestSentryEventErrors, IngestSentryEventResponse, IngestSentryEventResponses, IngestTracesByPathData, IngestTracesByPathError, IngestTracesByPathErrors, IngestTracesByPathResponses, IngestTracesData, IngestTracesError, IngestTracesErrors, IngestTracesResponses, InitAuthResponse, InitSessionReplayData, InitSessionReplayError, InitSessionReplayErrors, InitSessionReplayResponse, InitSessionReplayResponses, Insight, InsightSeverity, InsightsResponse, InsightStatus, InspectDropArchiveData, InspectDropArchiveErrors, InspectDropArchiveResponse, InspectDropArchiveResponses, IntegrationResponse, IpAccessControlQuery, IpAccessControlResponse, JobLogsData, JobLogsErrors, JobLogsResponses, JobStatusData, JobStatusErrors, JobStatusResponse, JobStatusResponse2, JobStatusResponses, JobSummaryResponse, JoinTokenStatusResponse, JourneyEvent, JourneySession, KeysRequest, KeysResponse, KillJobBody, KillJobData, KillJobErrors, KillJobResponse, KillJobResponses, KnownAiAgentsResponse, KvDelData, KvDelErrors, KvDelResponse, KvDelResponses, KvDisableData, KvDisableErrors, KvDisableResponse, KvDisableResponses, KvEnableData, KvEnableErrors, KvEnableResponse, KvEnableResponses, KvExpireData, KvExpireErrors, KvExpireResponse, KvExpireResponses, KvGetData, KvGetErrors, KvGetResponse, KvGetResponses, KvIncrData, KvIncrErrors, KvIncrResponse, KvIncrResponses, KvKeysData, KvKeysErrors, KvKeysResponse, KvKeysResponses, KvSetData, KvSetErrors, KvSetResponse, KvSetResponses, KvStatusData, KvStatusErrors, KvStatusResponse, KvStatusResponse2, KvStatusResponses, KvTtlData, KvTtlErrors, KvTtlResponse, KvTtlResponses, KvUpdateData, KvUpdateErrors, KvUpdateResponse, KvUpdateResponses, LatestRunForSourceData, LatestRunForSourceErrors, LatestRunForSourceResponse, LatestRunForSourceResponses, LemonSqueezyConfig, LetsEncryptSettings, LineContext, LinkCustomDomainToCertificateData, LinkCustomDomainToCertificateErrors, LinkCustomDomainToCertificateResponse, LinkCustomDomainToCertificateResponses, LinkServiceRequest, LinkServiceToProjectData, LinkServiceToProjectErrors, LinkServiceToProjectResponse, LinkServiceToProjectResponses, ListAgentRunsData, ListAgentRunsErrors, ListAgentRunsResponse, ListAgentRunsResponses, ListAgentsData, ListAgentsErrors, ListAgentsResponse, ListAgentsResponse2, ListAgentsResponses, ListAiProvidersData, ListAiProvidersErrors, ListAiProvidersResponse, ListAiProvidersResponses, ListAlertRulesData, ListAlertRulesErrors, ListAlertRulesResponse, ListAlertRulesResponses, ListAlertsData, ListAlertsError, ListAlertsErrors, ListAlertsResponse, ListAlertsResponses, ListAllConversationsData, ListAllConversationsErrors, ListAllConversationsResponse, ListAllConversationsResponses, ListAllRunsData, ListAllRunsErrors, ListAllRunsResponse, ListAllRunsResponses, ListApiKeysData, ListApiKeysErrors, ListApiKeysQuery, ListApiKeysResponse, ListApiKeysResponses, ListAuditLogsData, ListAuditLogsErrors, ListAuditLogsQuery, ListAuditLogsResponse, ListAuditLogsResponses, ListAvailableContainersData, ListAvailableContainersErrors, ListAvailableContainersResponse, ListAvailableContainersResponses, ListBackupAlertsData, ListBackupAlertsError, ListBackupAlertsErrors, ListBackupAlertsResponse, ListBackupAlertsResponses, ListBackupChildrenData, ListBackupChildrenError, ListBackupChildrenErrors, ListBackupChildrenResponse, ListBackupChildrenResponses, ListBackupSchedulesData, ListBackupSchedulesError, ListBackupSchedulesErrors, ListBackupSchedulesResponse, ListBackupSchedulesResponses, ListBackupsForScheduleData, ListBackupsForScheduleErrors, ListBackupsForScheduleResponse, ListBackupsForScheduleResponses, ListBlobsQuery, ListBlobsResponse, ListCommitsByRepositoryIdData, ListCommitsByRepositoryIdErrors, ListCommitsByRepositoryIdResponse, ListCommitsByRepositoryIdResponses, ListConnectionsData, ListConnectionsErrors, ListConnectionsResponse, ListConnectionsResponses, ListContainersAtPathData, ListContainersAtPathErrors, ListContainersAtPathResponse, ListContainersAtPathResponses, ListContainersData, ListContainersErrors, ListContainersResponse, ListContainersResponses, ListConversationsData, ListConversationsErrors, ListConversationsResponse, ListConversationsResponses, ListCustomDomainsForProjectData, ListCustomDomainsForProjectErrors, ListCustomDomainsForProjectResponse, ListCustomDomainsForProjectResponses, ListCustomDomainsResponse, ListDashboardsData, ListDashboardsError, ListDashboardsErrors, ListDashboardsResponse, ListDashboardsResponses, ListDeliveriesData, ListDeliveriesErrors, ListDeliveriesResponse, ListDeliveriesResponses, ListDeploymentContainerLogsData, ListDeploymentContainerLogsErrors, ListDeploymentContainerLogsResponse, ListDeploymentContainerLogsResponses, ListDeploymentTokensData, ListDeploymentTokensErrors, ListDeploymentTokensQuery, ListDeploymentTokensResponse, ListDeploymentTokensResponses, ListDnsProvidersData, ListDnsProvidersErrors, ListDnsProvidersResponse, ListDnsProvidersResponses, ListDomainsData, ListDomainsErrors, ListDomainsResponse, ListDomainsResponse2, ListDomainsResponses, ListDsnsData, ListDsnsErrors, ListDsnsResponse, ListDsnsResponses, ListEmailDomainsData, ListEmailDomainsErrors, ListEmailDomainsResponse, ListEmailDomainsResponses, ListEmailProvidersData, ListEmailProvidersErrors, ListEmailProvidersResponse, ListEmailProvidersResponses, ListEmailsData, ListEmailsErrors, ListEmailsResponse, ListEmailsResponses, ListEnrollmentTokensData, ListEnrollmentTokensErrors, ListEnrollmentTokensResponse, ListEnrollmentTokensResponses, ListEntitiesData, ListEntitiesErrors, ListEntitiesQuery, ListEntitiesResponse, ListEntitiesResponses, ListErrorEventsData, ListErrorEventsErrors, ListErrorEventsQuery, ListErrorEventsResponse, ListErrorEventsResponses, ListErrorGroupsData, ListErrorGroupsErrors, ListErrorGroupsQuery, ListErrorGroupsResponse, ListErrorGroupsResponses, ListEventsData, ListEventsResponse, ListEventsResponses, ListEventTypesData, ListEventTypesResponse, ListEventTypesResponses, ListExternalImagesData, ListExternalImagesErrors, ListExternalImagesResponse, ListExternalImagesResponses, ListExternalPluginsData, ListExternalPluginsErrors, ListExternalPluginsResponse, ListExternalPluginsResponses, ListExternalServiceBackupsData, ListExternalServiceBackupsError, ListExternalServiceBackupsErrors, ListExternalServiceBackupsResponse, ListExternalServiceBackupsResponses, ListFlagsData, ListFlagsErrors, ListFlagsResponse, ListFlagsResponses, ListFunnelsData, ListFunnelsErrors, ListFunnelsResponse, ListFunnelsResponses, ListGitProvidersData, ListGitProvidersErrors, ListGitProvidersResponse, ListGitProvidersResponses, ListGlobalMcpsData, ListGlobalMcpsErrors, ListGlobalMcpsResponse, ListGlobalMcpsResponses, ListGlobalSkillsData, ListGlobalSkillsErrors, ListGlobalSkillsResponse, ListGlobalSkillsResponses, ListIncidentsData, ListIncidentsErrors, ListIncidentsResponses, ListInsightsData, ListInsightsError, ListInsightsErrors, ListInsightsResponse, ListInsightsResponses, ListIpAccessControlData, ListIpAccessControlError, ListIpAccessControlErrors, ListIpAccessControlResponse, ListIpAccessControlResponses, ListJobsData, ListJobsErrors, ListJobsResponse, ListJobsResponse2, ListJobsResponses, ListKnownAiAgentsData, ListKnownAiAgentsError, ListKnownAiAgentsErrors, ListKnownAiAgentsResponse, ListKnownAiAgentsResponses, ListManagedDomainsData, ListManagedDomainsErrors, ListManagedDomainsResponse, ListManagedDomainsResponses, ListMcpsData, ListMcpsErrors, ListMcpsResponse, ListMcpsResponse2, ListMcpsResponses, ListMetricLabelKeysData, ListMetricLabelKeysError, ListMetricLabelKeysErrors, ListMetricLabelKeysResponse, ListMetricLabelKeysResponses, ListMetricLabelValuesData, ListMetricLabelValuesError, ListMetricLabelValuesErrors, ListMetricLabelValuesResponse, ListMetricLabelValuesResponses, ListMetricNamesData, ListMetricNamesError, ListMetricNamesErrors, ListMetricNamesResponse, ListMetricNamesResponses, ListModelsData, ListModelsError, ListModelsErrors, ListModelsResponse, ListModelsResponses, ListMonitorsData, ListMonitorsErrors, ListMonitorsResponse, ListMonitorsResponses, ListNotificationProvidersData, ListNotificationProvidersErrors, ListNotificationProvidersResponse, ListNotificationProvidersResponses, ListOidcProvidersData, ListOidcProvidersResponse, ListOidcProvidersResponses, ListOidcProviderUsersData, ListOidcProviderUsersErrors, ListOidcProviderUsersResponse, ListOidcProviderUsersResponses, ListOidcRoleMappingsData, ListOidcRoleMappingsResponse, ListOidcRoleMappingsResponses, ListOnDemandCertsData, ListOnDemandCertsErrors, ListOnDemandCertsResponse, ListOnDemandCertsResponse2, ListOnDemandCertsResponses, ListOrdersData, ListOrdersErrors, ListOrdersResponse, ListOrdersResponse2, ListOrdersResponses, ListPeersData, ListPeersErrors, ListPeersResponse, ListPeersResponses, ListPendingActionsData, ListPendingActionsErrors, ListPendingActionsResponse, ListPendingActionsResponses, ListPgUpgradesData, ListPgUpgradesErrors, ListPgUpgradesResponse, ListPgUpgradesResponses, ListPresetsData, ListPresetsErrors, ListPresetsResponse, ListPresetsResponse2, ListPresetsResponses, ListProjectAccessData, ListProjectAccessErrors, ListProjectAccessResponse, ListProjectAccessResponses, ListProjectAlarmsData, ListProjectAlarmsErrors, ListProjectAlarmsResponse, ListProjectAlarmsResponses, ListProjectScansData, ListProjectScansError, ListProjectScansErrors, ListProjectScansResponse, ListProjectScansResponses, ListProjectSecretsData, ListProjectSecretsErrors, ListProjectSecretsResponse, ListProjectSecretsResponses, ListProjectServicesData, ListProjectServicesErrors, ListProjectServicesResponse, ListProjectServicesResponses, ListProjectTemplatesData, ListProjectTemplatesErrors, ListProjectTemplatesResponse, ListProjectTemplatesResponses, ListProjectTemplateTagsData, ListProjectTemplateTagsErrors, ListProjectTemplateTagsResponse, ListProjectTemplateTagsResponses, ListProviderKeysData, ListProviderKeysError, ListProviderKeysErrors, ListProviderKeysResponse, ListProviderKeysResponses, ListProviderZonesData, ListProviderZonesErrors, ListProviderZonesResponse, ListProviderZonesResponses, ListPublicProvidersData, ListPublicProvidersResponse, ListPublicProvidersResponses, ListReleaseFilesData, ListReleaseFilesErrors, ListReleaseFilesResponse, ListReleaseFilesResponses, ListReleasesData, ListReleasesErrors, ListReleasesResponse, ListReleasesResponses, ListRemoteExternalImagesData, ListRemoteExternalImagesErrors, ListRemoteExternalImagesResponse, ListRemoteExternalImagesResponses, ListRepositoriesByConnectionData, ListRepositoriesByConnectionErrors, ListRepositoriesByConnectionResponse, ListRepositoriesByConnectionResponses, ListRepositoriesByProviderData, ListRepositoriesByProviderErrors, ListRepositoriesByProviderResponse, ListRepositoriesByProviderResponses, ListRestoreRunsForServiceData, ListRestoreRunsForServiceResponse, ListRestoreRunsForServiceResponses, ListRootContainersData, ListRootContainersErrors, ListRootContainersResponse, ListRootContainersResponses, ListRoutesData, ListRoutesErrors, ListRoutesResponse, ListRoutesResponses, ListRunsResponse, ListS3SourcesData, ListS3SourcesError, ListS3SourcesErrors, ListS3SourcesResponse, ListS3SourcesResponses, ListSandboxesData, ListSandboxesResponse, ListSandboxesResponse2, ListSandboxesResponses, ListScansQuery, ListScheduleRunJobsData, ListScheduleRunJobsError, ListScheduleRunJobsErrors, ListScheduleRunJobsResponse, ListScheduleRunJobsResponses, ListScheduleRunsData, ListScheduleRunsError, ListScheduleRunsErrors, ListScheduleRunsResponse, ListScheduleRunsResponses, ListScheduleServicesData, ListScheduleServicesError, ListScheduleServicesErrors, ListScheduleServicesResponse, ListScheduleServicesResponses, ListSecretsData, ListSecretsErrors, ListSecretsResponse, ListSecretsResponse2, ListSecretsResponses, ListServiceHealthStatusesData, ListServiceHealthStatusesErrors, ListServiceHealthStatusesResponse, ListServiceHealthStatusesResponses, ListServiceProjectsData, ListServiceProjectsErrors, ListServiceProjectsResponse, ListServiceProjectsResponses, ListServiceSchedulesData, ListServiceSchedulesError, ListServiceSchedulesErrors, ListServiceSchedulesResponse, ListServiceSchedulesResponses, ListServicesData, ListServicesErrors, ListServicesResponse, ListServicesResponses, ListSkillsData, ListSkillsErrors, ListSkillsResponse, ListSkillsResponse2, ListSkillsResponses, ListSourceBackupsData, ListSourceBackupsError, ListSourceBackupsErrors, ListSourceBackupsResponse, ListSourceBackupsResponses, ListSourceFilesData, ListSourceFilesErrors, ListSourceFilesResponse, ListSourceFilesResponses, ListSourceMapsData, ListSourceMapsErrors, ListSourceMapsResponse, ListSourceMapsResponses, ListSourcesData, ListSourcesErrors, ListSourcesResponse, ListSourcesResponses, ListStaticBundlesData, ListStaticBundlesErrors, ListStaticBundlesResponse, ListStaticBundlesResponses, ListSyncedRepositoriesData, ListSyncedRepositoriesErrors, ListSyncedRepositoriesResponse, ListSyncedRepositoriesResponses, ListTagsResponse, ListTeamMembersData, ListTeamMembersErrors, ListTeamMembersResponse, ListTeamMembersResponses, ListTeamProjectsData, ListTeamProjectsErrors, ListTeamProjectsResponse, ListTeamProjectsResponses, ListTeamsData, ListTeamsErrors, ListTeamsResponse, ListTeamsResponses, ListTemplatesQuery, ListTemplatesResponse, ListUsersData, ListUsersErrors, ListUsersResponse, ListUsersResponses, ListVulnerabilitiesQuery, ListWebhooksData, ListWebhooksErrors, ListWebhooksResponse, ListWebhooksResponses, LiveVisitorInfo, LiveVisitorsListResponse, LocationCount, LocationGranularity, LocationInfo, LoginData, LoginErrors, LoginRequest, LoginResponse, LoginResponses, LogLevel, LogoutData, LogoutErrors, LogoutResponses, LogRecord, LogSearchLine, LogSeverity, LogSource, LogsQuery, LogsResponse, LogStream, LookupDnsARecordsData, LookupDnsARecordsError, LookupDnsARecordsErrors, LookupDnsARecordsResponse, LookupDnsARecordsResponses, ManagedDomainResponse, ManualAction, ManualActionTiming, McpDefinitionResponse, MessageContent, MessagePart, MessageResponse, MeteredMode, MetricAggregation, MetricBucket, MetricDataPoint, MetricsOverTimeResponse, MetricsQuery, MetricsRangeQuery, MetricsStatusResponse, MetricsStoreKind, MetricsSummaryResponse, MetricType, MfaRequiredResponse, MfaSetupResponse, MfaVerificationRequest, MigrationStep, MigrationSummary, MintEnrollmentTokenData, MintEnrollmentTokenErrors, MintEnrollmentTokenRequest, MintEnrollmentTokenResponse, MintEnrollmentTokenResponse2, MintEnrollmentTokenResponses, MiscResult, MkdirBody, MkdirData, MkdirErrors, MkdirResponse, MkdirResponses, ModelInfo, ModelListResponse, ModelPricing, ModelUsage, MonitoringSettings, MonitoringSettingsMasked, MonitorResponse, MonitorStatus, MrrBucketResponse, MultiNodeSettings, MultiNodeSettingsMasked, MxResult, NavEntry, NavSection, NetworkConfiguration, NetworkMode, NixpacksPresetConfig, NixpacksProvider, NodeContainerListResponse, NodeContainerResponse, NodeCostInfo, NodeHeartbeatData, NodeHeartbeatErrors, NodeHeartbeatResponse, NodeHeartbeatResponses, NodeInfoResponse, NodeListResponse, NodeMetricsGetRangeData, NodeMetricsGetRangeErrors, NodeMetricsGetRangeResponse, NodeMetricsGetRangeResponses, NotificationPreferencesResponse, NotificationProviderResponse, ObservabilityCompressionSettings, ObservabilityEvent, ObservabilityFullEventData, ObservabilityFullEventError, ObservabilityFullEventErrors, ObservabilityFullEventResponse, ObservabilityFullEventResponses, ObservabilityListEventsData, ObservabilityListEventsError, ObservabilityListEventsErrors, ObservabilityListEventsResponse, ObservabilityListEventsResponses, ObservabilityRetentionSettings, OidcCallbackData, OidcProviderResponse, OidcProvidersListResponse, OidcProviderSummary, OidcProviderUserResponse, OidcRoleMappingResponse, OidcTestConnectionResponse, OnDemandCertAttemptResponse, OnDemandCertRow, OnDemandTlsSettings, OpenAiError, OpenAiErrorResponse, OperatingSystemCount, OperationResultResponse, OperationResultsResponse, OtelDashboardResponse, OtelDashboardsResponse, OtelMetricAlertRuleResponse, OtelMetricAlertsResponse, OtelMetricLabelKeysResponse, OtelMetricLabelValuesResponse, OtelMetricNamesResponse, OtelMetricsResponse, OutlierAlgorithm, OutlierParams, OverprovisioningAssessment, OverprovisioningVerdict, PageActivityBucket, PageCountryStats, PageFlowEntry, PageFlowQuery, PageFlowResponse, PageHourlySessionsQuery, PageHourlySessionsResponse, PagePathDetailQuery, PagePathDetailResponse, PagePathInfo, PagePathSparkline, PagePathSparklinePoint, PagePathsQuery, PagePathsResponse, PagePathsSparklineQuery, PagePathsSparklineResponse, PagePathVisitorsQuery, PagePathVisitorsResponse, PageReferrerStats, PagesComparisonResponse, PageSessionComparison, PageSessionStats, PageSessionStatsQuery, PageTransition, PageVisit, PageVisitorSession, PaginatedEmailsResponse, PaginatedEntitiesResponse, PaginatedErrorEventsResponse, PaginatedErrorGroupsResponse, PaginatedEventsResponse, PaginatedExternalImagesResponse, PaginatedProjectList, PaginatedStaticBundlesResponse, Pagination, PaginationMeta, PaginationParams, PasswordProtectionConfig, PatchAdminGateData, PatchAdminGateErrors, PatchAdminGateResponse, PatchAdminGateResponses, PatchPreviewGatewaySettingsData, PatchPreviewGatewaySettingsResponse, PatchPreviewGatewaySettingsResponses, PatchSettingsRequest, PathVisitors, PathVisitorsAnalyticsQuery, PathVisitorsResponse, PauseDeploymentData, PauseDeploymentErrors, PauseDeploymentResponse, PauseDeploymentResponses, PauseSandboxData, PauseSandboxErrors, PauseSandboxResponse, PauseSandboxResponses, PeerEntry, PeerListResponse, PendingActionResponse, PerformanceMetricsQuery, PerformanceMetricsResponse, PermissionInfo, PgUpgradeLogResponse, PgUpgradeResponse, PipelineStats, PipelineStatsResponse, PlanComplexity, PlanMetadata, PlanRestoreData, PlanRestoreError, PlanRestoreErrors, PlanRestoreResponse, PlanRestoreResponses, PlanSourceBackup, PlanTarget, PlatformInfo, PluginManifest, PortMapping, PostDnsAckData, PostDnsAckErrors, PostDnsAckResponse, PostDnsAckResponses, PostgresWalHealth, PresetConfigSchema, PresetInfo, PresetResponse, PreviewAlertData, PreviewAlertError, PreviewAlertErrors, PreviewAlertResponse, PreviewAlertResponses, PreviewFunnelMetricsData, PreviewFunnelMetricsErrors, PreviewFunnelMetricsResponse, PreviewFunnelMetricsResponses, PreviewGatewaySettings, PreviewGatewaySettingsMasked, PreviewGatewaySettingsResponse, PreviewHostnameModeData, PreviewHostnameModeErrors, PreviewHostnameModeResponse, PreviewHostnameModeResponses, PreviewShareLinkBody, PreviewShareLinkResponse, PricingResponse, ProblemDetails, ProjectAccessResponse, ProjectConfiguration, ProjectDashboardAnalytics, ProjectDsnResponse, ProjectHealthSummary, ProjectInfo, ProjectMonitorHealth, ProjectPresetResponse, ProjectQuery, ProjectRef, ProjectResponse, ProjectSecretEnvironmentInfo, ProjectSecretResponse, ProjectServiceInfo, ProjectsHealthResponse, ProjectsMonitorHealthResponse, ProjectStatisticsResponse, ProjectStatsBreakdown, ProjectType, ProjectUsageInfoResponse, PromoteClusterMemberData, PromoteClusterMemberErrors, PromoteClusterMemberResponses, PromoteDeploymentData, PromoteDeploymentErrors, PromoteDeploymentRequest, PromoteDeploymentResponse, PromoteDeploymentResponses, PropertyBreakdownItem, PropertyBreakdownQuery, PropertyBreakdownResponse, PropertyColumn, PropertyTimelineItem, PropertyTimelineQuery, PropertyTimelineResponse, Protocol, ProviderCatalogDto, ProviderCatalogResponse, ProviderConfig, ProviderConfigMasked, ProviderDeletionCheckResponse, ProviderDescriptor, ProviderKeyResponse, ProviderMetadata, ProviderResponse, ProviderUsage, ProvisionDomainData, ProvisionDomainErrors, ProvisionDomainResponse, ProvisionDomainResponses, ProvisionResponse, ProxyLogResponse, ProxyLogsPaginatedResponse, PublicHostnameStrategy, PublicPresetResponse, PublicRepositoryInfo, PurgeLogsRequest, PurgeProjectLogsData, PurgeProjectLogsError, PurgeProjectLogsErrors, PurgeProjectLogsResponses, PushedExternalImageResponse, PushExternalImageData, PushExternalImageErrors, PushExternalImageResponse, PushExternalImageResponses, PushImageRequest, QueryDataData, QueryDataErrors, QueryDataRequest, QueryDataResponse, QueryDataResponse2, QueryDataResponses, QueryGenaiTracesData, QueryGenaiTracesError, QueryGenaiTracesErrors, QueryGenaiTracesResponse, QueryGenaiTracesResponses, QueryLogsData, QueryLogsError, QueryLogsErrors, QueryLogsResponse, QueryLogsResponses, QueryMetricsData, QueryMetricsError, QueryMetricsErrors, QueryMetricsResponse, QueryMetricsResponses, QueryTracesData, QueryTracesError, QueryTracesErrors, QueryTracesResponse, QueryTracesResponses, QueryTraceSummariesData, QueryTraceSummariesError, QueryTraceSummariesErrors, QueryTraceSummariesResponse, QueryTraceSummariesResponses, QuotaResponse, RateLimitConfig, RateLimitSettings, ReachabilityStatus, ReadFileData, ReadFileErrors, ReadFileResponse, ReadFileResponse2, ReadFileResponses, ReAnalyzeData, ReAnalyzeErrors, ReAnalyzeResponses, RecentActivityQuery, RecentActivityResponse, RecentEventResponse, RecentQueryParams, RecordConsoleEventData, RecordConsoleEventErrors, RecordConsoleEventResponses, RecordEventMetricsData, RecordEventMetricsErrors, RecordEventMetricsResponse, RecordEventMetricsResponses, RecordExposureRequest, RecordExposureResponse, RecordFlagExposureData, RecordFlagExposureErrors, RecordFlagExposureResponse, RecordFlagExposureResponses, RecordListResponse, RecordSpeedMetricsData, RecordSpeedMetricsError, RecordSpeedMetricsErrors, RecordSpeedMetricsResponse, RecordSpeedMetricsResponses, RecoveryTarget, ReferrerCount, ReferrersAnalyticsQuery, RefreshRouteTableData, RefreshRouteTableErrors, RefreshRouteTableResponse, RefreshRouteTableResponses, RegenerateDsnData, RegenerateDsnErrors, RegenerateDsnRequest, RegenerateDsnResponse, RegenerateDsnResponses, RegisterExternalImageData, RegisterExternalImageErrors, RegisterExternalImageResponse, RegisterExternalImageResponses, RegisterImageRequest, RegisterNodeApiRequest, RegisterNodeData, RegisterNodeErrors, RegisterNodeResponse, RegisterNodeResponse2, RegisterNodeResponses, RegisterRequest, ReinstallGitlabWebhookData, ReinstallGitlabWebhookErrors, ReinstallGitlabWebhookResponse, ReinstallGitlabWebhookResponses, ReinstallWebhookResponse, RejectPendingActionData, RejectPendingActionErrors, RejectPendingActionResponse, RejectPendingActionResponses, ReleaseListResponse, ReloadPluginsData, ReloadPluginsErrors, ReloadPluginsResponse, ReloadPluginsResponses, ReloadResponse, RemoteDeploymentResponse, RemoveClusterMemberData, RemoveClusterMemberErrors, RemoveClusterMemberResponse, RemoveClusterMemberResponses, RemoveManagedDomainData, RemoveManagedDomainErrors, RemoveManagedDomainResponse, RemoveManagedDomainResponses, RemoveNodeResponse, RemoveRoleData, RemoveRoleErrors, RemoveRoleResponse, RemoveRoleResponses, RemoveTeamMemberData, RemoveTeamMemberErrors, RemoveTeamMemberResponse, RemoveTeamMemberResponses, RenameConversationData, RenameConversationErrors, RenameConversationRequest, RenameConversationResponse, RenameConversationResponses, RenewDomainData, RenewDomainErrors, RenewDomainResponse, RenewDomainResponses, RepositoryListQuery, RepositoryListResponse, RepositoryPresetResponse, RepositoryResponse, RepositorySyncStartedResponse, RequestPasswordResetData, RequestPasswordResetErrors, RequestPasswordResetResponse, RequestPasswordResetResponses, RequestRow, RequiredPasswordChangeRequest, RequiredPasswordChangeResponse, ResetPasswordData, ResetPasswordErrors, ResetPasswordRequest, ResetPasswordResponse, ResetPasswordResponses, ResetPgStatStatementsRequest, ResetPgStatStatementsResponse, ResizeSandboxBody, ResizeSandboxData, ResizeSandboxErrors, ResizeSandboxResponse, ResizeSandboxResponses, ResolveAlarmData, ResolveAlarmErrors, ResolveAlarmResponses, ResolvedEnvVarResponse, ResolvedEnvVarSource, ResourceCounts, ResourceFootprint, ResourceInfo, ResourceLimitApplyResult, ResourceLimits, ResourceLimitsResponse, ResourceLimitsUpdateResponse, ResourcesBody, RestartContainerData, RestartContainerErrors, RestartContainerResponse, RestartContainerResponses, RestartPreviewGatewayData, RestartPreviewGatewayResponse, RestartPreviewGatewayResponses, RestartSandboxData, RestartSandboxErrors, RestartSandboxResponse, RestartSandboxResponses, RestoreCapabilities, RestoreCapabilitiesResponse, RestoreFlagData, RestoreFlagErrors, RestoreFlagResponse, RestoreFlagResponses, RestorePlan, RestoreRequestMode, RestoreRunView, RestoreUserData, RestoreUserErrors, RestoreUserResponse, RestoreUserResponses, ResumeDeploymentData, ResumeDeploymentErrors, ResumeDeploymentResponse, ResumeDeploymentResponses, ResumeSandboxData, ResumeSandboxErrors, ResumeSandboxResponse, ResumeSandboxResponses, RetentionCleanupFailure, RetentionCleanupReport, RetryClusterData, RetryClusterErrors, RetryClusterRequest, RetryClusterResponse, RetryClusterResponses, RetryDeliveryData, RetryDeliveryErrors, RetryDeliveryResponse, RetryDeliveryResponses, RetryPgUpgradeData, RetryPgUpgradeErrors, RetryPgUpgradeResponse, RetryPgUpgradeResponses, RetryRunData, RetryRunErrors, RetryRunResponse, RetryRunResponses, RevealGlobalMcpConfigData, RevealGlobalMcpConfigErrors, RevealGlobalMcpConfigResponse, RevealGlobalMcpConfigResponses, RevealMcpConfigData, RevealMcpConfigErrors, RevealMcpConfigResponse, RevealMcpConfigResponses, RevealNotificationProviderConfigData, RevealNotificationProviderConfigErrors, RevealNotificationProviderConfigResponse, RevealNotificationProviderConfigResponses, RevealServiceParameterData, RevealServiceParameterErrors, RevealServiceParameterResponse, RevealServiceParameterResponses, RevenueCreateIntegrationData, RevenueCreateIntegrationErrors, RevenueCreateIntegrationResponse, RevenueCreateIntegrationResponses, RevenueDeleteIntegrationData, RevenueDeleteIntegrationResponse, RevenueDeleteIntegrationResponses, RevenueGlobalEventsData, RevenueGlobalEventsResponse, RevenueGlobalEventsResponses, RevenueImportInvoicesCsvData, RevenueImportInvoicesCsvErrors, RevenueImportInvoicesCsvResponse, RevenueImportInvoicesCsvResponses, RevenueImportSubscriptionsCsvData, RevenueImportSubscriptionsCsvErrors, RevenueImportSubscriptionsCsvResponse, RevenueImportSubscriptionsCsvResponses, RevenueListIntegrationsData, RevenueListIntegrationsResponse, RevenueListIntegrationsResponses, RevenueListProvidersData, RevenueListProvidersResponse, RevenueListProvidersResponses, RevenueMetricsCustomersData, RevenueMetricsCustomersResponse, RevenueMetricsCustomersResponses, RevenueMetricsGlobalMrrData, RevenueMetricsGlobalMrrResponse, RevenueMetricsGlobalMrrResponses, RevenueMetricsGlobalSummaryData, RevenueMetricsGlobalSummaryResponse, RevenueMetricsGlobalSummaryResponses, RevenueMetricsMrrData, RevenueMetricsMrrResponse, RevenueMetricsMrrResponses, RevenueMetricsSummaryData, RevenueMetricsSummaryResponse, RevenueMetricsSummaryResponses, RevenueRecentEventsData, RevenueRecentEventsResponse, RevenueRecentEventsResponses, RevenueRotateTokenData, RevenueRotateTokenResponse, RevenueRotateTokenResponses, RevenueRow, RevenueUpdateConfigData, RevenueUpdateConfigErrors, RevenueUpdateConfigResponse, RevenueUpdateConfigResponses, RevenueUpdateSecretData, RevenueUpdateSecretErrors, RevenueUpdateSecretResponse, RevenueUpdateSecretResponses, RevokeDsnData, RevokeDsnErrors, RevokeDsnResponse, RevokeDsnResponses, RevokeEnrollmentTokenData, RevokeEnrollmentTokenErrors, RevokeEnrollmentTokenResponse, RevokeEnrollmentTokenResponses, RevokeJoinTokenData, RevokeJoinTokenErrors, RevokeJoinTokenResponse, RevokeJoinTokenResponses, RevokeProjectAccessData, RevokeProjectAccessErrors, RevokeProjectAccessResponse, RevokeProjectAccessResponses, RiskLevel, RoleInfo, RollbackPgUpgradeData, RollbackPgUpgradeErrors, RollbackPgUpgradeResponse, RollbackPgUpgradeResponses, RollbackToDeploymentData, RollbackToDeploymentErrors, RollbackToDeploymentResponse, RollbackToDeploymentResponses, RootfsCacheEntry, RootfsGcData, RootfsGcReport, RootfsGcResponses, RootfsReport, RootfsReportData, RootfsReportResponses, RootfsVmEntry, RotateApiKeyData, RotateApiKeyErrors, RotateApiKeyResponse, RotateApiKeyResponses, RotateDeploymentTokenData, RotateDeploymentTokenErrors, RotateDeploymentTokenResponse, RotateDeploymentTokenResponses, RouteRefreshResponse, RouteResponse, RouteRole, RouteUser, RouteUserWithRoles, RunBackupForSourceData, RunBackupForSourceError, RunBackupForSourceErrors, RunBackupForSourceResponse, RunBackupForSourceResponses, RunBackupRequest, RunConnectionHealthCheckData, RunConnectionHealthCheckErrors, RunConnectionHealthCheckResponse, RunConnectionHealthCheckResponses, RunExternalServiceBackupData, RunExternalServiceBackupError, RunExternalServiceBackupErrors, RunExternalServiceBackupRequest, RunExternalServiceBackupResponse, RunExternalServiceBackupResponses, RunScheduleNowData, RunScheduleNowError, RunScheduleNowErrors, RunScheduleNowResponse, RunScheduleNowResponses, S3ConnectionTestResponse, S3CredentialsResponse, S3SourceResponse, S3SourceResponseWritable, SandboxCreatePreviewLinkData, SandboxCreatePreviewLinkErrors, SandboxCreatePreviewLinkResponse, SandboxCreatePreviewLinkResponses, SandboxDomainResponse, SandboxEvent, SandboxEventsResponse, SandboxInner, SandboxResponse, SandboxRoute, SandboxStatusResponse, SaveAgentTokenData, SaveAgentTokenErrors, SaveAgentTokenRequest, SaveAgentTokenResponse, SaveAgentTokenResponse2, SaveAgentTokenResponses, SaveAiProviderCredentialData, SaveAiProviderCredentialErrors, SaveAiProviderCredentialResponse, SaveAiProviderCredentialResponses, SaveCredentialRequest, SaveCredentialResponse, ScalewayCredentialsRequest, ScanResponse, ScheduleRunEntry, ScheduleRunJobEntry, ScheduleRunListResponse, ScheduleRunResponse, ScheduleRunSummary, ScheduleRunSummaryList, ScreenshotSettings, SearchLogsData, SearchLogsError, SearchLogsErrors, SearchLogsRequest, SearchLogsResponse, SearchLogsResponse2, SearchLogsResponses, SearchMode, Seasonality, SecretResponse, SecurityConfig, SecurityHeadersConfig, SecurityHeadersSettings, SendEmailData, SendEmailErrors, SendEmailRequestBody, SendEmailResponse, SendEmailResponseBody, SendEmailResponses, SendMessageRequest, SensitiveConfigValueResponse, SensitiveMcpConfigValueResponse, SensitiveValueResponse, SentryChunkUploadResponse, SentryCreateReleaseRequest, SentryEventRequest, SentryEventResponse, SentryReleaseFileResponse, SentryReleaseProjectRef, SentryReleaseResponse, SeriesStateEntry, ServiceAccessInfo, ServiceAction, ServiceAlertRuleResponse, ServiceBackupEntryResponse, ServiceBackupListResponse, ServiceCreateAlertRuleRequest, ServiceHealthResponse, ServiceHealthStatusBatchResponse, ServiceHealthStatusEntryResponse, ServiceMemberInfo, ServiceParameter, ServicePlan, ServiceResourceLimits, ServiceRuntimeReport, ServiceStatsReport, ServiceTypeInfo, ServiceTypeRoute, ServiceUpdateAlertRuleRequest, SesCredentialsRequest, SessionDetails, SessionDetailsQuery, SessionEvent, SessionEventDto, SessionEventsQuery, SessionEventsResponse, SessionLogsQuery, SessionLogsResponse, SessionReplayEventsRequest, SessionReplayInfoDto, SessionReplayInitRequest, SessionReplayInitResponse, SessionReplayWithEventsDto, SessionReplayWithVisitorDto, SessionRequestLog, SessionSummary, SetDefaultS3SourceData, SetDefaultS3SourceError, SetDefaultS3SourceErrors, SetDefaultS3SourceResponse, SetDefaultS3SourceResponses, SetFlagEnvironmentData, SetFlagEnvironmentErrors, SetFlagEnvironmentRequest, SetFlagEnvironmentResponse, SetFlagEnvironmentResponses, SetPreviewPasswordBody, SetPreviewPasswordData, SetPreviewPasswordErrors, SetPreviewPasswordResponse, SetPreviewPasswordResponse2, SetPreviewPasswordResponses, SetRequest, SetResponse, SettingsUpdateResponse, SetupDnsChallengeData, SetupDnsChallengeErrors, SetupDnsChallengeRequest, SetupDnsChallengeResponse, SetupDnsChallengeResponse2, SetupDnsChallengeResponses, SetupDnsData, SetupDnsErrors, SetupDnsRequest, SetupDnsResponse, SetupDnsResponse2, SetupDnsResponses, SetupEmailTrackingData, SetupEmailTrackingErrors, SetupEmailTrackingResponse, SetupEmailTrackingResponses, SetupMfaData, SetupMfaErrors, SetupMfaResponse, SetupMfaResponses, SiblingRef, SkillDefinitionResponse, SlackConfig, SleepEnvironmentData, SleepEnvironmentErrors, SleepEnvironmentResponse, SleepEnvironmentResponses, SlowQueriesResponse, SlowQueryRow, SmartFilter, SmokeTestAgentData, SmokeTestAgentErrors, SmokeTestAgentResponse, SmokeTestAgentResponses, SmokeTestResponse, SmtpCredentialsRequest, SmtpEncryptionRoute, SmtpResult, SourceArchiveUpload, SourceBackupEntry, SourceBackupIndexResponse, SourceBody, SourceFileListResponse, SourceFileResponse, SourceMapListResponse, SourceMapResponse, SourceSandboxData, SourceSandboxErrors, SourceSandboxResponse, SourceSandboxResponses, SourceType, SpanEvent, SpanKind, SpanRecord, SpanRow, SpanStatusCode, SpeedMetricsPayload, SpeedSegmentFilters, StaleSlot, StartAnalysisData, StartAnalysisErrors, StartAnalysisRequest, StartAnalysisResponse, StartAnalysisResponses, StartContainerData, StartContainerErrors, StartContainerResponse, StartContainerResponses, StartFixData, StartFixErrors, StartFixResponses, StartGitProviderOauthData, StartGitProviderOauthErrors, StartOidcLoginBySlugData, StartOidcLoginBySlugErrors, StartPgUpgradeData, StartPgUpgradeErrors, StartPgUpgradeRequest, StartPgUpgradeResponse, StartPgUpgradeResponses, StartRestoreData, StartRestoreError, StartRestoreErrors, StartRestoreRequest, StartRestoreResponse, StartRestoreResponses, StartServiceData, StartServiceErrors, StartServiceResponse, StartServiceResponses, StaticBundleResponse, StaticParams, StaticPresetConfig, StatPathData, StatPathErrors, StatPathResponse, StatPathResponses, StatResponse, StatsFilters, StatusBucket, StatusBucketedResponse, StatusCodeCount, StatusCodesQuery, StatusPageOverview, StepConversionResponse, StepResourceType, StepResult, StepUpResponse, StopContainerData, StopContainerErrors, StopContainerResponse, StopContainerResponses, StopSandboxData, StopSandboxErrors, StopSandboxResponse, StopSandboxResponses, StopSequence, StopServiceData, StopServiceErrors, StopServiceResponse, StopServiceResponses, StorageQuota, StreamContainerMetricsData, StreamContainerMetricsErrors, StreamContainerMetricsResponses, StreamEventsData, StreamEventsErrors, StreamEventsResponses, StreamRunEventsData, StreamRunEventsErrors, StreamRunEventsResponses, StripeConfig, SyncedRepositoryListQuery, SyncRepositoriesData, SyncRepositoriesErrors, SyncRepositoriesResponse, SyncRepositoriesResponses, SyntaxResult, TagInfo, TagListResponse, TailDeploymentJobLogsData, TailDeploymentJobLogsErrors, TailLogsData, TailLogsError, TailLogsErrors, TailLogsRequest, TailLogsResponses, TargetRecommendation, TeamListResponse, TeamMemberResponse, TeamResponse, TeamRole, TeardownDeploymentData, TeardownDeploymentErrors, TeardownDeploymentResponse, TeardownDeploymentResponses, TeardownEnvironmentData, TeardownEnvironmentErrors, TeardownEnvironmentResponse, TeardownEnvironmentResponses, TemplateResponse, TestEmailRequest, TestEmailResponse, TestNotificationProviderData, TestNotificationProviderErrors, TestNotificationProviderResponse, TestNotificationProviderResponses, TestOidcProviderData, TestOidcProviderResponse, TestOidcProviderResponses, TestProviderConnectionData, TestProviderConnectionErrors, TestProviderConnectionResponse, TestProviderConnectionResponses, TestProviderData, TestProviderErrors, TestProviderKeyByIdData, TestProviderKeyByIdError, TestProviderKeyByIdErrors, TestProviderKeyByIdResponse, TestProviderKeyByIdResponses, TestProviderKeyInlineData, TestProviderKeyInlineError, TestProviderKeyInlineErrors, TestProviderKeyInlineResponse, TestProviderKeyInlineResponses, TestProviderKeyRequest, TestProviderKeyResponse, TestProviderResponse, TestProviderResponse2, TestProviderResponses, TestS3ConnectionPreviewData, TestS3ConnectionPreviewError, TestS3ConnectionPreviewErrors, TestS3ConnectionPreviewResponse, TestS3ConnectionPreviewResponses, TestS3SourceConnectionData, TestS3SourceConnectionError, TestS3SourceConnectionErrors, TestS3SourceConnectionResponse, TestS3SourceConnectionResponses, TimeBucketStats, TimeBucketStatsResponse, TimeseriesBucket, TimeseriesQueryParams, TlsMode, TodayStatsResponse, ToggleDeploymentMetricsRequest, ToggleServiceMetricsRequest, TokenRenewalRequest, ToolCallEvent, ToolInfo, ToolResultEvent, TopModelsQueryParams, TraceProjectRef, TracesResponse, TraceSummariesResponse, TraceSummary, TrackClickData, TrackClickErrors, TrackedLinkResponse, TrackingEventResponse, TrackOpenData, TrackOpenErrors, TrackOpenResponses, TriggerAgentData, TriggerAgentErrors, TriggerAgentRequest, TriggerAgentResponse, TriggerAgentResponses, TriggerDigestResponse, TriggerPipelinePayload, TriggerPipelineResponse, TriggerProjectPipelineData, TriggerProjectPipelineErrors, TriggerProjectPipelineResponse, TriggerProjectPipelineResponses, TriggerScanData, TriggerScanError, TriggerScanErrors, TriggerScanRequest, TriggerScanResponse, TriggerScanResponse2, TriggerScanResponses, TriggerServiceHealthCheckData, TriggerServiceHealthCheckErrors, TriggerServiceHealthCheckResponse, TriggerServiceHealthCheckResponses, TriggerWeeklyDigestData, TriggerWeeklyDigestErrors, TriggerWeeklyDigestResponse, TriggerWeeklyDigestResponses, TtlRequest, TtlResponse, TxtRecord, UiManifest, UiRoute, UndrainNodeResponse, UnifiedTrace, UniqueCountsQuery, UniqueCountsResponse, UnlinkServiceFromProjectData, UnlinkServiceFromProjectErrors, UnlinkServiceFromProjectResponse, UnlinkServiceFromProjectResponses, UnsupportedFeature, UpdateAdminGateRequest, UpdateAgentData, UpdateAgentErrors, UpdateAgentResponse, UpdateAgentResponses, UpdateAiProviderData, UpdateAiProviderErrors, UpdateAiProviderRequest, UpdateAiProviderResponse, UpdateAiProviderResponse2, UpdateAiProviderResponses, UpdateAlertData, UpdateAlertError, UpdateAlertErrors, UpdateAlertResponse, UpdateAlertResponses, UpdateAlertRuleData, UpdateAlertRuleErrors, UpdateAlertRuleRequest, UpdateAlertRuleResponse, UpdateAlertRuleResponses, UpdateApiKeyData, UpdateApiKeyErrors, UpdateApiKeyRequest, UpdateApiKeyResponse, UpdateApiKeyResponses, UpdateAutomaticDeployData, UpdateAutomaticDeployErrors, UpdateAutomaticDeployRequest, UpdateAutomaticDeployResponse, UpdateAutomaticDeployResponses, UpdateBackupScheduleData, UpdateBackupScheduleError, UpdateBackupScheduleErrors, UpdateBackupScheduleRequest, UpdateBackupScheduleResponse, UpdateBackupScheduleResponses, UpdateBlobRequest, UpdateBlobResponse, UpdateCloudflareProviderData, UpdateCloudflareProviderErrors, UpdateCloudflareProviderRequest, UpdateCloudflareProviderResponse, UpdateCloudflareProviderResponses, UpdateConfigBody, UpdateConnectionTokenData, UpdateConnectionTokenErrors, UpdateConnectionTokenResponse, UpdateConnectionTokenResponses, UpdateCustomDomainData, UpdateCustomDomainErrors, UpdateCustomDomainRequest, UpdateCustomDomainResponse, UpdateCustomDomainResponses, UpdateDashboardData, UpdateDashboardError, UpdateDashboardErrors, UpdateDashboardRequest, UpdateDashboardResponse, UpdateDashboardResponses, UpdateDeploymentConfigRequest, UpdateDeploymentTokenData, UpdateDeploymentTokenErrors, UpdateDeploymentTokenRequest, UpdateDeploymentTokenResponse, UpdateDeploymentTokenResponses, UpdateDnsProviderRequest, UpdateEmailProviderData, UpdateEmailProviderErrors, UpdateEmailProviderRequest, UpdateEmailProviderResponse, UpdateEmailProviderResponses, UpdateEnvironmentSettingsData, UpdateEnvironmentSettingsErrors, UpdateEnvironmentSettingsRequest, UpdateEnvironmentSettingsResponse, UpdateEnvironmentSettingsResponses, UpdateEnvironmentSubdomainData, UpdateEnvironmentSubdomainErrors, UpdateEnvironmentSubdomainRequest, UpdateEnvironmentSubdomainResponse, UpdateEnvironmentSubdomainResponses, UpdateEnvironmentVariableData, UpdateEnvironmentVariableErrors, UpdateEnvironmentVariableRequest, UpdateEnvironmentVariableResponse, UpdateEnvironmentVariableResponses, UpdateErrorGroupData, UpdateErrorGroupErrors, UpdateErrorGroupRequest, UpdateErrorGroupResponses, UpdateExternalServiceRequest, UpdateFlagData, UpdateFlagErrors, UpdateFlagRequest, UpdateFlagResponse, UpdateFlagResponses, UpdateFunnelData, UpdateFunnelErrors, UpdateFunnelResponses, UpdateGitProviderCredentialsData, UpdateGitProviderCredentialsErrors, UpdateGitProviderCredentialsResponse, UpdateGitProviderCredentialsResponses, UpdateGitSettingsData, UpdateGitSettingsErrors, UpdateGitSettingsRequest, UpdateGitSettingsResponse, UpdateGitSettingsResponses, UpdateGlobalMcpData, UpdateGlobalMcpErrors, UpdateGlobalMcpResponse, UpdateGlobalMcpResponses, UpdateGlobalSkillData, UpdateGlobalSkillErrors, UpdateGlobalSkillResponse, UpdateGlobalSkillResponses, UpdateIncidentStatusData, UpdateIncidentStatusErrors, UpdateIncidentStatusRequest, UpdateIncidentStatusResponse, UpdateIncidentStatusResponses, UpdateIpAccessControlData, UpdateIpAccessControlError, UpdateIpAccessControlErrors, UpdateIpAccessControlRequest, UpdateIpAccessControlResponse, UpdateIpAccessControlResponses, UpdateKvRequest, UpdateKvResponse, UpdateManagedDomainApiRequest, UpdateManagedDomainData, UpdateManagedDomainErrors, UpdateManagedDomainResponse, UpdateManagedDomainResponses, UpdateMcpData, UpdateMcpErrors, UpdateMcpRequest, UpdateMcpResponse, UpdateMcpResponses, UpdateMemberRoleRequest, UpdateMetricAlertRequest, UpdateNotificationEmailProviderData, UpdateNotificationEmailProviderErrors, UpdateNotificationEmailProviderRequest, UpdateNotificationEmailProviderResponse, UpdateNotificationEmailProviderResponses, UpdateNotificationProviderData, UpdateNotificationProviderErrors, UpdateNotificationProviderResponse, UpdateNotificationProviderResponses, UpdateOidcProviderData, UpdateOidcProviderRequest, UpdateOidcProviderResponse, UpdateOidcProviderResponses, UpdatePreferencesData, UpdatePreferencesErrors, UpdatePreferencesRequest, UpdatePreferencesResponse, UpdatePreferencesResponses, UpdateProjectData, UpdateProjectDeploymentConfigData, UpdateProjectDeploymentConfigErrors, UpdateProjectDeploymentConfigResponse, UpdateProjectDeploymentConfigResponses, UpdateProjectErrors, UpdateProjectResponse, UpdateProjectResponses, UpdateProjectSecretData, UpdateProjectSecretErrors, UpdateProjectSecretRequest, UpdateProjectSecretResponse, UpdateProjectSecretResponses, UpdateProjectSettingsData, UpdateProjectSettingsErrors, UpdateProjectSettingsRequest, UpdateProjectSettingsResponse, UpdateProjectSettingsResponses, UpdateProviderCredentialsRequest, UpdateProviderData, UpdateProviderErrors, UpdateProviderKeyData, UpdateProviderKeyError, UpdateProviderKeyErrors, UpdateProviderKeyRequest, UpdateProviderKeyResponse, UpdateProviderKeyResponses, UpdateProviderRequest, UpdateProviderResponse, UpdateProviderResponses, UpdateRouteData, UpdateRouteErrors, UpdateRouteRequest, UpdateRouteResponse, UpdateRouteResponses, UpdateS3SourceData, UpdateS3SourceError, UpdateS3SourceErrors, UpdateS3SourceRequest, UpdateS3SourceResponse, UpdateS3SourceResponses, UpdateSecretBody, UpdateSelfData, UpdateSelfErrors, UpdateSelfRequest, UpdateSelfResponse, UpdateSelfResponses, UpdateServiceData, UpdateServiceErrors, UpdateServiceResourcesData, UpdateServiceResourcesErrors, UpdateServiceResourcesResponse, UpdateServiceResourcesResponses, UpdateServiceResponse, UpdateServiceResponses, UpdateSessionDurationData, UpdateSessionDurationError, UpdateSessionDurationErrors, UpdateSessionDurationRequest, UpdateSessionDurationResponse, UpdateSessionDurationResponse2, UpdateSessionDurationResponses, UpdateSettingsData, UpdateSettingsErrors, UpdateSettingsResponse, UpdateSettingsResponses, UpdateSkillData, UpdateSkillErrors, UpdateSkillRequest, UpdateSkillResponse, UpdateSkillResponses, UpdateSlackProviderData, UpdateSlackProviderErrors, UpdateSlackProviderRequest, UpdateSlackProviderResponse, UpdateSlackProviderResponses, UpdateSpeedMetricsData, UpdateSpeedMetricsError, UpdateSpeedMetricsErrors, UpdateSpeedMetricsPayload, UpdateSpeedMetricsResponse, UpdateSpeedMetricsResponses, UpdateStatusResponse, UpdateTeamData, UpdateTeamErrors, UpdateTeamMemberRoleData, UpdateTeamMemberRoleErrors, UpdateTeamMemberRoleResponse, UpdateTeamMemberRoleResponses, UpdateTeamRequest, UpdateTeamResponse, UpdateTeamResponses, UpdateTokenRequest, UpdateTokenResponse, UpdateUserData, UpdateUserErrors, UpdateUserRequest, UpdateUserResponse, UpdateUserResponses, UpdateWebhookData, UpdateWebhookErrors, UpdateWebhookProviderData, UpdateWebhookProviderErrors, UpdateWebhookProviderRequest, UpdateWebhookProviderResponse, UpdateWebhookProviderResponses, UpdateWebhookRequestBody, UpdateWebhookResponse, UpdateWebhookResponses, UpgradeExternalServiceRequest, UpgradePreviewGatewayData, UpgradePreviewGatewayResponse, UpgradePreviewGatewayResponses, UpgradeRequest, UpgradeServiceData, UpgradeServiceErrors, UpgradeServiceResponse, UpgradeServiceResponses, UploadGlobalSkillData, UploadGlobalSkillErrors, UploadGlobalSkillResponse, UploadGlobalSkillResponses, UploadReleaseFileData, UploadReleaseFileErrors, UploadReleaseFileResponse, UploadReleaseFileResponses, UploadSkillData, UploadSkillErrors, UploadSkillResponse, UploadSkillResponses, UploadSourceFileData, UploadSourceFileErrors, UploadSourceFileResponse, UploadSourceFileResponses, UploadSourceMapData, UploadSourceMapErrors, UploadSourceMapResponse, UploadSourceMapResponses, UploadStaticBundleData, UploadStaticBundleErrors, UploadStaticBundleResponse, UploadStaticBundleResponses, UpsertAgentRequest, UpsertSecretData, UpsertSecretErrors, UpsertSecretRequest, UpsertSecretResponse, UpsertSecretResponses, UptimeDataPoint, UptimeHistoryResponse, UsageFilter, UsageInfo, UsageLogEntry, UsageLogPage, UsageQueryParams, UsageSource, UsageSummary, UserResponse, ValidateConnectionData, ValidateConnectionErrors, ValidateConnectionResponse, ValidateConnectionResponses, ValidateEmailData, ValidateEmailErrors, ValidateEmailRequest, ValidateEmailResponse, ValidateEmailResponse2, ValidateEmailResponses, ValidationLevel, ValidationReport, ValidationResponse, ValidationResult, ValidationStatus, ValidationSummary, VerifyAndEnableMfaData, VerifyAndEnableMfaErrors, VerifyAndEnableMfaResponse, VerifyAndEnableMfaResponses, VerifyDomainData, VerifyDomainErrors, VerifyDomainResponse, VerifyDomainResponses, VerifyEmailData, VerifyEmailErrors, VerifyEmailResponse, VerifyEmailResponses, VerifyManagedDomainData, VerifyManagedDomainErrors, VerifyManagedDomainResponse, VerifyManagedDomainResponses, VerifyMfaChallengeData, VerifyMfaChallengeErrors, VerifyMfaChallengeResponse, VerifyMfaChallengeResponses, VerifyMfaRequest, VerifyStepUpData, VerifyStepUpErrors, VerifyStepUpRequest, VerifyStepUpResponse, VerifyStepUpResponses, ViewItem, ViewsOverTime, ViewsOverTimeQuery, VisitorDetails, VisitorFacets, VisitorFacetsQuery, VisitorFacetValue, VisitorInfo, VisitorJourneyQuery, VisitorJourneyResponse, VisitorLocationsQuery, VisitorRecord, VisitorSegmentFilters, VisitorSessionsQuery, VisitorSessionsResponse, VisitorsListQuery, VisitorsResponse, VisitorStats, VisitorWithGeolocation, VolumeMount, VolumeType, VulnerabilityResponse, WakeEnvironmentData, WakeEnvironmentErrors, WakeEnvironmentResponse, WakeEnvironmentResponses, WalWarning, WalWarningSeverity, WebhookConfig, WebhookDeliveryResponse, WebhookResponse, WebhookTriggerData, WebhookTriggerErrors, WebhookTriggerRequest, WebhookTriggerResponse, WebhookTriggerResponse2, WebhookTriggerResponses, WorkflowDryRunData, WorkflowDryRunErrors, WorkflowDryRunRequest, WorkflowDryRunResponse, WorkflowDryRunResponses, WorkloadDescriptor, WorkloadId, WorkloadStatus, WorkloadType, WriteFileBody, WriteFileData, WriteFileErrors, WriteFileResponse, WriteFileResponses, WriteFilesBody, WriteFilesData, WriteFilesErrors, WriteFilesResponse, WriteFilesResponse2, WriteFilesResponses, ZoneListResponse } from './types.gen'; diff --git a/web/src/api/client/sdk.gen.ts b/web/src/api/client/sdk.gen.ts index 7f564a1c2..d48d9e084 100644 --- a/web/src/api/client/sdk.gen.ts +++ b/web/src/api/client/sdk.gen.ts @@ -2,7 +2,7 @@ import { type Client, type ClientMeta, formDataBodySerializer, type Options as Options2, type RequestResult, type ServerSentEventsResult, type TDataShape } from './client'; import { client } from './client.gen'; -import type { AcknowledgeAlarmData, AcknowledgeAlarmErrors, AcknowledgeAlarmResponses, ActivateAiProviderData, ActivateAiProviderErrors, ActivateAiProviderResponses, ActivateApiKeyData, ActivateApiKeyErrors, ActivateApiKeyResponses, ActivateConnectionData, ActivateConnectionErrors, ActivateConnectionResponses, ActivateProviderData, ActivateProviderErrors, ActivateProviderResponses, AddClusterMemberData, AddClusterMemberErrors, AddClusterMemberResponses, AddContextData, AddContextErrors, AddContextResponses, AddEnvironmentDomainData, AddEnvironmentDomainErrors, AddEnvironmentDomainResponses, AddEventsData, AddEventsErrors, AddEventsResponses, AddManagedDomainData, AddManagedDomainErrors, AddManagedDomainResponses, AddSessionReplayEventsData, AddSessionReplayEventsErrors, AddSessionReplayEventsResponses, AddTeamMemberData, AddTeamMemberErrors, AddTeamMemberResponses, AdminDrainNodeData, AdminDrainNodeErrors, AdminDrainNodeResponses, AdminDrainStatusData, AdminDrainStatusErrors, AdminDrainStatusResponses, AdminGetNodeData, AdminGetNodeErrors, AdminGetNodeResponses, AdminListNodeContainersData, AdminListNodeContainersErrors, AdminListNodeContainersResponses, AdminListNodesData, AdminListNodesErrors, AdminListNodesResponses, AdminRemoveNodeData, AdminRemoveNodeErrors, AdminRemoveNodeResponses, AdminUndrainNodeData, AdminUndrainNodeErrors, AdminUndrainNodeResponses, ApplyHostnameModeData, ApplyHostnameModeErrors, ApplyHostnameModeResponses, ArchiveConversationData, ArchiveConversationErrors, ArchiveConversationResponses, ArchiveFlagData, ArchiveFlagErrors, ArchiveFlagResponses, AssignRoleData, AssignRoleErrors, AssignRoleResponses, AttachScheduleServicesData, AttachScheduleServicesErrors, AttachScheduleServicesResponses, BlobCopyData, BlobCopyErrors, BlobCopyResponses, BlobDeleteData, BlobDeleteErrors, BlobDeleteResponses, BlobDisableData, BlobDisableErrors, BlobDisableResponses, BlobDownloadData, BlobDownloadErrors, BlobDownloadResponses, BlobEnableData, BlobEnableErrors, BlobEnableResponses, BlobHeadData, BlobHeadErrors, BlobHeadResponses, BlobListData, BlobListErrors, BlobListResponses, BlobPutData, BlobPutErrors, BlobPutResponses, BlobStatusData, BlobStatusErrors, BlobStatusResponses, BlobUpdateData, BlobUpdateErrors, BlobUpdateResponses, CancelBackupData, CancelBackupErrors, CancelBackupResponses, CancelData, CancelDeploymentData, CancelDeploymentErrors, CancelDeploymentResponses, CancelDomainOrderData, CancelDomainOrderErrors, CancelDomainOrderResponses, CancelErrors, CancelPgUpgradeData, CancelPgUpgradeErrors, CancelPgUpgradeResponses, CancelResponses, CancelRunData, CancelRunErrors, CancelRunResponses, CancelScheduleRunData, CancelScheduleRunErrors, CancelScheduleRunResponses, ChangePasswordSelfData, ChangePasswordSelfErrors, ChangePasswordSelfResponses, ChangeProjectSourceData, ChangeProjectSourceErrors, ChangeProjectSourceResponses, ChatCompletionsData, ChatCompletionsErrors, ChatCompletionsResponses, CheckAnalyticsHasEventsData, CheckAnalyticsHasEventsErrors, CheckAnalyticsHasEventsResponses, CheckCommitExistsData, CheckCommitExistsErrors, CheckCommitExistsResponses, CheckDomainStatusData, CheckDomainStatusErrors, CheckDomainStatusResponses, CheckExplorerSupportData, CheckExplorerSupportErrors, CheckExplorerSupportResponses, CheckIpBlockedData, CheckIpBlockedErrors, CheckIpBlockedResponses, CheckProviderDeletionSafetyData, CheckProviderDeletionSafetyErrors, CheckProviderDeletionSafetyResponses, ChunkUploadOptionsData, ChunkUploadOptionsResponses, CleanupExpiredBackupsData, CleanupExpiredBackupsErrors, CleanupExpiredBackupsResponses, ClearPreviewPasswordData, ClearPreviewPasswordErrors, ClearPreviewPasswordResponses, CliDeviceApproveData, CliDeviceApproveErrors, CliDeviceApproveResponses, CliDeviceDenyData, CliDeviceDenyErrors, CliDeviceDenyResponses, CliDeviceLookupData, CliDeviceLookupErrors, CliDeviceLookupResponses, CliDevicePollData, CliDevicePollErrors, CliDevicePollResponses, CliDeviceStartData, CliDeviceStartErrors, CliDeviceStartResponses, CliLogoutData, CliLogoutErrors, CliLogoutResponses, CmdData, CmdErrors, CmdKillData, CmdKillErrors, CmdKillResponses, CmdLogsData, CmdLogsErrors, CmdLogsResponses, CmdResponses, ConfirmPendingActionData, ConfirmPendingActionErrors, ConfirmPendingActionResponses, ContainerMetricsGetHistoryData, ContainerMetricsGetHistoryErrors, ContainerMetricsGetHistoryResponses, CreateAgentData, CreateAgentErrors, CreateAgentResponses, CreateAlertData, CreateAlertErrors, CreateAlertResponses, CreateAlertRuleData, CreateAlertRuleErrors, CreateAlertRuleResponses, CreateApiKeyData, CreateApiKeyErrors, CreateApiKeyResponses, CreateBackupScheduleData, CreateBackupScheduleErrors, CreateBackupScheduleResponses, CreateBitbucketProviderData, CreateBitbucketProviderErrors, CreateBitbucketProviderResponses, CreateCloudflareProviderData, CreateCloudflareProviderErrors, CreateCloudflareProviderResponses, CreateConversationData, CreateConversationErrors, CreateConversationResponses, CreateCustomDomainData, CreateCustomDomainErrors, CreateCustomDomainResponses, CreateDashboardData, CreateDashboardErrors, CreateDashboardResponses, CreateDeploymentTokenData, CreateDeploymentTokenErrors, CreateDeploymentTokenResponses, CreateDnsProviderData, CreateDnsProviderErrors, CreateDnsProviderResponses, CreateDomainData, CreateDomainErrors, CreateDomainResponses, CreateDsnData, CreateDsnErrors, CreateDsnResponses, CreateEmailDomainData, CreateEmailDomainErrors, CreateEmailDomainResponses, CreateEmailProviderData, CreateEmailProviderErrors, CreateEmailProviderResponses, CreateEnvironmentData, CreateEnvironmentErrors, CreateEnvironmentResponses, CreateEnvironmentVariableData, CreateEnvironmentVariableErrors, CreateEnvironmentVariableResponses, CreateFlagData, CreateFlagErrors, CreateFlagResponses, CreateFunnelData, CreateFunnelErrors, CreateFunnelResponses, CreateGenericProviderData, CreateGenericProviderErrors, CreateGenericProviderResponses, CreateGiteaPatProviderData, CreateGiteaPatProviderErrors, CreateGiteaPatProviderResponses, CreateGithubPatProviderData, CreateGithubPatProviderErrors, CreateGithubPatProviderResponses, CreateGitlabOauthProviderData, CreateGitlabOauthProviderErrors, CreateGitlabOauthProviderResponses, CreateGitlabPatProviderData, CreateGitlabPatProviderErrors, CreateGitlabPatProviderResponses, CreateGitProviderData, CreateGitProviderErrors, CreateGitProviderResponses, CreateGlobalMcpData, CreateGlobalMcpErrors, CreateGlobalMcpResponses, CreateGlobalSkillData, CreateGlobalSkillErrors, CreateGlobalSkillResponses, CreateIncidentData, CreateIncidentErrors, CreateIncidentResponses, CreateIpAccessControlData, CreateIpAccessControlErrors, CreateIpAccessControlResponses, CreateMcpData, CreateMcpErrors, CreateMcpResponses, CreateMonitorData, CreateMonitorErrors, CreateMonitorResponses, CreateNotificationEmailProviderData, CreateNotificationEmailProviderErrors, CreateNotificationEmailProviderResponses, CreateNotificationProviderData, CreateNotificationProviderErrors, CreateNotificationProviderResponses, CreateOidcProviderData, CreateOidcProviderErrors, CreateOidcProviderResponses, CreateOidcRoleMappingData, CreateOidcRoleMappingResponses, CreateOrRecreateOrderData, CreateOrRecreateOrderErrors, CreateOrRecreateOrderResponses, CreatePlanData, CreatePlanErrors, CreatePlanResponses, CreatePrData, CreatePrErrors, CreateProjectData, CreateProjectErrors, CreateProjectFromTemplateData, CreateProjectFromTemplateErrors, CreateProjectFromTemplateResponses, CreateProjectReleaseData, CreateProjectReleaseErrors, CreateProjectReleaseResponses, CreateProjectResponses, CreateProjectSecretData, CreateProjectSecretErrors, CreateProjectSecretResponses, CreateProviderKeyData, CreateProviderKeyErrors, CreateProviderKeyResponses, CreatePrResponses, CreateReleaseData, CreateReleaseErrors, CreateReleaseResponses, CreateRouteData, CreateRouteErrors, CreateRouteResponses, CreateS3SourceData, CreateS3SourceErrors, CreateS3SourceResponses, CreateSandboxData, CreateSandboxErrors, CreateSandboxResponses, CreateServiceData, CreateServiceErrors, CreateServiceResponses, CreateSkillData, CreateSkillErrors, CreateSkillResponses, CreateSlackProviderData, CreateSlackProviderErrors, CreateSlackProviderResponses, CreateTeamData, CreateTeamErrors, CreateTeamResponses, CreateUserData, CreateUserErrors, CreateUserResponses, CreateWebhookData, CreateWebhookErrors, CreateWebhookProviderData, CreateWebhookProviderErrors, CreateWebhookProviderResponses, CreateWebhookResponses, DeactivateApiKeyData, DeactivateApiKeyErrors, DeactivateApiKeyResponses, DeactivateConnectionData, DeactivateConnectionErrors, DeactivateConnectionResponses, DeactivateProviderData, DeactivateProviderErrors, DeactivateProviderResponses, DeleteAgentData, DeleteAgentErrors, DeleteAgentResponses, DeleteAlertData, DeleteAlertErrors, DeleteAlertResponses, DeleteAlertRuleData, DeleteAlertRuleErrors, DeleteAlertRuleResponses, DeleteApiKeyData, DeleteApiKeyErrors, DeleteApiKeyResponses, DeleteBackupData, DeleteBackupErrors, DeleteBackupResponses, DeleteBackupScheduleData, DeleteBackupScheduleErrors, DeleteBackupScheduleResponses, DeleteConnectionData, DeleteConnectionErrors, DeleteConnectionResponses, DeleteCustomDomainData, DeleteCustomDomainErrors, DeleteCustomDomainResponses, DeleteDashboardData, DeleteDashboardErrors, DeleteDashboardResponses, DeleteDeploymentTokenData, DeleteDeploymentTokenErrors, DeleteDeploymentTokenResponses, DeleteDnsProviderData, DeleteDnsProviderErrors, DeleteDnsProviderResponses, DeleteDomainData, DeleteDomainErrors, DeleteDomainResponses, DeleteEmailDomainData, DeleteEmailDomainErrors, DeleteEmailDomainResponses, DeleteEmailProviderData, DeleteEmailProviderErrors, DeleteEmailProviderResponses, DeleteEnvironmentData, DeleteEnvironmentDomainData, DeleteEnvironmentDomainErrors, DeleteEnvironmentDomainResponses, DeleteEnvironmentErrors, DeleteEnvironmentResponses, DeleteEnvironmentVariableData, DeleteEnvironmentVariableErrors, DeleteEnvironmentVariableResponses, DeleteExternalImageData, DeleteExternalImageErrors, DeleteExternalImageResponses, DeleteFunnelData, DeleteFunnelErrors, DeleteFunnelResponses, DeleteGitProviderData, DeleteGitProviderErrors, DeleteGitProviderResponses, DeleteGlobalMcpData, DeleteGlobalMcpErrors, DeleteGlobalMcpResponses, DeleteGlobalSkillData, DeleteGlobalSkillErrors, DeleteGlobalSkillResponses, DeleteIpAccessControlData, DeleteIpAccessControlErrors, DeleteIpAccessControlResponses, DeleteMcpData, DeleteMcpErrors, DeleteMcpResponses, DeleteMonitorData, DeleteMonitorErrors, DeleteMonitorResponses, DeleteNotificationProviderData, DeleteNotificationProviderErrors, DeleteNotificationProviderResponses, DeleteOidcProviderData, DeleteOidcProviderResponses, DeleteOidcRoleMappingData, DeleteOidcRoleMappingResponses, DeletePreferencesData, DeletePreferencesErrors, DeletePreferencesResponses, DeleteProjectData, DeleteProjectErrors, DeleteProjectResponses, DeleteProjectSecretData, DeleteProjectSecretErrors, DeleteProjectSecretResponses, DeleteProviderKeyData, DeleteProviderKeyErrors, DeleteProviderKeyResponses, DeleteProviderSafelyData, DeleteProviderSafelyErrors, DeleteProviderSafelyResponses, DeleteReleaseSourceFilesData, DeleteReleaseSourceFilesErrors, DeleteReleaseSourceFilesResponses, DeleteReleaseSourceMapsData, DeleteReleaseSourceMapsErrors, DeleteReleaseSourceMapsResponses, DeleteRouteData, DeleteRouteErrors, DeleteRouteResponses, DeleteS3SourceData, DeleteS3SourceErrors, DeleteS3SourceResponses, DeleteScanData, DeleteScanErrors, DeleteScanResponses, DeleteSecretData, DeleteSecretErrors, DeleteSecretResponses, DeleteServiceData, DeleteServiceErrors, DeleteServiceResponses, DeleteSessionReplayData, DeleteSessionReplayErrors, DeleteSessionReplayResponses, DeleteSkillData, DeleteSkillErrors, DeleteSkillResponses, DeleteSourceMapData, DeleteSourceMapErrors, DeleteSourceMapResponses, DeleteStaticBundleData, DeleteStaticBundleErrors, DeleteStaticBundleResponses, DeleteTeamData, DeleteTeamErrors, DeleteTeamResponses, DeleteUserData, DeleteUserErrors, DeleteUserResponses, DeleteWebhookData, DeleteWebhookErrors, DeleteWebhookResponses, DeployFromImageData, DeployFromImageErrors, DeployFromImageResponses, DeployFromImageUploadData, DeployFromImageUploadErrors, DeployFromImageUploadResponses, DeployFromStaticData, DeployFromStaticErrors, DeployFromStaticResponses, DeployFromUploadedSourceData, DeployFromUploadedSourceErrors, DeployFromUploadedSourceResponses, DeploymentMetricsGetLatestData, DeploymentMetricsGetLatestErrors, DeploymentMetricsGetLatestResponses, DeploymentMetricsGetRangeData, DeploymentMetricsGetRangeErrors, DeploymentMetricsGetRangeResponses, DeploymentMetricsToggleData, DeploymentMetricsToggleErrors, DeploymentMetricsToggleResponses, DestroySandboxData, DestroySandboxErrors, DestroySandboxResponses, DetachScheduleServiceData, DetachScheduleServiceErrors, DetachScheduleServiceResponses, DetectPublicPresetsData, DetectPublicPresetsErrors, DetectPublicPresetsResponses, DisableBackupScheduleData, DisableBackupScheduleErrors, DisableBackupScheduleResponses, DisableMfaData, DisableMfaErrors, DisableMfaResponses, DisconnectCloudData, DisconnectCloudResponses, DiscoverWorkloadsData, DiscoverWorkloadsErrors, DiscoverWorkloadsResponses, DomainData, DomainErrors, DomainResponses, DownloadGlobalSkillArchiveData, DownloadGlobalSkillArchiveErrors, DownloadGlobalSkillArchiveResponses, DownloadObjectData, DownloadObjectErrors, DownloadObjectResponses, DownloadSkillArchiveData, DownloadSkillArchiveErrors, DownloadSkillArchiveResponses, EmailStatusData, EmailStatusErrors, EmailStatusResponses, EmbeddingsData, EmbeddingsErrors, EmbeddingsResponses, EnableBackupScheduleData, EnableBackupScheduleErrors, EnableBackupScheduleResponses, EnrichVisitorData, EnrichVisitorErrors, EnrichVisitorResponses, EnrollCloudData, EnrollCloudResponses, ExecData, ExecDetachedData, ExecDetachedErrors, ExecDetachedResponses, ExecErrors, ExecResponses, ExecuteDeploymentOperationData, ExecuteDeploymentOperationErrors, ExecuteDeploymentOperationResponses, ExecuteImportData, ExecuteImportErrors, ExecuteImportResponses, ExtendTimeoutData, ExtendTimeoutErrors, ExtendTimeoutResponses, ExternalServiceEnablePgStatStatementsData, ExternalServiceEnablePgStatStatementsErrors, ExternalServiceEnablePgStatStatementsResponses, ExternalServiceMetricsByDatabaseData, ExternalServiceMetricsByDatabaseErrors, ExternalServiceMetricsByDatabaseResponses, ExternalServiceMetricsCreateAlertRuleData, ExternalServiceMetricsCreateAlertRuleErrors, ExternalServiceMetricsCreateAlertRuleResponses, ExternalServiceMetricsDeleteAlertRuleData, ExternalServiceMetricsDeleteAlertRuleErrors, ExternalServiceMetricsDeleteAlertRuleResponses, ExternalServiceMetricsGetAlertRulesData, ExternalServiceMetricsGetAlertRulesErrors, ExternalServiceMetricsGetAlertRulesResponses, ExternalServiceMetricsGetLatestData, ExternalServiceMetricsGetLatestErrors, ExternalServiceMetricsGetLatestResponses, ExternalServiceMetricsGetRangeData, ExternalServiceMetricsGetRangeErrors, ExternalServiceMetricsGetRangeResponses, ExternalServiceMetricsStatusData, ExternalServiceMetricsStatusErrors, ExternalServiceMetricsStatusResponses, ExternalServiceMetricsToggleData, ExternalServiceMetricsToggleErrors, ExternalServiceMetricsToggleResponses, ExternalServiceMetricsUpdateAlertRuleData, ExternalServiceMetricsUpdateAlertRuleErrors, ExternalServiceMetricsUpdateAlertRuleResponses, ExternalServiceResetPgStatStatementsData, ExternalServiceResetPgStatStatementsErrors, ExternalServiceResetPgStatStatementsResponses, FinalizeOrderData, FinalizeOrderErrors, FinalizeOrderResponses, FinalizeProjectReleaseData, FinalizeProjectReleaseErrors, FinalizeProjectReleaseResponses, FindConversationData, FindConversationErrors, FindConversationResponses, GenerateJoinTokenData, GenerateJoinTokenErrors, GenerateJoinTokenResponses, GeneratePresetDockerfileData, GeneratePresetDockerfileErrors, GeneratePresetDockerfileResponses, GetAccessInfoData, GetAccessInfoErrors, GetAccessInfoResponses, GetActiveVisitorsData, GetActiveVisitorsErrors, GetActiveVisitorsResponses, GetActivityGraphData, GetActivityGraphErrors, GetActivityGraphResponses, GetAdminGateData, GetAdminGateErrors, GetAdminGateResponses, GetAgentData, GetAgentErrors, GetAgentResponses, GetAggregatedBucketsData, GetAggregatedBucketsErrors, GetAggregatedBucketsResponses, GetAiAgentBreakdownData, GetAiAgentBreakdownErrors, GetAiAgentBreakdownResponses, GetAiAgentPagesData, GetAiAgentPagesErrors, GetAiAgentPagesResponses, GetAiAgentTimelineData, GetAiAgentTimelineErrors, GetAiAgentTimelineResponses, GetAiPageBreakdownData, GetAiPageBreakdownErrors, GetAiPageBreakdownResponses, GetAiStatusBreakdownData, GetAiStatusBreakdownErrors, GetAiStatusBreakdownResponses, GetAlertData, GetAlertErrors, GetAlertResponses, GetAlertRuleData, GetAlertRuleErrors, GetAlertRuleResponses, GetAllRepositoriesByNameData, GetAllRepositoriesByNameErrors, GetAllRepositoriesByNameResponses, GetAnalyticsActiveVisitorsData, GetAnalyticsActiveVisitorsErrors, GetAnalyticsActiveVisitorsResponses, GetAnalyticsEventsCountData, GetAnalyticsEventsCountErrors, GetAnalyticsEventsCountResponses, GetAnalyticsSessionEventsData, GetAnalyticsSessionEventsErrors, GetAnalyticsSessionEventsResponses, GetAnalyticsVisitorSessionsData, GetAnalyticsVisitorSessionsErrors, GetAnalyticsVisitorSessionsResponses, GetApiKeyData, GetApiKeyErrors, GetApiKeyPermissionsData, GetApiKeyPermissionsErrors, GetApiKeyPermissionsResponses, GetApiKeyResponses, GetAuditLogData, GetAuditLogErrors, GetAuditLogResponses, GetBackupData, GetBackupErrors, GetBackupResponses, GetBackupScheduleData, GetBackupScheduleErrors, GetBackupScheduleResponses, GetBranchesByRepositoryIdData, GetBranchesByRepositoryIdErrors, GetBranchesByRepositoryIdResponses, GetBucketedIncidentsData, GetBucketedIncidentsErrors, GetBucketedIncidentsResponses, GetBucketedStatusData, GetBucketedStatusErrors, GetBucketedStatusResponses, GetChallengeTokenData, GetChallengeTokenErrors, GetChallengeTokenResponses, GetChatReadinessData, GetChatReadinessErrors, GetChatReadinessResponses, GetCliStatusData, GetCliStatusErrors, GetCliStatusResponses, GetCloudCapabilityData, GetCloudCapabilityResponses, GetCloudStatusData, GetCloudStatusResponses, GetClusterHealthData, GetClusterHealthErrors, GetClusterHealthResponses, GetClusterMemberData, GetClusterMemberErrors, GetClusterMemberResponses, GetCmdData, GetCmdErrors, GetCmdResponses, GetContainerDetailData, GetContainerDetailErrors, GetContainerDetailResponses, GetContainerEnvironmentVariableData, GetContainerEnvironmentVariableErrors, GetContainerEnvironmentVariableResponses, GetContainerInfoData, GetContainerInfoErrors, GetContainerInfoResponses, GetContainerLogsByIdData, GetContainerLogsByIdErrors, GetContainerLogsData, GetContainerLogsErrors, GetContainerMetricsData, GetContainerMetricsErrors, GetContainerMetricsResponses, GetConversationData, GetConversationDetailData, GetConversationDetailErrors, GetConversationDetailResponses, GetConversationErrors, GetConversationResponses, GetConversationsData, GetConversationsErrors, GetConversationsResponses, GetCronByIdData, GetCronByIdErrors, GetCronByIdResponses, GetCronExecutionsData, GetCronExecutionsErrors, GetCronExecutionsResponses, GetCrossProjectTraceSiblingsData, GetCrossProjectTraceSiblingsErrors, GetCrossProjectTraceSiblingsResponses, GetCurrentMonitorStatusData, GetCurrentMonitorStatusErrors, GetCurrentMonitorStatusResponses, GetCurrentUserData, GetCurrentUserErrors, GetCurrentUserResponses, GetCustomDomainData, GetCustomDomainErrors, GetCustomDomainResponses, GetDashboardData, GetDashboardErrors, GetDashboardProjectsAnalyticsData, GetDashboardProjectsAnalyticsErrors, GetDashboardProjectsAnalyticsResponses, GetDashboardResponses, GetDeliveryData, GetDeliveryErrors, GetDeliveryResponses, GetDeploymentContainerLogContentData, GetDeploymentContainerLogContentErrors, GetDeploymentContainerLogContentResponses, GetDeploymentData, GetDeploymentErrors, GetDeploymentJobLogsData, GetDeploymentJobLogsErrors, GetDeploymentJobLogsResponses, GetDeploymentJobsData, GetDeploymentJobsErrors, GetDeploymentJobsResponses, GetDeploymentOperationsData, GetDeploymentOperationsErrors, GetDeploymentOperationsResponses, GetDeploymentOperationStatusData, GetDeploymentOperationStatusErrors, GetDeploymentOperationStatusResponses, GetDeploymentResponses, GetDeploymentTokenData, GetDeploymentTokenErrors, GetDeploymentTokenResponses, GetDiskStatusData, GetDiskStatusErrors, GetDiskStatusResponses, GetDnsChangesData, GetDnsChangesErrors, GetDnsChangesResponses, GetDnsProviderData, GetDnsProviderErrors, GetDnsProviderResponses, GetDomainByHostData, GetDomainByHostErrors, GetDomainByHostResponses, GetDomainByIdData, GetDomainByIdErrors, GetDomainByIdResponses, GetDomainByNameData, GetDomainByNameErrors, GetDomainByNameResponses, GetDomainData, GetDomainDnsRecordsData, GetDomainDnsRecordsErrors, GetDomainDnsRecordsResponses, GetDomainErrors, GetDomainOrderData, GetDomainOrderErrors, GetDomainOrderResponses, GetDomainResponses, GetEmailData, GetEmailErrors, GetEmailEventsData, GetEmailEventsErrors, GetEmailEventsResponses, GetEmailLinksData, GetEmailLinksErrors, GetEmailLinksResponses, GetEmailProviderData, GetEmailProviderErrors, GetEmailProviderResponses, GetEmailResponses, GetEmailStatsData, GetEmailStatsErrors, GetEmailStatsResponses, GetEmailTrackingData, GetEmailTrackingErrors, GetEmailTrackingResponses, GetEmailTrackingStatusData, GetEmailTrackingStatusErrors, GetEmailTrackingStatusResponses, GetEntityInfoData, GetEntityInfoErrors, GetEntityInfoResponses, GetEnvironmentCronsData, GetEnvironmentCronsErrors, GetEnvironmentCronsResponses, GetEnvironmentData, GetEnvironmentDomainsData, GetEnvironmentDomainsErrors, GetEnvironmentDomainsResponses, GetEnvironmentErrors, GetEnvironmentResponses, GetEnvironmentsData, GetEnvironmentsErrors, GetEnvironmentsResponses, GetEnvironmentVariablesData, GetEnvironmentVariablesErrors, GetEnvironmentVariablesResponses, GetEnvironmentVariableValueData, GetEnvironmentVariableValueErrors, GetEnvironmentVariableValueResponses, GetErrorDashboardStatsData, GetErrorDashboardStatsErrors, GetErrorDashboardStatsResponses, GetErrorEventData, GetErrorEventErrors, GetErrorEventResponses, GetErrorGroupData, GetErrorGroupErrors, GetErrorGroupResponses, GetErrorStatsData, GetErrorStatsErrors, GetErrorStatsResponses, GetErrorTimeSeriesData, GetErrorTimeSeriesErrors, GetErrorTimeSeriesResponses, GetEventDetailData, GetEventDetailErrors, GetEventDetailResponses, GetEventEntriesData, GetEventEntriesErrors, GetEventEntriesResponses, GetEventsCountData, GetEventsCountErrors, GetEventsCountResponses, GetEventsTimelineData, GetEventsTimelineErrors, GetEventsTimelineResponses, GetEventTypeBreakdownData, GetEventTypeBreakdownErrors, GetEventTypeBreakdownResponses, GetEventVisitorsData, GetEventVisitorsErrors, GetEventVisitorsResponses, GetExternalImageData, GetExternalImageErrors, GetExternalImageResponses, GetFileData, GetFileErrors, GetFileResponses, GetFlagData, GetFlagErrors, GetFlagResponses, GetFlagSnapshotData, GetFlagSnapshotErrors, GetFlagSnapshotResponses, GetFunnelMetricsData, GetFunnelMetricsErrors, GetFunnelMetricsResponses, GetGenaiTraceData, GetGenaiTraceErrors, GetGenaiTraceResponses, GetGeneralStatsData, GetGeneralStatsErrors, GetGeneralStatsResponses, GetGitProviderData, GetGitProviderErrors, GetGitProviderResponses, GetGlobalEventsData, GetGlobalEventsErrors, GetGlobalEventsResponses, GetGlobalEventStatsData, GetGlobalEventStatsErrors, GetGlobalEventStatsResponses, GetGlobalMcpData, GetGlobalMcpErrors, GetGlobalMcpResponses, GetGlobalSandboxStatusData, GetGlobalSandboxStatusErrors, GetGlobalSandboxStatusResponses, GetGlobalSkillData, GetGlobalSkillErrors, GetGlobalSkillResponses, GetGroupedPageMetricsData, GetGroupedPageMetricsErrors, GetGroupedPageMetricsResponses, GetHealthData, GetHealthErrors, GetHealthResponses, GetHourlyVisitsData, GetHourlyVisitsErrors, GetHourlyVisitsResponses, GetHttpChallengeDebugData, GetHttpChallengeDebugErrors, GetHttpChallengeDebugResponses, GetImportStatusData, GetImportStatusErrors, GetImportStatusResponses, GetIncidentData, GetIncidentErrors, GetIncidentResponses, GetIncidentUpdatesData, GetIncidentUpdatesErrors, GetIncidentUpdatesResponses, GetIpAccessControlData, GetIpAccessControlErrors, GetIpAccessControlResponses, GetIpGeolocationData, GetIpGeolocationErrors, GetIpGeolocationResponses, GetJoinTokenStatusData, GetJoinTokenStatusErrors, GetJoinTokenStatusResponses, GetLastDeploymentData, GetLastDeploymentErrors, GetLastDeploymentResponses, GetLatestScanData, GetLatestScanErrors, GetLatestScanResponses, GetLatestScansPerEnvironmentData, GetLatestScansPerEnvironmentErrors, GetLatestScansPerEnvironmentResponses, GetLiveVisitorsListData, GetLiveVisitorsListErrors, GetLiveVisitorsListResponses, GetLogContextData, GetLogContextErrors, GetLogContextResponses, GetMcpData, GetMcpErrors, GetMcpResponses, GetMetricsOverTimeData, GetMetricsOverTimeErrors, GetMetricsOverTimeResponses, GetMonitorData, GetMonitorErrors, GetMonitorResponses, GetNotificationProviderData, GetNotificationProviderErrors, GetNotificationProviderResponses, GetOnDemandCertStatusData, GetOnDemandCertStatusErrors, GetOnDemandCertStatusResponses, GetOrCreateDsnData, GetOrCreateDsnErrors, GetOrCreateDsnResponses, GetPageFlowData, GetPageFlowErrors, GetPageFlowResponses, GetPageHourlySessionsData, GetPageHourlySessionsErrors, GetPageHourlySessionsResponses, GetPagePathDetailData, GetPagePathDetailErrors, GetPagePathDetailResponses, GetPagePathsData, GetPagePathsErrors, GetPagePathsResponses, GetPagePathsSparklinesData, GetPagePathsSparklinesErrors, GetPagePathsSparklinesResponses, GetPagePathVisitorsData, GetPagePathVisitorsErrors, GetPagePathVisitorsResponses, GetPendingActionData, GetPendingActionErrors, GetPendingActionResponses, GetPerformanceMetricsData, GetPerformanceMetricsErrors, GetPerformanceMetricsResponses, GetPgUpgradeData, GetPgUpgradeErrors, GetPgUpgradeLogsData, GetPgUpgradeLogsErrors, GetPgUpgradeLogsResponses, GetPgUpgradeResponses, GetPipelineStatsData, GetPipelineStatsErrors, GetPipelineStatsResponses, GetPlatformInfoData, GetPlatformInfoErrors, GetPlatformInfoResponses, GetPostgresWalHealthData, GetPostgresWalHealthErrors, GetPostgresWalHealthResponses, GetPreferencesData, GetPreferencesErrors, GetPreferencesResponses, GetPreviewGatewayLogsData, GetPreviewGatewayLogsResponses, GetPreviewGatewaySettingsData, GetPreviewGatewaySettingsResponses, GetPreviewGatewayStatusData, GetPreviewGatewayStatusResponses, GetPricingData, GetPricingErrors, GetPricingResponses, GetPrivateIpData, GetPrivateIpErrors, GetPrivateIpResponses, GetProjectAlarmsSummaryData, GetProjectAlarmsSummaryErrors, GetProjectAlarmsSummaryResponses, GetProjectBySlugData, GetProjectBySlugErrors, GetProjectBySlugResponses, GetProjectData, GetProjectDeploymentsData, GetProjectDeploymentsErrors, GetProjectDeploymentsResponses, GetProjectErrors, GetProjectResponses, GetProjectsData, GetProjectsErrors, GetProjectServiceEnvironmentVariablesData, GetProjectServiceEnvironmentVariablesErrors, GetProjectServiceEnvironmentVariablesResponses, GetProjectSessionReplaysData, GetProjectSessionReplaysErrors, GetProjectSessionReplaysResponses, GetProjectsHealthData, GetProjectsHealthErrors, GetProjectsHealthResponses, GetProjectsMonitorHealthData, GetProjectsMonitorHealthErrors, GetProjectsMonitorHealthResponses, GetProjectsResponses, GetProjectStatisticsData, GetProjectStatisticsErrors, GetProjectStatisticsResponses, GetProjectTemplateData, GetProjectTemplateErrors, GetProjectTemplateResponses, GetPropertyBreakdownData, GetPropertyBreakdownErrors, GetPropertyBreakdownResponses, GetPropertyTimelineData, GetPropertyTimelineErrors, GetPropertyTimelineResponses, GetProviderConnectionsData, GetProviderConnectionsErrors, GetProviderConnectionsResponses, GetProviderMetadataData, GetProviderMetadataErrors, GetProviderMetadataResponses, GetProvidersMetadataData, GetProvidersMetadataErrors, GetProvidersMetadataResponses, GetProxyLogByIdData, GetProxyLogByIdErrors, GetProxyLogByIdResponses, GetProxyLogByRequestIdData, GetProxyLogByRequestIdErrors, GetProxyLogByRequestIdResponses, GetProxyLogsData, GetProxyLogsErrors, GetProxyLogsResponses, GetPublicBranchesData, GetPublicBranchesErrors, GetPublicBranchesResponses, GetPublicIpData, GetPublicIpErrors, GetPublicIpResponses, GetPublicRepositoryData, GetPublicRepositoryErrors, GetPublicRepositoryResponses, GetQuotaData, GetQuotaErrors, GetQuotaResponses, GetRecentActivityData, GetRecentActivityErrors, GetRecentActivityResponses, GetRemoteExternalImageData, GetRemoteExternalImageErrors, GetRemoteExternalImageResponses, GetRepositoryBranchesData, GetRepositoryBranchesErrors, GetRepositoryBranchesResponses, GetRepositoryByIdData, GetRepositoryByIdErrors, GetRepositoryByIdResponses, GetRepositoryByNameData, GetRepositoryByNameErrors, GetRepositoryByNameResponses, GetRepositoryPresetByNameData, GetRepositoryPresetByNameErrors, GetRepositoryPresetByNameResponses, GetRepositoryPresetLiveData, GetRepositoryPresetLiveErrors, GetRepositoryPresetLiveResponses, GetRepositoryTagsData, GetRepositoryTagsErrors, GetRepositoryTagsResponses, GetResolvedEnvironmentVariablesData, GetResolvedEnvironmentVariablesErrors, GetResolvedEnvironmentVariablesResponses, GetResolvedEnvironmentVariableValueData, GetResolvedEnvironmentVariableValueErrors, GetResolvedEnvironmentVariableValueResponses, GetRestoreCapabilitiesData, GetRestoreCapabilitiesErrors, GetRestoreCapabilitiesResponses, GetRestoreRunData, GetRestoreRunErrors, GetRestoreRunResponses, GetRouteData, GetRouteErrors, GetRouteResponses, GetRunData, GetRunErrors, GetRunResponses, GetRunWithLogsData, GetRunWithLogsErrors, GetRunWithLogsResponses, GetS3CredentialsData, GetS3CredentialsErrors, GetS3CredentialsResponses, GetS3SourceData, GetS3SourceErrors, GetS3SourceResponses, GetSandboxData, GetSandboxErrors, GetSandboxResponses, GetSandboxStatusData, GetSandboxStatusErrors, GetSandboxStatusResponses, GetScanByDeploymentData, GetScanByDeploymentErrors, GetScanByDeploymentResponses, GetScanData, GetScanErrors, GetScanResponses, GetScanVulnerabilitiesData, GetScanVulnerabilitiesErrors, GetScanVulnerabilitiesResponses, GetServiceBySlugData, GetServiceBySlugErrors, GetServiceBySlugResponses, GetServiceData, GetServiceEnvironmentVariableData, GetServiceEnvironmentVariableErrors, GetServiceEnvironmentVariableResponses, GetServiceEnvironmentVariablesData, GetServiceEnvironmentVariablesErrors, GetServiceEnvironmentVariablesResponses, GetServiceErrors, GetServiceHealthStatusData, GetServiceHealthStatusErrors, GetServiceHealthStatusResponses, GetServicePreviewEnvironmentVariableNamesData, GetServicePreviewEnvironmentVariableNamesErrors, GetServicePreviewEnvironmentVariableNamesResponses, GetServicePreviewEnvironmentVariablesMaskedData, GetServicePreviewEnvironmentVariablesMaskedErrors, GetServicePreviewEnvironmentVariablesMaskedResponses, GetServiceResponses, GetServiceRuntimeData, GetServiceRuntimeErrors, GetServiceRuntimeResponses, GetServiceStatsData, GetServiceStatsErrors, GetServiceStatsResponses, GetServiceTypeParametersData, GetServiceTypeParametersErrors, GetServiceTypeParametersResponses, GetServiceTypesData, GetServiceTypesErrors, GetServiceTypesResponses, GetSessionDetailsData, GetSessionDetailsErrors, GetSessionDetailsResponses, GetSessionEventsData, GetSessionEventsErrors, GetSessionEventsResponses, GetSessionLogsData, GetSessionLogsErrors, GetSessionLogsResponses, GetSessionReplayData, GetSessionReplayErrors, GetSessionReplayEventsData, GetSessionReplayEventsErrors, GetSessionReplayEventsResponses, GetSessionReplayResponses, GetSettingsData, GetSettingsErrors, GetSettingsResponses, GetSkillData, GetSkillErrors, GetSkillResponses, GetSlowQueriesData, GetSlowQueriesErrors, GetSlowQueriesResponses, GetStaticBundleData, GetStaticBundleErrors, GetStaticBundleResponses, GetStatusOverviewData, GetStatusOverviewErrors, GetStatusOverviewResponses, GetTagsByRepositoryIdData, GetTagsByRepositoryIdErrors, GetTagsByRepositoryIdResponses, GetTeamData, GetTeamErrors, GetTeamResponses, GetTimeBucketStatsData, GetTimeBucketStatsErrors, GetTimeBucketStatsResponses, GetTodayStatsData, GetTodayStatsErrors, GetTodayStatsResponses, GetTraceData, GetTraceErrors, GetTraceResponses, GetUnifiedTraceData, GetUnifiedTraceErrors, GetUnifiedTraceResponses, GetUniqueCountsData, GetUniqueCountsErrors, GetUniqueCountsResponses, GetUniqueEventsData, GetUniqueEventsErrors, GetUniqueEventsResponses, GetUpdateStatusData, GetUpdateStatusErrors, GetUpdateStatusResponses, GetUptimeHistoryData, GetUptimeHistoryErrors, GetUptimeHistoryResponses, GetUsageByProviderData, GetUsageByProviderErrors, GetUsageByProviderResponses, GetUsageRecentData, GetUsageRecentErrors, GetUsageRecentResponses, GetUsageSummaryData, GetUsageSummaryErrors, GetUsageSummaryResponses, GetUsageTimeseriesData, GetUsageTimeseriesErrors, GetUsageTimeseriesResponses, GetUsageTopModelsData, GetUsageTopModelsErrors, GetUsageTopModelsResponses, GetVisitorByGuidData, GetVisitorByGuidErrors, GetVisitorByGuidResponses, GetVisitorByIdData, GetVisitorByIdErrors, GetVisitorByIdResponses, GetVisitorDetailsData, GetVisitorDetailsErrors, GetVisitorDetailsResponses, GetVisitorFacetsData, GetVisitorFacetsErrors, GetVisitorFacetsResponses, GetVisitorInfoData, GetVisitorInfoErrors, GetVisitorInfoResponses, GetVisitorJourneyData, GetVisitorJourneyErrors, GetVisitorJourneyResponses, GetVisitorsData, GetVisitorsErrors, GetVisitorSessionsData, GetVisitorSessionsErrors, GetVisitorSessionsResponses, GetVisitorsResponses, GetVisitorStatsData, GetVisitorStatsErrors, GetVisitorStatsResponses, GetWebhookData, GetWebhookErrors, GetWebhookResponses, GrantProjectAccessData, GrantProjectAccessErrors, GrantProjectAccessResponses, HandleGitProviderOauthCallbackData, HandleGitProviderOauthCallbackErrors, HasAnalyticsEventsData, HasAnalyticsEventsErrors, HasAnalyticsEventsResponses, HasErrorGroupsData, HasErrorGroupsErrors, HasErrorGroupsResponses, HasPerformanceMetricsData, HasPerformanceMetricsErrors, HasPerformanceMetricsResponses, ImportExternalServiceData, ImportExternalServiceErrors, ImportExternalServiceResponses, IngestLogsByPathData, IngestLogsByPathErrors, IngestLogsByPathResponses, IngestLogsData, IngestLogsErrors, IngestLogsResponses, IngestMetricsByPathData, IngestMetricsByPathErrors, IngestMetricsByPathResponses, IngestMetricsData, IngestMetricsErrors, IngestMetricsResponses, IngestSentryEnvelopeData, IngestSentryEnvelopeErrors, IngestSentryEnvelopeResponses, IngestSentryEventData, IngestSentryEventErrors, IngestSentryEventResponses, IngestTracesByPathData, IngestTracesByPathErrors, IngestTracesByPathResponses, IngestTracesData, IngestTracesErrors, IngestTracesResponses, InitSessionReplayData, InitSessionReplayErrors, InitSessionReplayResponses, InspectDropArchiveData, InspectDropArchiveErrors, InspectDropArchiveResponses, JobLogsData, JobLogsErrors, JobLogsResponses, JobStatusData, JobStatusErrors, JobStatusResponses, KillJobData, KillJobErrors, KillJobResponses, KvDelData, KvDelErrors, KvDelResponses, KvDisableData, KvDisableErrors, KvDisableResponses, KvEnableData, KvEnableErrors, KvEnableResponses, KvExpireData, KvExpireErrors, KvExpireResponses, KvGetData, KvGetErrors, KvGetResponses, KvIncrData, KvIncrErrors, KvIncrResponses, KvKeysData, KvKeysErrors, KvKeysResponses, KvSetData, KvSetErrors, KvSetResponses, KvStatusData, KvStatusErrors, KvStatusResponses, KvTtlData, KvTtlErrors, KvTtlResponses, KvUpdateData, KvUpdateErrors, KvUpdateResponses, LatestRunForSourceData, LatestRunForSourceErrors, LatestRunForSourceResponses, LinkCustomDomainToCertificateData, LinkCustomDomainToCertificateErrors, LinkCustomDomainToCertificateResponses, LinkServiceToProjectData, LinkServiceToProjectErrors, LinkServiceToProjectResponses, ListAgentRunsData, ListAgentRunsErrors, ListAgentRunsResponses, ListAgentsData, ListAgentsErrors, ListAgentsResponses, ListAiProvidersData, ListAiProvidersErrors, ListAiProvidersResponses, ListAlertRulesData, ListAlertRulesErrors, ListAlertRulesResponses, ListAlertsData, ListAlertsErrors, ListAlertsResponses, ListAllConversationsData, ListAllConversationsErrors, ListAllConversationsResponses, ListAllRunsData, ListAllRunsErrors, ListAllRunsResponses, ListApiKeysData, ListApiKeysErrors, ListApiKeysResponses, ListAuditLogsData, ListAuditLogsErrors, ListAuditLogsResponses, ListAvailableContainersData, ListAvailableContainersErrors, ListAvailableContainersResponses, ListBackupAlertsData, ListBackupAlertsErrors, ListBackupAlertsResponses, ListBackupChildrenData, ListBackupChildrenErrors, ListBackupChildrenResponses, ListBackupSchedulesData, ListBackupSchedulesErrors, ListBackupSchedulesResponses, ListBackupsForScheduleData, ListBackupsForScheduleErrors, ListBackupsForScheduleResponses, ListCommitsByRepositoryIdData, ListCommitsByRepositoryIdErrors, ListCommitsByRepositoryIdResponses, ListConnectionsData, ListConnectionsErrors, ListConnectionsResponses, ListContainersAtPathData, ListContainersAtPathErrors, ListContainersAtPathResponses, ListContainersData, ListContainersErrors, ListContainersResponses, ListConversationsData, ListConversationsErrors, ListConversationsResponses, ListCustomDomainsForProjectData, ListCustomDomainsForProjectErrors, ListCustomDomainsForProjectResponses, ListDashboardsData, ListDashboardsErrors, ListDashboardsResponses, ListDeliveriesData, ListDeliveriesErrors, ListDeliveriesResponses, ListDeploymentContainerLogsData, ListDeploymentContainerLogsErrors, ListDeploymentContainerLogsResponses, ListDeploymentTokensData, ListDeploymentTokensErrors, ListDeploymentTokensResponses, ListDnsProvidersData, ListDnsProvidersErrors, ListDnsProvidersResponses, ListDomainsData, ListDomainsErrors, ListDomainsResponses, ListDsnsData, ListDsnsErrors, ListDsnsResponses, ListEmailDomainsData, ListEmailDomainsErrors, ListEmailDomainsResponses, ListEmailProvidersData, ListEmailProvidersErrors, ListEmailProvidersResponses, ListEmailsData, ListEmailsErrors, ListEmailsResponses, ListEnrollmentTokensData, ListEnrollmentTokensErrors, ListEnrollmentTokensResponses, ListEntitiesData, ListEntitiesErrors, ListEntitiesResponses, ListErrorEventsData, ListErrorEventsErrors, ListErrorEventsResponses, ListErrorGroupsData, ListErrorGroupsErrors, ListErrorGroupsResponses, ListEventsData, ListEventsResponses, ListEventTypesData, ListEventTypesResponses, ListExternalImagesData, ListExternalImagesErrors, ListExternalImagesResponses, ListExternalPluginsData, ListExternalPluginsErrors, ListExternalPluginsResponses, ListExternalServiceBackupsData, ListExternalServiceBackupsErrors, ListExternalServiceBackupsResponses, ListFlagsData, ListFlagsErrors, ListFlagsResponses, ListFunnelsData, ListFunnelsErrors, ListFunnelsResponses, ListGitProvidersData, ListGitProvidersErrors, ListGitProvidersResponses, ListGlobalMcpsData, ListGlobalMcpsErrors, ListGlobalMcpsResponses, ListGlobalSkillsData, ListGlobalSkillsErrors, ListGlobalSkillsResponses, ListIncidentsData, ListIncidentsErrors, ListIncidentsResponses, ListInsightsData, ListInsightsErrors, ListInsightsResponses, ListIpAccessControlData, ListIpAccessControlErrors, ListIpAccessControlResponses, ListJobsData, ListJobsErrors, ListJobsResponses, ListKnownAiAgentsData, ListKnownAiAgentsErrors, ListKnownAiAgentsResponses, ListManagedDomainsData, ListManagedDomainsErrors, ListManagedDomainsResponses, ListMcpsData, ListMcpsErrors, ListMcpsResponses, ListMetricLabelKeysData, ListMetricLabelKeysErrors, ListMetricLabelKeysResponses, ListMetricLabelValuesData, ListMetricLabelValuesErrors, ListMetricLabelValuesResponses, ListMetricNamesData, ListMetricNamesErrors, ListMetricNamesResponses, ListModelsData, ListModelsErrors, ListModelsResponses, ListMonitorsData, ListMonitorsErrors, ListMonitorsResponses, ListNotificationProvidersData, ListNotificationProvidersErrors, ListNotificationProvidersResponses, ListOidcProvidersData, ListOidcProvidersResponses, ListOidcProviderUsersData, ListOidcProviderUsersErrors, ListOidcProviderUsersResponses, ListOidcRoleMappingsData, ListOidcRoleMappingsResponses, ListOnDemandCertsData, ListOnDemandCertsErrors, ListOnDemandCertsResponses, ListOrdersData, ListOrdersErrors, ListOrdersResponses, ListPeersData, ListPeersErrors, ListPeersResponses, ListPendingActionsData, ListPendingActionsErrors, ListPendingActionsResponses, ListPgUpgradesData, ListPgUpgradesErrors, ListPgUpgradesResponses, ListPresetsData, ListPresetsErrors, ListPresetsResponses, ListProjectAccessData, ListProjectAccessErrors, ListProjectAccessResponses, ListProjectAlarmsData, ListProjectAlarmsErrors, ListProjectAlarmsResponses, ListProjectScansData, ListProjectScansErrors, ListProjectScansResponses, ListProjectSecretsData, ListProjectSecretsErrors, ListProjectSecretsResponses, ListProjectServicesData, ListProjectServicesErrors, ListProjectServicesResponses, ListProjectTemplatesData, ListProjectTemplatesErrors, ListProjectTemplatesResponses, ListProjectTemplateTagsData, ListProjectTemplateTagsErrors, ListProjectTemplateTagsResponses, ListProviderKeysData, ListProviderKeysErrors, ListProviderKeysResponses, ListProviderZonesData, ListProviderZonesErrors, ListProviderZonesResponses, ListPublicProvidersData, ListPublicProvidersResponses, ListReleaseFilesData, ListReleaseFilesErrors, ListReleaseFilesResponses, ListReleasesData, ListReleasesErrors, ListReleasesResponses, ListRemoteExternalImagesData, ListRemoteExternalImagesErrors, ListRemoteExternalImagesResponses, ListRepositoriesByConnectionData, ListRepositoriesByConnectionErrors, ListRepositoriesByConnectionResponses, ListRepositoriesByProviderData, ListRepositoriesByProviderErrors, ListRepositoriesByProviderResponses, ListRestoreRunsForServiceData, ListRestoreRunsForServiceResponses, ListRootContainersData, ListRootContainersErrors, ListRootContainersResponses, ListRoutesData, ListRoutesErrors, ListRoutesResponses, ListS3SourcesData, ListS3SourcesErrors, ListS3SourcesResponses, ListSandboxesData, ListSandboxesResponses, ListScheduleRunJobsData, ListScheduleRunJobsErrors, ListScheduleRunJobsResponses, ListScheduleRunsData, ListScheduleRunsErrors, ListScheduleRunsResponses, ListScheduleServicesData, ListScheduleServicesErrors, ListScheduleServicesResponses, ListSecretsData, ListSecretsErrors, ListSecretsResponses, ListServiceHealthStatusesData, ListServiceHealthStatusesErrors, ListServiceHealthStatusesResponses, ListServiceProjectsData, ListServiceProjectsErrors, ListServiceProjectsResponses, ListServiceSchedulesData, ListServiceSchedulesErrors, ListServiceSchedulesResponses, ListServicesData, ListServicesErrors, ListServicesResponses, ListSkillsData, ListSkillsErrors, ListSkillsResponses, ListSourceBackupsData, ListSourceBackupsErrors, ListSourceBackupsResponses, ListSourceFilesData, ListSourceFilesErrors, ListSourceFilesResponses, ListSourceMapsData, ListSourceMapsErrors, ListSourceMapsResponses, ListSourcesData, ListSourcesErrors, ListSourcesResponses, ListStaticBundlesData, ListStaticBundlesErrors, ListStaticBundlesResponses, ListSyncedRepositoriesData, ListSyncedRepositoriesErrors, ListSyncedRepositoriesResponses, ListTeamMembersData, ListTeamMembersErrors, ListTeamMembersResponses, ListTeamProjectsData, ListTeamProjectsErrors, ListTeamProjectsResponses, ListTeamsData, ListTeamsErrors, ListTeamsResponses, ListUsersData, ListUsersErrors, ListUsersResponses, ListWebhooksData, ListWebhooksErrors, ListWebhooksResponses, LoginData, LoginErrors, LoginResponses, LogoutData, LogoutErrors, LogoutResponses, LookupDnsARecordsData, LookupDnsARecordsErrors, LookupDnsARecordsResponses, MintEnrollmentTokenData, MintEnrollmentTokenErrors, MintEnrollmentTokenResponses, MkdirData, MkdirErrors, MkdirResponses, NodeHeartbeatData, NodeHeartbeatErrors, NodeHeartbeatResponses, NodeMetricsGetRangeData, NodeMetricsGetRangeErrors, NodeMetricsGetRangeResponses, ObservabilityFullEventData, ObservabilityFullEventErrors, ObservabilityFullEventResponses, ObservabilityListEventsData, ObservabilityListEventsErrors, ObservabilityListEventsResponses, OidcCallbackData, PatchAdminGateData, PatchAdminGateErrors, PatchAdminGateResponses, PatchPreviewGatewaySettingsData, PatchPreviewGatewaySettingsResponses, PauseDeploymentData, PauseDeploymentErrors, PauseDeploymentResponses, PauseSandboxData, PauseSandboxErrors, PauseSandboxResponses, PlanRestoreData, PlanRestoreErrors, PlanRestoreResponses, PostDnsAckData, PostDnsAckErrors, PostDnsAckResponses, PreviewAlertData, PreviewAlertErrors, PreviewAlertResponses, PreviewFunnelMetricsData, PreviewFunnelMetricsErrors, PreviewFunnelMetricsResponses, PreviewHostnameModeData, PreviewHostnameModeErrors, PreviewHostnameModeResponses, PromoteClusterMemberData, PromoteClusterMemberErrors, PromoteClusterMemberResponses, PromoteDeploymentData, PromoteDeploymentErrors, PromoteDeploymentResponses, ProvisionDomainData, ProvisionDomainErrors, ProvisionDomainResponses, PurgeProjectLogsData, PurgeProjectLogsErrors, PurgeProjectLogsResponses, PushExternalImageData, PushExternalImageErrors, PushExternalImageResponses, QueryDataData, QueryDataErrors, QueryDataResponses, QueryGenaiTracesData, QueryGenaiTracesErrors, QueryGenaiTracesResponses, QueryLogsData, QueryLogsErrors, QueryLogsResponses, QueryMetricsData, QueryMetricsErrors, QueryMetricsResponses, QueryTracesData, QueryTracesErrors, QueryTracesResponses, QueryTraceSummariesData, QueryTraceSummariesErrors, QueryTraceSummariesResponses, ReadFileData, ReadFileErrors, ReadFileResponses, ReAnalyzeData, ReAnalyzeErrors, ReAnalyzeResponses, RecordConsoleEventData, RecordConsoleEventErrors, RecordConsoleEventResponses, RecordEventMetricsData, RecordEventMetricsErrors, RecordEventMetricsResponses, RecordFlagExposureData, RecordFlagExposureErrors, RecordFlagExposureResponses, RecordSpeedMetricsData, RecordSpeedMetricsErrors, RecordSpeedMetricsResponses, RefreshRouteTableData, RefreshRouteTableErrors, RefreshRouteTableResponses, RegenerateDsnData, RegenerateDsnErrors, RegenerateDsnResponses, RegisterExternalImageData, RegisterExternalImageErrors, RegisterExternalImageResponses, RegisterNodeData, RegisterNodeErrors, RegisterNodeResponses, ReinstallGitlabWebhookData, ReinstallGitlabWebhookErrors, ReinstallGitlabWebhookResponses, RejectPendingActionData, RejectPendingActionErrors, RejectPendingActionResponses, ReloadPluginsData, ReloadPluginsErrors, ReloadPluginsResponses, RemoveClusterMemberData, RemoveClusterMemberErrors, RemoveClusterMemberResponses, RemoveManagedDomainData, RemoveManagedDomainErrors, RemoveManagedDomainResponses, RemoveRoleData, RemoveRoleErrors, RemoveRoleResponses, RemoveTeamMemberData, RemoveTeamMemberErrors, RemoveTeamMemberResponses, RenameConversationData, RenameConversationErrors, RenameConversationResponses, RenewDomainData, RenewDomainErrors, RenewDomainResponses, RequestPasswordResetData, RequestPasswordResetErrors, RequestPasswordResetResponses, ResetPasswordData, ResetPasswordErrors, ResetPasswordResponses, ResizeSandboxData, ResizeSandboxErrors, ResizeSandboxResponses, ResolveAlarmData, ResolveAlarmErrors, ResolveAlarmResponses, RestartContainerData, RestartContainerErrors, RestartContainerResponses, RestartPreviewGatewayData, RestartPreviewGatewayResponses, RestartSandboxData, RestartSandboxErrors, RestartSandboxResponses, RestoreFlagData, RestoreFlagErrors, RestoreFlagResponses, RestoreUserData, RestoreUserErrors, RestoreUserResponses, ResumeDeploymentData, ResumeDeploymentErrors, ResumeDeploymentResponses, ResumeSandboxData, ResumeSandboxErrors, ResumeSandboxResponses, RetryClusterData, RetryClusterErrors, RetryClusterResponses, RetryDeliveryData, RetryDeliveryErrors, RetryDeliveryResponses, RetryPgUpgradeData, RetryPgUpgradeErrors, RetryPgUpgradeResponses, RetryRunData, RetryRunErrors, RetryRunResponses, RevealGlobalMcpConfigData, RevealGlobalMcpConfigErrors, RevealGlobalMcpConfigResponses, RevealMcpConfigData, RevealMcpConfigErrors, RevealMcpConfigResponses, RevealNotificationProviderConfigData, RevealNotificationProviderConfigErrors, RevealNotificationProviderConfigResponses, RevealServiceParameterData, RevealServiceParameterErrors, RevealServiceParameterResponses, RevenueCreateIntegrationData, RevenueCreateIntegrationErrors, RevenueCreateIntegrationResponses, RevenueDeleteIntegrationData, RevenueDeleteIntegrationResponses, RevenueGlobalEventsData, RevenueGlobalEventsResponses, RevenueImportInvoicesCsvData, RevenueImportInvoicesCsvErrors, RevenueImportInvoicesCsvResponses, RevenueImportSubscriptionsCsvData, RevenueImportSubscriptionsCsvErrors, RevenueImportSubscriptionsCsvResponses, RevenueListIntegrationsData, RevenueListIntegrationsResponses, RevenueListProvidersData, RevenueListProvidersResponses, RevenueMetricsCustomersData, RevenueMetricsCustomersResponses, RevenueMetricsGlobalMrrData, RevenueMetricsGlobalMrrResponses, RevenueMetricsGlobalSummaryData, RevenueMetricsGlobalSummaryResponses, RevenueMetricsMrrData, RevenueMetricsMrrResponses, RevenueMetricsSummaryData, RevenueMetricsSummaryResponses, RevenueRecentEventsData, RevenueRecentEventsResponses, RevenueRotateTokenData, RevenueRotateTokenResponses, RevenueUpdateConfigData, RevenueUpdateConfigErrors, RevenueUpdateConfigResponses, RevenueUpdateSecretData, RevenueUpdateSecretErrors, RevenueUpdateSecretResponses, RevokeDsnData, RevokeDsnErrors, RevokeDsnResponses, RevokeEnrollmentTokenData, RevokeEnrollmentTokenErrors, RevokeEnrollmentTokenResponses, RevokeJoinTokenData, RevokeJoinTokenErrors, RevokeJoinTokenResponses, RevokeProjectAccessData, RevokeProjectAccessErrors, RevokeProjectAccessResponses, RollbackPgUpgradeData, RollbackPgUpgradeErrors, RollbackPgUpgradeResponses, RollbackToDeploymentData, RollbackToDeploymentErrors, RollbackToDeploymentResponses, RootfsGcData, RootfsGcResponses, RootfsReportData, RootfsReportResponses, RotateApiKeyData, RotateApiKeyErrors, RotateApiKeyResponses, RotateDeploymentTokenData, RotateDeploymentTokenErrors, RotateDeploymentTokenResponses, RunBackupForSourceData, RunBackupForSourceErrors, RunBackupForSourceResponses, RunConnectionHealthCheckData, RunConnectionHealthCheckErrors, RunConnectionHealthCheckResponses, RunExternalServiceBackupData, RunExternalServiceBackupErrors, RunExternalServiceBackupResponses, RunScheduleNowData, RunScheduleNowErrors, RunScheduleNowResponses, SandboxCreatePreviewLinkData, SandboxCreatePreviewLinkErrors, SandboxCreatePreviewLinkResponses, SaveAgentTokenData, SaveAgentTokenErrors, SaveAgentTokenResponses, SaveAiProviderCredentialData, SaveAiProviderCredentialErrors, SaveAiProviderCredentialResponses, SearchLogsData, SearchLogsErrors, SearchLogsResponses, SendEmailData, SendEmailErrors, SendEmailResponses, SetDefaultS3SourceData, SetDefaultS3SourceErrors, SetDefaultS3SourceResponses, SetFlagEnvironmentData, SetFlagEnvironmentErrors, SetFlagEnvironmentResponses, SetPreviewPasswordData, SetPreviewPasswordErrors, SetPreviewPasswordResponses, SetupDnsChallengeData, SetupDnsChallengeErrors, SetupDnsChallengeResponses, SetupDnsData, SetupDnsErrors, SetupDnsResponses, SetupEmailTrackingData, SetupEmailTrackingErrors, SetupEmailTrackingResponses, SetupMfaData, SetupMfaErrors, SetupMfaResponses, SleepEnvironmentData, SleepEnvironmentErrors, SleepEnvironmentResponses, SmokeTestAgentData, SmokeTestAgentErrors, SmokeTestAgentResponses, SourceSandboxData, SourceSandboxErrors, SourceSandboxResponses, StartAnalysisData, StartAnalysisErrors, StartAnalysisResponses, StartContainerData, StartContainerErrors, StartContainerResponses, StartFixData, StartFixErrors, StartFixResponses, StartGitProviderOauthData, StartGitProviderOauthErrors, StartOidcLoginBySlugData, StartOidcLoginBySlugErrors, StartPgUpgradeData, StartPgUpgradeErrors, StartPgUpgradeResponses, StartRestoreData, StartRestoreErrors, StartRestoreResponses, StartServiceData, StartServiceErrors, StartServiceResponses, StatPathData, StatPathErrors, StatPathResponses, StopContainerData, StopContainerErrors, StopContainerResponses, StopSandboxData, StopSandboxErrors, StopSandboxResponses, StopServiceData, StopServiceErrors, StopServiceResponses, StreamContainerMetricsData, StreamContainerMetricsErrors, StreamContainerMetricsResponses, StreamEventsData, StreamEventsErrors, StreamEventsResponses, StreamRunEventsData, StreamRunEventsErrors, StreamRunEventsResponses, SyncRepositoriesData, SyncRepositoriesErrors, SyncRepositoriesResponses, TailDeploymentJobLogsData, TailDeploymentJobLogsErrors, TailLogsData, TailLogsErrors, TailLogsResponses, TeardownDeploymentData, TeardownDeploymentErrors, TeardownDeploymentResponses, TeardownEnvironmentData, TeardownEnvironmentErrors, TeardownEnvironmentResponses, TestNotificationProviderData, TestNotificationProviderErrors, TestNotificationProviderResponses, TestOidcProviderData, TestOidcProviderResponses, TestProviderConnectionData, TestProviderConnectionErrors, TestProviderConnectionResponses, TestProviderData, TestProviderErrors, TestProviderKeyByIdData, TestProviderKeyByIdErrors, TestProviderKeyByIdResponses, TestProviderKeyInlineData, TestProviderKeyInlineErrors, TestProviderKeyInlineResponses, TestProviderResponses, TestS3ConnectionPreviewData, TestS3ConnectionPreviewErrors, TestS3ConnectionPreviewResponses, TestS3SourceConnectionData, TestS3SourceConnectionErrors, TestS3SourceConnectionResponses, TrackClickData, TrackClickErrors, TrackOpenData, TrackOpenErrors, TrackOpenResponses, TriggerAgentData, TriggerAgentErrors, TriggerAgentResponses, TriggerProjectPipelineData, TriggerProjectPipelineErrors, TriggerProjectPipelineResponses, TriggerScanData, TriggerScanErrors, TriggerScanResponses, TriggerServiceHealthCheckData, TriggerServiceHealthCheckErrors, TriggerServiceHealthCheckResponses, TriggerWeeklyDigestData, TriggerWeeklyDigestErrors, TriggerWeeklyDigestResponses, UnlinkServiceFromProjectData, UnlinkServiceFromProjectErrors, UnlinkServiceFromProjectResponses, UpdateAgentData, UpdateAgentErrors, UpdateAgentResponses, UpdateAiProviderData, UpdateAiProviderErrors, UpdateAiProviderResponses, UpdateAlertData, UpdateAlertErrors, UpdateAlertResponses, UpdateAlertRuleData, UpdateAlertRuleErrors, UpdateAlertRuleResponses, UpdateApiKeyData, UpdateApiKeyErrors, UpdateApiKeyResponses, UpdateAutomaticDeployData, UpdateAutomaticDeployErrors, UpdateAutomaticDeployResponses, UpdateBackupScheduleData, UpdateBackupScheduleErrors, UpdateBackupScheduleResponses, UpdateCloudflareProviderData, UpdateCloudflareProviderErrors, UpdateCloudflareProviderResponses, UpdateConnectionTokenData, UpdateConnectionTokenErrors, UpdateConnectionTokenResponses, UpdateCustomDomainData, UpdateCustomDomainErrors, UpdateCustomDomainResponses, UpdateDashboardData, UpdateDashboardErrors, UpdateDashboardResponses, UpdateDeploymentTokenData, UpdateDeploymentTokenErrors, UpdateDeploymentTokenResponses, UpdateEmailProviderData, UpdateEmailProviderErrors, UpdateEmailProviderResponses, UpdateEnvironmentSettingsData, UpdateEnvironmentSettingsErrors, UpdateEnvironmentSettingsResponses, UpdateEnvironmentSubdomainData, UpdateEnvironmentSubdomainErrors, UpdateEnvironmentSubdomainResponses, UpdateEnvironmentVariableData, UpdateEnvironmentVariableErrors, UpdateEnvironmentVariableResponses, UpdateErrorGroupData, UpdateErrorGroupErrors, UpdateErrorGroupResponses, UpdateFlagData, UpdateFlagErrors, UpdateFlagResponses, UpdateFunnelData, UpdateFunnelErrors, UpdateFunnelResponses, UpdateGitProviderCredentialsData, UpdateGitProviderCredentialsErrors, UpdateGitProviderCredentialsResponses, UpdateGitSettingsData, UpdateGitSettingsErrors, UpdateGitSettingsResponses, UpdateGlobalMcpData, UpdateGlobalMcpErrors, UpdateGlobalMcpResponses, UpdateGlobalSkillData, UpdateGlobalSkillErrors, UpdateGlobalSkillResponses, UpdateIncidentStatusData, UpdateIncidentStatusErrors, UpdateIncidentStatusResponses, UpdateIpAccessControlData, UpdateIpAccessControlErrors, UpdateIpAccessControlResponses, UpdateManagedDomainData, UpdateManagedDomainErrors, UpdateManagedDomainResponses, UpdateMcpData, UpdateMcpErrors, UpdateMcpResponses, UpdateNotificationEmailProviderData, UpdateNotificationEmailProviderErrors, UpdateNotificationEmailProviderResponses, UpdateNotificationProviderData, UpdateNotificationProviderErrors, UpdateNotificationProviderResponses, UpdateOidcProviderData, UpdateOidcProviderResponses, UpdatePreferencesData, UpdatePreferencesErrors, UpdatePreferencesResponses, UpdateProjectData, UpdateProjectDeploymentConfigData, UpdateProjectDeploymentConfigErrors, UpdateProjectDeploymentConfigResponses, UpdateProjectErrors, UpdateProjectResponses, UpdateProjectSecretData, UpdateProjectSecretErrors, UpdateProjectSecretResponses, UpdateProjectSettingsData, UpdateProjectSettingsErrors, UpdateProjectSettingsResponses, UpdateProviderData, UpdateProviderErrors, UpdateProviderKeyData, UpdateProviderKeyErrors, UpdateProviderKeyResponses, UpdateProviderResponses, UpdateRouteData, UpdateRouteErrors, UpdateRouteResponses, UpdateS3SourceData, UpdateS3SourceErrors, UpdateS3SourceResponses, UpdateSelfData, UpdateSelfErrors, UpdateSelfResponses, UpdateServiceData, UpdateServiceErrors, UpdateServiceResourcesData, UpdateServiceResourcesErrors, UpdateServiceResourcesResponses, UpdateServiceResponses, UpdateSessionDurationData, UpdateSessionDurationErrors, UpdateSessionDurationResponses, UpdateSettingsData, UpdateSettingsErrors, UpdateSettingsResponses, UpdateSkillData, UpdateSkillErrors, UpdateSkillResponses, UpdateSlackProviderData, UpdateSlackProviderErrors, UpdateSlackProviderResponses, UpdateSpeedMetricsData, UpdateSpeedMetricsErrors, UpdateSpeedMetricsResponses, UpdateTeamData, UpdateTeamErrors, UpdateTeamMemberRoleData, UpdateTeamMemberRoleErrors, UpdateTeamMemberRoleResponses, UpdateTeamResponses, UpdateUserData, UpdateUserErrors, UpdateUserResponses, UpdateWebhookData, UpdateWebhookErrors, UpdateWebhookProviderData, UpdateWebhookProviderErrors, UpdateWebhookProviderResponses, UpdateWebhookResponses, UpgradePreviewGatewayData, UpgradePreviewGatewayResponses, UpgradeServiceData, UpgradeServiceErrors, UpgradeServiceResponses, UploadGlobalSkillData, UploadGlobalSkillErrors, UploadGlobalSkillResponses, UploadReleaseFileData, UploadReleaseFileErrors, UploadReleaseFileResponses, UploadSkillData, UploadSkillErrors, UploadSkillResponses, UploadSourceFileData, UploadSourceFileErrors, UploadSourceFileResponses, UploadSourceMapData, UploadSourceMapErrors, UploadSourceMapResponses, UploadStaticBundleData, UploadStaticBundleErrors, UploadStaticBundleResponses, UpsertSecretData, UpsertSecretErrors, UpsertSecretResponses, ValidateConnectionData, ValidateConnectionErrors, ValidateConnectionResponses, ValidateEmailData, ValidateEmailErrors, ValidateEmailResponses, VerifyAndEnableMfaData, VerifyAndEnableMfaErrors, VerifyAndEnableMfaResponses, VerifyDomainData, VerifyDomainErrors, VerifyDomainResponses, VerifyEmailData, VerifyEmailErrors, VerifyEmailResponses, VerifyManagedDomainData, VerifyManagedDomainErrors, VerifyManagedDomainResponses, VerifyMfaChallengeData, VerifyMfaChallengeErrors, VerifyMfaChallengeResponses, VerifyStepUpData, VerifyStepUpErrors, VerifyStepUpResponses, WakeEnvironmentData, WakeEnvironmentErrors, WakeEnvironmentResponses, WebhookTriggerData, WebhookTriggerErrors, WebhookTriggerResponses, WorkflowDryRunData, WorkflowDryRunErrors, WorkflowDryRunResponses, WriteFileData, WriteFileErrors, WriteFileResponses, WriteFilesData, WriteFilesErrors, WriteFilesResponses } from './types.gen'; +import type { AcknowledgeAlarmData, AcknowledgeAlarmErrors, AcknowledgeAlarmResponses, ActivateAiProviderData, ActivateAiProviderErrors, ActivateAiProviderResponses, ActivateApiKeyData, ActivateApiKeyErrors, ActivateApiKeyResponses, ActivateConnectionData, ActivateConnectionErrors, ActivateConnectionResponses, ActivateProviderData, ActivateProviderErrors, ActivateProviderResponses, AddClusterMemberData, AddClusterMemberErrors, AddClusterMemberResponses, AddContextData, AddContextErrors, AddContextResponses, AddEnvironmentDomainData, AddEnvironmentDomainErrors, AddEnvironmentDomainResponses, AddEventsData, AddEventsErrors, AddEventsResponses, AddManagedDomainData, AddManagedDomainErrors, AddManagedDomainResponses, AddSessionReplayEventsData, AddSessionReplayEventsErrors, AddSessionReplayEventsResponses, AddTeamMemberData, AddTeamMemberErrors, AddTeamMemberResponses, AdminDrainNodeData, AdminDrainNodeErrors, AdminDrainNodeResponses, AdminDrainStatusData, AdminDrainStatusErrors, AdminDrainStatusResponses, AdminGetNodeData, AdminGetNodeErrors, AdminGetNodeResponses, AdminListNodeContainersData, AdminListNodeContainersErrors, AdminListNodeContainersResponses, AdminListNodesData, AdminListNodesErrors, AdminListNodesResponses, AdminRemoveNodeData, AdminRemoveNodeErrors, AdminRemoveNodeResponses, AdminUndrainNodeData, AdminUndrainNodeErrors, AdminUndrainNodeResponses, ApplyHostnameModeData, ApplyHostnameModeErrors, ApplyHostnameModeResponses, ArchiveConversationData, ArchiveConversationErrors, ArchiveConversationResponses, ArchiveFlagData, ArchiveFlagErrors, ArchiveFlagResponses, AssignRoleData, AssignRoleErrors, AssignRoleResponses, AttachScheduleServicesData, AttachScheduleServicesErrors, AttachScheduleServicesResponses, BlobCopyData, BlobCopyErrors, BlobCopyResponses, BlobDeleteData, BlobDeleteErrors, BlobDeleteResponses, BlobDisableData, BlobDisableErrors, BlobDisableResponses, BlobDownloadData, BlobDownloadErrors, BlobDownloadResponses, BlobEnableData, BlobEnableErrors, BlobEnableResponses, BlobHeadData, BlobHeadErrors, BlobHeadResponses, BlobListData, BlobListErrors, BlobListResponses, BlobPutData, BlobPutErrors, BlobPutResponses, BlobStatusData, BlobStatusErrors, BlobStatusResponses, BlobUpdateData, BlobUpdateErrors, BlobUpdateResponses, CancelBackupData, CancelBackupErrors, CancelBackupResponses, CancelData, CancelDeploymentData, CancelDeploymentErrors, CancelDeploymentResponses, CancelDomainOrderData, CancelDomainOrderErrors, CancelDomainOrderResponses, CancelErrors, CancelPgUpgradeData, CancelPgUpgradeErrors, CancelPgUpgradeResponses, CancelResponses, CancelRunData, CancelRunErrors, CancelRunResponses, CancelScheduleRunData, CancelScheduleRunErrors, CancelScheduleRunResponses, ChangePasswordSelfData, ChangePasswordSelfErrors, ChangePasswordSelfResponses, ChangeProjectSourceData, ChangeProjectSourceErrors, ChangeProjectSourceResponses, ChangeRequiredPasswordData, ChangeRequiredPasswordErrors, ChangeRequiredPasswordResponses, ChatCompletionsData, ChatCompletionsErrors, ChatCompletionsResponses, CheckAnalyticsHasEventsData, CheckAnalyticsHasEventsErrors, CheckAnalyticsHasEventsResponses, CheckCommitExistsData, CheckCommitExistsErrors, CheckCommitExistsResponses, CheckDomainStatusData, CheckDomainStatusErrors, CheckDomainStatusResponses, CheckExplorerSupportData, CheckExplorerSupportErrors, CheckExplorerSupportResponses, CheckIpBlockedData, CheckIpBlockedErrors, CheckIpBlockedResponses, CheckProviderDeletionSafetyData, CheckProviderDeletionSafetyErrors, CheckProviderDeletionSafetyResponses, ChunkUploadOptionsData, ChunkUploadOptionsResponses, CleanupExpiredBackupsData, CleanupExpiredBackupsErrors, CleanupExpiredBackupsResponses, ClearPreviewPasswordData, ClearPreviewPasswordErrors, ClearPreviewPasswordResponses, CliDeviceApproveData, CliDeviceApproveErrors, CliDeviceApproveResponses, CliDeviceDenyData, CliDeviceDenyErrors, CliDeviceDenyResponses, CliDeviceLookupData, CliDeviceLookupErrors, CliDeviceLookupResponses, CliDevicePollData, CliDevicePollErrors, CliDevicePollResponses, CliDeviceStartData, CliDeviceStartErrors, CliDeviceStartResponses, CliLogoutData, CliLogoutErrors, CliLogoutResponses, CmdData, CmdErrors, CmdKillData, CmdKillErrors, CmdKillResponses, CmdLogsData, CmdLogsErrors, CmdLogsResponses, CmdResponses, ConfirmPendingActionData, ConfirmPendingActionErrors, ConfirmPendingActionResponses, ContainerMetricsGetHistoryData, ContainerMetricsGetHistoryErrors, ContainerMetricsGetHistoryResponses, CreateAgentData, CreateAgentErrors, CreateAgentResponses, CreateAlertData, CreateAlertErrors, CreateAlertResponses, CreateAlertRuleData, CreateAlertRuleErrors, CreateAlertRuleResponses, CreateApiKeyData, CreateApiKeyErrors, CreateApiKeyResponses, CreateBackupScheduleData, CreateBackupScheduleErrors, CreateBackupScheduleResponses, CreateBitbucketProviderData, CreateBitbucketProviderErrors, CreateBitbucketProviderResponses, CreateCloudflareProviderData, CreateCloudflareProviderErrors, CreateCloudflareProviderResponses, CreateConversationData, CreateConversationErrors, CreateConversationResponses, CreateCustomDomainData, CreateCustomDomainErrors, CreateCustomDomainResponses, CreateDashboardData, CreateDashboardErrors, CreateDashboardResponses, CreateDeploymentTokenData, CreateDeploymentTokenErrors, CreateDeploymentTokenResponses, CreateDnsProviderData, CreateDnsProviderErrors, CreateDnsProviderResponses, CreateDomainData, CreateDomainErrors, CreateDomainResponses, CreateDsnData, CreateDsnErrors, CreateDsnResponses, CreateEmailDomainData, CreateEmailDomainErrors, CreateEmailDomainResponses, CreateEmailProviderData, CreateEmailProviderErrors, CreateEmailProviderResponses, CreateEnvironmentData, CreateEnvironmentErrors, CreateEnvironmentResponses, CreateEnvironmentVariableData, CreateEnvironmentVariableErrors, CreateEnvironmentVariableResponses, CreateFlagData, CreateFlagErrors, CreateFlagResponses, CreateFunnelData, CreateFunnelErrors, CreateFunnelResponses, CreateGenericProviderData, CreateGenericProviderErrors, CreateGenericProviderResponses, CreateGiteaPatProviderData, CreateGiteaPatProviderErrors, CreateGiteaPatProviderResponses, CreateGithubPatProviderData, CreateGithubPatProviderErrors, CreateGithubPatProviderResponses, CreateGitlabOauthProviderData, CreateGitlabOauthProviderErrors, CreateGitlabOauthProviderResponses, CreateGitlabPatProviderData, CreateGitlabPatProviderErrors, CreateGitlabPatProviderResponses, CreateGitProviderData, CreateGitProviderErrors, CreateGitProviderResponses, CreateGlobalMcpData, CreateGlobalMcpErrors, CreateGlobalMcpResponses, CreateGlobalSkillData, CreateGlobalSkillErrors, CreateGlobalSkillResponses, CreateIncidentData, CreateIncidentErrors, CreateIncidentResponses, CreateIpAccessControlData, CreateIpAccessControlErrors, CreateIpAccessControlResponses, CreateMcpData, CreateMcpErrors, CreateMcpResponses, CreateMonitorData, CreateMonitorErrors, CreateMonitorResponses, CreateNotificationEmailProviderData, CreateNotificationEmailProviderErrors, CreateNotificationEmailProviderResponses, CreateNotificationProviderData, CreateNotificationProviderErrors, CreateNotificationProviderResponses, CreateOidcProviderData, CreateOidcProviderErrors, CreateOidcProviderResponses, CreateOidcRoleMappingData, CreateOidcRoleMappingResponses, CreateOrRecreateOrderData, CreateOrRecreateOrderErrors, CreateOrRecreateOrderResponses, CreatePlanData, CreatePlanErrors, CreatePlanResponses, CreatePrData, CreatePrErrors, CreateProjectData, CreateProjectErrors, CreateProjectFromTemplateData, CreateProjectFromTemplateErrors, CreateProjectFromTemplateResponses, CreateProjectReleaseData, CreateProjectReleaseErrors, CreateProjectReleaseResponses, CreateProjectResponses, CreateProjectSecretData, CreateProjectSecretErrors, CreateProjectSecretResponses, CreateProviderKeyData, CreateProviderKeyErrors, CreateProviderKeyResponses, CreatePrResponses, CreateReleaseData, CreateReleaseErrors, CreateReleaseResponses, CreateRouteData, CreateRouteErrors, CreateRouteResponses, CreateS3SourceData, CreateS3SourceErrors, CreateS3SourceResponses, CreateSandboxData, CreateSandboxErrors, CreateSandboxResponses, CreateServiceData, CreateServiceErrors, CreateServiceResponses, CreateSkillData, CreateSkillErrors, CreateSkillResponses, CreateSlackProviderData, CreateSlackProviderErrors, CreateSlackProviderResponses, CreateTeamData, CreateTeamErrors, CreateTeamResponses, CreateUserData, CreateUserErrors, CreateUserResponses, CreateWebhookData, CreateWebhookErrors, CreateWebhookProviderData, CreateWebhookProviderErrors, CreateWebhookProviderResponses, CreateWebhookResponses, DeactivateApiKeyData, DeactivateApiKeyErrors, DeactivateApiKeyResponses, DeactivateConnectionData, DeactivateConnectionErrors, DeactivateConnectionResponses, DeactivateProviderData, DeactivateProviderErrors, DeactivateProviderResponses, DeleteAgentData, DeleteAgentErrors, DeleteAgentResponses, DeleteAlertData, DeleteAlertErrors, DeleteAlertResponses, DeleteAlertRuleData, DeleteAlertRuleErrors, DeleteAlertRuleResponses, DeleteApiKeyData, DeleteApiKeyErrors, DeleteApiKeyResponses, DeleteBackupData, DeleteBackupErrors, DeleteBackupResponses, DeleteBackupScheduleData, DeleteBackupScheduleErrors, DeleteBackupScheduleResponses, DeleteConnectionData, DeleteConnectionErrors, DeleteConnectionResponses, DeleteCustomDomainData, DeleteCustomDomainErrors, DeleteCustomDomainResponses, DeleteDashboardData, DeleteDashboardErrors, DeleteDashboardResponses, DeleteDeploymentTokenData, DeleteDeploymentTokenErrors, DeleteDeploymentTokenResponses, DeleteDnsProviderData, DeleteDnsProviderErrors, DeleteDnsProviderResponses, DeleteDomainData, DeleteDomainErrors, DeleteDomainResponses, DeleteEmailDomainData, DeleteEmailDomainErrors, DeleteEmailDomainResponses, DeleteEmailProviderData, DeleteEmailProviderErrors, DeleteEmailProviderResponses, DeleteEnvironmentData, DeleteEnvironmentDomainData, DeleteEnvironmentDomainErrors, DeleteEnvironmentDomainResponses, DeleteEnvironmentErrors, DeleteEnvironmentResponses, DeleteEnvironmentVariableData, DeleteEnvironmentVariableErrors, DeleteEnvironmentVariableResponses, DeleteExternalImageData, DeleteExternalImageErrors, DeleteExternalImageResponses, DeleteFunnelData, DeleteFunnelErrors, DeleteFunnelResponses, DeleteGitProviderData, DeleteGitProviderErrors, DeleteGitProviderResponses, DeleteGlobalMcpData, DeleteGlobalMcpErrors, DeleteGlobalMcpResponses, DeleteGlobalSkillData, DeleteGlobalSkillErrors, DeleteGlobalSkillResponses, DeleteIpAccessControlData, DeleteIpAccessControlErrors, DeleteIpAccessControlResponses, DeleteMcpData, DeleteMcpErrors, DeleteMcpResponses, DeleteMonitorData, DeleteMonitorErrors, DeleteMonitorResponses, DeleteNotificationProviderData, DeleteNotificationProviderErrors, DeleteNotificationProviderResponses, DeleteOidcProviderData, DeleteOidcProviderResponses, DeleteOidcRoleMappingData, DeleteOidcRoleMappingResponses, DeletePreferencesData, DeletePreferencesErrors, DeletePreferencesResponses, DeleteProjectData, DeleteProjectErrors, DeleteProjectResponses, DeleteProjectSecretData, DeleteProjectSecretErrors, DeleteProjectSecretResponses, DeleteProviderKeyData, DeleteProviderKeyErrors, DeleteProviderKeyResponses, DeleteProviderSafelyData, DeleteProviderSafelyErrors, DeleteProviderSafelyResponses, DeleteReleaseSourceFilesData, DeleteReleaseSourceFilesErrors, DeleteReleaseSourceFilesResponses, DeleteReleaseSourceMapsData, DeleteReleaseSourceMapsErrors, DeleteReleaseSourceMapsResponses, DeleteRouteData, DeleteRouteErrors, DeleteRouteResponses, DeleteS3SourceData, DeleteS3SourceErrors, DeleteS3SourceResponses, DeleteScanData, DeleteScanErrors, DeleteScanResponses, DeleteSecretData, DeleteSecretErrors, DeleteSecretResponses, DeleteServiceData, DeleteServiceErrors, DeleteServiceResponses, DeleteSessionReplayData, DeleteSessionReplayErrors, DeleteSessionReplayResponses, DeleteSkillData, DeleteSkillErrors, DeleteSkillResponses, DeleteSourceMapData, DeleteSourceMapErrors, DeleteSourceMapResponses, DeleteStaticBundleData, DeleteStaticBundleErrors, DeleteStaticBundleResponses, DeleteTeamData, DeleteTeamErrors, DeleteTeamResponses, DeleteUserData, DeleteUserErrors, DeleteUserResponses, DeleteWebhookData, DeleteWebhookErrors, DeleteWebhookResponses, DeployFromImageData, DeployFromImageErrors, DeployFromImageResponses, DeployFromImageUploadData, DeployFromImageUploadErrors, DeployFromImageUploadResponses, DeployFromStaticData, DeployFromStaticErrors, DeployFromStaticResponses, DeployFromUploadedSourceData, DeployFromUploadedSourceErrors, DeployFromUploadedSourceResponses, DeploymentMetricsGetLatestData, DeploymentMetricsGetLatestErrors, DeploymentMetricsGetLatestResponses, DeploymentMetricsGetRangeData, DeploymentMetricsGetRangeErrors, DeploymentMetricsGetRangeResponses, DeploymentMetricsToggleData, DeploymentMetricsToggleErrors, DeploymentMetricsToggleResponses, DestroySandboxData, DestroySandboxErrors, DestroySandboxResponses, DetachScheduleServiceData, DetachScheduleServiceErrors, DetachScheduleServiceResponses, DetectPublicPresetsData, DetectPublicPresetsErrors, DetectPublicPresetsResponses, DisableBackupScheduleData, DisableBackupScheduleErrors, DisableBackupScheduleResponses, DisableMfaData, DisableMfaErrors, DisableMfaResponses, DisconnectCloudData, DisconnectCloudResponses, DiscoverWorkloadsData, DiscoverWorkloadsErrors, DiscoverWorkloadsResponses, DomainData, DomainErrors, DomainResponses, DownloadGlobalSkillArchiveData, DownloadGlobalSkillArchiveErrors, DownloadGlobalSkillArchiveResponses, DownloadObjectData, DownloadObjectErrors, DownloadObjectResponses, DownloadSkillArchiveData, DownloadSkillArchiveErrors, DownloadSkillArchiveResponses, EmailStatusData, EmailStatusErrors, EmailStatusResponses, EmbeddingsData, EmbeddingsErrors, EmbeddingsResponses, EnableBackupScheduleData, EnableBackupScheduleErrors, EnableBackupScheduleResponses, EnrichVisitorData, EnrichVisitorErrors, EnrichVisitorResponses, EnrollCloudData, EnrollCloudResponses, ExecData, ExecDetachedData, ExecDetachedErrors, ExecDetachedResponses, ExecErrors, ExecResponses, ExecuteDeploymentOperationData, ExecuteDeploymentOperationErrors, ExecuteDeploymentOperationResponses, ExecuteImportData, ExecuteImportErrors, ExecuteImportResponses, ExtendTimeoutData, ExtendTimeoutErrors, ExtendTimeoutResponses, ExternalServiceEnablePgStatStatementsData, ExternalServiceEnablePgStatStatementsErrors, ExternalServiceEnablePgStatStatementsResponses, ExternalServiceMetricsByDatabaseData, ExternalServiceMetricsByDatabaseErrors, ExternalServiceMetricsByDatabaseResponses, ExternalServiceMetricsCreateAlertRuleData, ExternalServiceMetricsCreateAlertRuleErrors, ExternalServiceMetricsCreateAlertRuleResponses, ExternalServiceMetricsDeleteAlertRuleData, ExternalServiceMetricsDeleteAlertRuleErrors, ExternalServiceMetricsDeleteAlertRuleResponses, ExternalServiceMetricsGetAlertRulesData, ExternalServiceMetricsGetAlertRulesErrors, ExternalServiceMetricsGetAlertRulesResponses, ExternalServiceMetricsGetLatestData, ExternalServiceMetricsGetLatestErrors, ExternalServiceMetricsGetLatestResponses, ExternalServiceMetricsGetRangeData, ExternalServiceMetricsGetRangeErrors, ExternalServiceMetricsGetRangeResponses, ExternalServiceMetricsStatusData, ExternalServiceMetricsStatusErrors, ExternalServiceMetricsStatusResponses, ExternalServiceMetricsToggleData, ExternalServiceMetricsToggleErrors, ExternalServiceMetricsToggleResponses, ExternalServiceMetricsUpdateAlertRuleData, ExternalServiceMetricsUpdateAlertRuleErrors, ExternalServiceMetricsUpdateAlertRuleResponses, ExternalServiceResetPgStatStatementsData, ExternalServiceResetPgStatStatementsErrors, ExternalServiceResetPgStatStatementsResponses, FinalizeOrderData, FinalizeOrderErrors, FinalizeOrderResponses, FinalizeProjectReleaseData, FinalizeProjectReleaseErrors, FinalizeProjectReleaseResponses, FindConversationData, FindConversationErrors, FindConversationResponses, GenerateJoinTokenData, GenerateJoinTokenErrors, GenerateJoinTokenResponses, GeneratePresetDockerfileData, GeneratePresetDockerfileErrors, GeneratePresetDockerfileResponses, GetAccessInfoData, GetAccessInfoErrors, GetAccessInfoResponses, GetActiveVisitorsData, GetActiveVisitorsErrors, GetActiveVisitorsResponses, GetActivityGraphData, GetActivityGraphErrors, GetActivityGraphResponses, GetAdminGateData, GetAdminGateErrors, GetAdminGateResponses, GetAgentData, GetAgentErrors, GetAgentResponses, GetAggregatedBucketsData, GetAggregatedBucketsErrors, GetAggregatedBucketsResponses, GetAiAgentBreakdownData, GetAiAgentBreakdownErrors, GetAiAgentBreakdownResponses, GetAiAgentPagesData, GetAiAgentPagesErrors, GetAiAgentPagesResponses, GetAiAgentTimelineData, GetAiAgentTimelineErrors, GetAiAgentTimelineResponses, GetAiPageBreakdownData, GetAiPageBreakdownErrors, GetAiPageBreakdownResponses, GetAiStatusBreakdownData, GetAiStatusBreakdownErrors, GetAiStatusBreakdownResponses, GetAlertData, GetAlertErrors, GetAlertResponses, GetAlertRuleData, GetAlertRuleErrors, GetAlertRuleResponses, GetAllRepositoriesByNameData, GetAllRepositoriesByNameErrors, GetAllRepositoriesByNameResponses, GetAnalyticsActiveVisitorsData, GetAnalyticsActiveVisitorsErrors, GetAnalyticsActiveVisitorsResponses, GetAnalyticsEventsCountData, GetAnalyticsEventsCountErrors, GetAnalyticsEventsCountResponses, GetAnalyticsSessionEventsData, GetAnalyticsSessionEventsErrors, GetAnalyticsSessionEventsResponses, GetAnalyticsVisitorSessionsData, GetAnalyticsVisitorSessionsErrors, GetAnalyticsVisitorSessionsResponses, GetApiKeyData, GetApiKeyErrors, GetApiKeyPermissionsData, GetApiKeyPermissionsErrors, GetApiKeyPermissionsResponses, GetApiKeyResponses, GetAuditLogData, GetAuditLogErrors, GetAuditLogResponses, GetBackupData, GetBackupErrors, GetBackupResponses, GetBackupScheduleData, GetBackupScheduleErrors, GetBackupScheduleResponses, GetBranchesByRepositoryIdData, GetBranchesByRepositoryIdErrors, GetBranchesByRepositoryIdResponses, GetBucketedIncidentsData, GetBucketedIncidentsErrors, GetBucketedIncidentsResponses, GetBucketedStatusData, GetBucketedStatusErrors, GetBucketedStatusResponses, GetChallengeTokenData, GetChallengeTokenErrors, GetChallengeTokenResponses, GetChatReadinessData, GetChatReadinessErrors, GetChatReadinessResponses, GetCliStatusData, GetCliStatusErrors, GetCliStatusResponses, GetCloudCapabilityData, GetCloudCapabilityResponses, GetCloudStatusData, GetCloudStatusResponses, GetClusterHealthData, GetClusterHealthErrors, GetClusterHealthResponses, GetClusterMemberData, GetClusterMemberErrors, GetClusterMemberResponses, GetCmdData, GetCmdErrors, GetCmdResponses, GetContainerDetailData, GetContainerDetailErrors, GetContainerDetailResponses, GetContainerEnvironmentVariableData, GetContainerEnvironmentVariableErrors, GetContainerEnvironmentVariableResponses, GetContainerInfoData, GetContainerInfoErrors, GetContainerInfoResponses, GetContainerLogsByIdData, GetContainerLogsByIdErrors, GetContainerLogsData, GetContainerLogsErrors, GetContainerMetricsData, GetContainerMetricsErrors, GetContainerMetricsResponses, GetConversationData, GetConversationDetailData, GetConversationDetailErrors, GetConversationDetailResponses, GetConversationErrors, GetConversationResponses, GetConversationsData, GetConversationsErrors, GetConversationsResponses, GetCronByIdData, GetCronByIdErrors, GetCronByIdResponses, GetCronExecutionsData, GetCronExecutionsErrors, GetCronExecutionsResponses, GetCrossProjectTraceSiblingsData, GetCrossProjectTraceSiblingsErrors, GetCrossProjectTraceSiblingsResponses, GetCurrentMonitorStatusData, GetCurrentMonitorStatusErrors, GetCurrentMonitorStatusResponses, GetCurrentUserData, GetCurrentUserErrors, GetCurrentUserResponses, GetCustomDomainData, GetCustomDomainErrors, GetCustomDomainResponses, GetDashboardData, GetDashboardErrors, GetDashboardProjectsAnalyticsData, GetDashboardProjectsAnalyticsErrors, GetDashboardProjectsAnalyticsResponses, GetDashboardResponses, GetDeliveryData, GetDeliveryErrors, GetDeliveryResponses, GetDeploymentContainerLogContentData, GetDeploymentContainerLogContentErrors, GetDeploymentContainerLogContentResponses, GetDeploymentData, GetDeploymentErrors, GetDeploymentJobLogsData, GetDeploymentJobLogsErrors, GetDeploymentJobLogsResponses, GetDeploymentJobsData, GetDeploymentJobsErrors, GetDeploymentJobsResponses, GetDeploymentOperationsData, GetDeploymentOperationsErrors, GetDeploymentOperationsResponses, GetDeploymentOperationStatusData, GetDeploymentOperationStatusErrors, GetDeploymentOperationStatusResponses, GetDeploymentResponses, GetDeploymentTokenData, GetDeploymentTokenErrors, GetDeploymentTokenResponses, GetDiskStatusData, GetDiskStatusErrors, GetDiskStatusResponses, GetDnsChangesData, GetDnsChangesErrors, GetDnsChangesResponses, GetDnsProviderData, GetDnsProviderErrors, GetDnsProviderResponses, GetDomainByHostData, GetDomainByHostErrors, GetDomainByHostResponses, GetDomainByIdData, GetDomainByIdErrors, GetDomainByIdResponses, GetDomainByNameData, GetDomainByNameErrors, GetDomainByNameResponses, GetDomainData, GetDomainDnsRecordsData, GetDomainDnsRecordsErrors, GetDomainDnsRecordsResponses, GetDomainErrors, GetDomainOrderData, GetDomainOrderErrors, GetDomainOrderResponses, GetDomainResponses, GetEmailData, GetEmailErrors, GetEmailEventsData, GetEmailEventsErrors, GetEmailEventsResponses, GetEmailLinksData, GetEmailLinksErrors, GetEmailLinksResponses, GetEmailProviderData, GetEmailProviderErrors, GetEmailProviderResponses, GetEmailResponses, GetEmailStatsData, GetEmailStatsErrors, GetEmailStatsResponses, GetEmailTrackingData, GetEmailTrackingErrors, GetEmailTrackingResponses, GetEmailTrackingStatusData, GetEmailTrackingStatusErrors, GetEmailTrackingStatusResponses, GetEntityInfoData, GetEntityInfoErrors, GetEntityInfoResponses, GetEnvironmentCronsData, GetEnvironmentCronsErrors, GetEnvironmentCronsResponses, GetEnvironmentData, GetEnvironmentDomainsData, GetEnvironmentDomainsErrors, GetEnvironmentDomainsResponses, GetEnvironmentErrors, GetEnvironmentResponses, GetEnvironmentsData, GetEnvironmentsErrors, GetEnvironmentsResponses, GetEnvironmentVariablesData, GetEnvironmentVariablesErrors, GetEnvironmentVariablesResponses, GetEnvironmentVariableValueData, GetEnvironmentVariableValueErrors, GetEnvironmentVariableValueResponses, GetErrorDashboardStatsData, GetErrorDashboardStatsErrors, GetErrorDashboardStatsResponses, GetErrorEventData, GetErrorEventErrors, GetErrorEventResponses, GetErrorGroupData, GetErrorGroupErrors, GetErrorGroupResponses, GetErrorStatsData, GetErrorStatsErrors, GetErrorStatsResponses, GetErrorTimeSeriesData, GetErrorTimeSeriesErrors, GetErrorTimeSeriesResponses, GetEventDetailData, GetEventDetailErrors, GetEventDetailResponses, GetEventEntriesData, GetEventEntriesErrors, GetEventEntriesResponses, GetEventsCountData, GetEventsCountErrors, GetEventsCountResponses, GetEventsTimelineData, GetEventsTimelineErrors, GetEventsTimelineResponses, GetEventTypeBreakdownData, GetEventTypeBreakdownErrors, GetEventTypeBreakdownResponses, GetEventVisitorsData, GetEventVisitorsErrors, GetEventVisitorsResponses, GetExternalImageData, GetExternalImageErrors, GetExternalImageResponses, GetFileData, GetFileErrors, GetFileResponses, GetFlagData, GetFlagErrors, GetFlagResponses, GetFlagSnapshotData, GetFlagSnapshotErrors, GetFlagSnapshotResponses, GetFunnelMetricsData, GetFunnelMetricsErrors, GetFunnelMetricsResponses, GetGenaiTraceData, GetGenaiTraceErrors, GetGenaiTraceResponses, GetGeneralStatsData, GetGeneralStatsErrors, GetGeneralStatsResponses, GetGitProviderData, GetGitProviderErrors, GetGitProviderResponses, GetGlobalEventsData, GetGlobalEventsErrors, GetGlobalEventsResponses, GetGlobalEventStatsData, GetGlobalEventStatsErrors, GetGlobalEventStatsResponses, GetGlobalMcpData, GetGlobalMcpErrors, GetGlobalMcpResponses, GetGlobalSandboxStatusData, GetGlobalSandboxStatusErrors, GetGlobalSandboxStatusResponses, GetGlobalSkillData, GetGlobalSkillErrors, GetGlobalSkillResponses, GetGroupedPageMetricsData, GetGroupedPageMetricsErrors, GetGroupedPageMetricsResponses, GetHealthData, GetHealthErrors, GetHealthResponses, GetHourlyVisitsData, GetHourlyVisitsErrors, GetHourlyVisitsResponses, GetHttpChallengeDebugData, GetHttpChallengeDebugErrors, GetHttpChallengeDebugResponses, GetImportStatusData, GetImportStatusErrors, GetImportStatusResponses, GetIncidentData, GetIncidentErrors, GetIncidentResponses, GetIncidentUpdatesData, GetIncidentUpdatesErrors, GetIncidentUpdatesResponses, GetIpAccessControlData, GetIpAccessControlErrors, GetIpAccessControlResponses, GetIpGeolocationData, GetIpGeolocationErrors, GetIpGeolocationResponses, GetJoinTokenStatusData, GetJoinTokenStatusErrors, GetJoinTokenStatusResponses, GetLastDeploymentData, GetLastDeploymentErrors, GetLastDeploymentResponses, GetLatestScanData, GetLatestScanErrors, GetLatestScanResponses, GetLatestScansPerEnvironmentData, GetLatestScansPerEnvironmentErrors, GetLatestScansPerEnvironmentResponses, GetLiveVisitorsListData, GetLiveVisitorsListErrors, GetLiveVisitorsListResponses, GetLogContextData, GetLogContextErrors, GetLogContextResponses, GetMcpData, GetMcpErrors, GetMcpResponses, GetMetricsOverTimeData, GetMetricsOverTimeErrors, GetMetricsOverTimeResponses, GetMonitorData, GetMonitorErrors, GetMonitorResponses, GetNotificationProviderData, GetNotificationProviderErrors, GetNotificationProviderResponses, GetOnDemandCertStatusData, GetOnDemandCertStatusErrors, GetOnDemandCertStatusResponses, GetOrCreateDsnData, GetOrCreateDsnErrors, GetOrCreateDsnResponses, GetPageFlowData, GetPageFlowErrors, GetPageFlowResponses, GetPageHourlySessionsData, GetPageHourlySessionsErrors, GetPageHourlySessionsResponses, GetPagePathDetailData, GetPagePathDetailErrors, GetPagePathDetailResponses, GetPagePathsData, GetPagePathsErrors, GetPagePathsResponses, GetPagePathsSparklinesData, GetPagePathsSparklinesErrors, GetPagePathsSparklinesResponses, GetPagePathVisitorsData, GetPagePathVisitorsErrors, GetPagePathVisitorsResponses, GetPendingActionData, GetPendingActionErrors, GetPendingActionResponses, GetPerformanceMetricsData, GetPerformanceMetricsErrors, GetPerformanceMetricsResponses, GetPgUpgradeData, GetPgUpgradeErrors, GetPgUpgradeLogsData, GetPgUpgradeLogsErrors, GetPgUpgradeLogsResponses, GetPgUpgradeResponses, GetPipelineStatsData, GetPipelineStatsErrors, GetPipelineStatsResponses, GetPlatformInfoData, GetPlatformInfoErrors, GetPlatformInfoResponses, GetPostgresWalHealthData, GetPostgresWalHealthErrors, GetPostgresWalHealthResponses, GetPreferencesData, GetPreferencesErrors, GetPreferencesResponses, GetPreviewGatewayLogsData, GetPreviewGatewayLogsResponses, GetPreviewGatewaySettingsData, GetPreviewGatewaySettingsResponses, GetPreviewGatewayStatusData, GetPreviewGatewayStatusResponses, GetPricingData, GetPricingErrors, GetPricingResponses, GetPrivateIpData, GetPrivateIpErrors, GetPrivateIpResponses, GetProjectAlarmsSummaryData, GetProjectAlarmsSummaryErrors, GetProjectAlarmsSummaryResponses, GetProjectBySlugData, GetProjectBySlugErrors, GetProjectBySlugResponses, GetProjectData, GetProjectDeploymentsData, GetProjectDeploymentsErrors, GetProjectDeploymentsResponses, GetProjectErrors, GetProjectResponses, GetProjectsData, GetProjectsErrors, GetProjectServiceEnvironmentVariablesData, GetProjectServiceEnvironmentVariablesErrors, GetProjectServiceEnvironmentVariablesResponses, GetProjectSessionReplaysData, GetProjectSessionReplaysErrors, GetProjectSessionReplaysResponses, GetProjectsHealthData, GetProjectsHealthErrors, GetProjectsHealthResponses, GetProjectsMonitorHealthData, GetProjectsMonitorHealthErrors, GetProjectsMonitorHealthResponses, GetProjectsResponses, GetProjectStatisticsData, GetProjectStatisticsErrors, GetProjectStatisticsResponses, GetProjectTemplateData, GetProjectTemplateErrors, GetProjectTemplateResponses, GetPropertyBreakdownData, GetPropertyBreakdownErrors, GetPropertyBreakdownResponses, GetPropertyTimelineData, GetPropertyTimelineErrors, GetPropertyTimelineResponses, GetProviderConnectionsData, GetProviderConnectionsErrors, GetProviderConnectionsResponses, GetProviderMetadataData, GetProviderMetadataErrors, GetProviderMetadataResponses, GetProvidersMetadataData, GetProvidersMetadataErrors, GetProvidersMetadataResponses, GetProxyLogByIdData, GetProxyLogByIdErrors, GetProxyLogByIdResponses, GetProxyLogByRequestIdData, GetProxyLogByRequestIdErrors, GetProxyLogByRequestIdResponses, GetProxyLogsData, GetProxyLogsErrors, GetProxyLogsResponses, GetPublicBranchesData, GetPublicBranchesErrors, GetPublicBranchesResponses, GetPublicIpData, GetPublicIpErrors, GetPublicIpResponses, GetPublicRepositoryData, GetPublicRepositoryErrors, GetPublicRepositoryResponses, GetQuotaData, GetQuotaErrors, GetQuotaResponses, GetRecentActivityData, GetRecentActivityErrors, GetRecentActivityResponses, GetRemoteExternalImageData, GetRemoteExternalImageErrors, GetRemoteExternalImageResponses, GetRepositoryBranchesData, GetRepositoryBranchesErrors, GetRepositoryBranchesResponses, GetRepositoryByIdData, GetRepositoryByIdErrors, GetRepositoryByIdResponses, GetRepositoryByNameData, GetRepositoryByNameErrors, GetRepositoryByNameResponses, GetRepositoryPresetByNameData, GetRepositoryPresetByNameErrors, GetRepositoryPresetByNameResponses, GetRepositoryPresetLiveData, GetRepositoryPresetLiveErrors, GetRepositoryPresetLiveResponses, GetRepositoryTagsData, GetRepositoryTagsErrors, GetRepositoryTagsResponses, GetResolvedEnvironmentVariablesData, GetResolvedEnvironmentVariablesErrors, GetResolvedEnvironmentVariablesResponses, GetResolvedEnvironmentVariableValueData, GetResolvedEnvironmentVariableValueErrors, GetResolvedEnvironmentVariableValueResponses, GetRestoreCapabilitiesData, GetRestoreCapabilitiesErrors, GetRestoreCapabilitiesResponses, GetRestoreRunData, GetRestoreRunErrors, GetRestoreRunResponses, GetRouteData, GetRouteErrors, GetRouteResponses, GetRunData, GetRunErrors, GetRunResponses, GetRunWithLogsData, GetRunWithLogsErrors, GetRunWithLogsResponses, GetS3CredentialsData, GetS3CredentialsErrors, GetS3CredentialsResponses, GetS3SourceData, GetS3SourceErrors, GetS3SourceResponses, GetSandboxData, GetSandboxErrors, GetSandboxResponses, GetSandboxStatusData, GetSandboxStatusErrors, GetSandboxStatusResponses, GetScanByDeploymentData, GetScanByDeploymentErrors, GetScanByDeploymentResponses, GetScanData, GetScanErrors, GetScanResponses, GetScanVulnerabilitiesData, GetScanVulnerabilitiesErrors, GetScanVulnerabilitiesResponses, GetServiceBySlugData, GetServiceBySlugErrors, GetServiceBySlugResponses, GetServiceData, GetServiceEnvironmentVariableData, GetServiceEnvironmentVariableErrors, GetServiceEnvironmentVariableResponses, GetServiceEnvironmentVariablesData, GetServiceEnvironmentVariablesErrors, GetServiceEnvironmentVariablesResponses, GetServiceErrors, GetServiceHealthStatusData, GetServiceHealthStatusErrors, GetServiceHealthStatusResponses, GetServicePreviewEnvironmentVariableNamesData, GetServicePreviewEnvironmentVariableNamesErrors, GetServicePreviewEnvironmentVariableNamesResponses, GetServicePreviewEnvironmentVariablesMaskedData, GetServicePreviewEnvironmentVariablesMaskedErrors, GetServicePreviewEnvironmentVariablesMaskedResponses, GetServiceResponses, GetServiceRuntimeData, GetServiceRuntimeErrors, GetServiceRuntimeResponses, GetServiceStatsData, GetServiceStatsErrors, GetServiceStatsResponses, GetServiceTypeParametersData, GetServiceTypeParametersErrors, GetServiceTypeParametersResponses, GetServiceTypesData, GetServiceTypesErrors, GetServiceTypesResponses, GetSessionDetailsData, GetSessionDetailsErrors, GetSessionDetailsResponses, GetSessionEventsData, GetSessionEventsErrors, GetSessionEventsResponses, GetSessionLogsData, GetSessionLogsErrors, GetSessionLogsResponses, GetSessionReplayData, GetSessionReplayErrors, GetSessionReplayEventsData, GetSessionReplayEventsErrors, GetSessionReplayEventsResponses, GetSessionReplayResponses, GetSettingsData, GetSettingsErrors, GetSettingsResponses, GetSkillData, GetSkillErrors, GetSkillResponses, GetSlowQueriesData, GetSlowQueriesErrors, GetSlowQueriesResponses, GetStaticBundleData, GetStaticBundleErrors, GetStaticBundleResponses, GetStatusOverviewData, GetStatusOverviewErrors, GetStatusOverviewResponses, GetTagsByRepositoryIdData, GetTagsByRepositoryIdErrors, GetTagsByRepositoryIdResponses, GetTeamData, GetTeamErrors, GetTeamResponses, GetTimeBucketStatsData, GetTimeBucketStatsErrors, GetTimeBucketStatsResponses, GetTodayStatsData, GetTodayStatsErrors, GetTodayStatsResponses, GetTraceData, GetTraceErrors, GetTraceResponses, GetUnifiedTraceData, GetUnifiedTraceErrors, GetUnifiedTraceResponses, GetUniqueCountsData, GetUniqueCountsErrors, GetUniqueCountsResponses, GetUniqueEventsData, GetUniqueEventsErrors, GetUniqueEventsResponses, GetUpdateStatusData, GetUpdateStatusErrors, GetUpdateStatusResponses, GetUptimeHistoryData, GetUptimeHistoryErrors, GetUptimeHistoryResponses, GetUsageByProviderData, GetUsageByProviderErrors, GetUsageByProviderResponses, GetUsageRecentData, GetUsageRecentErrors, GetUsageRecentResponses, GetUsageSummaryData, GetUsageSummaryErrors, GetUsageSummaryResponses, GetUsageTimeseriesData, GetUsageTimeseriesErrors, GetUsageTimeseriesResponses, GetUsageTopModelsData, GetUsageTopModelsErrors, GetUsageTopModelsResponses, GetVisitorByGuidData, GetVisitorByGuidErrors, GetVisitorByGuidResponses, GetVisitorByIdData, GetVisitorByIdErrors, GetVisitorByIdResponses, GetVisitorDetailsData, GetVisitorDetailsErrors, GetVisitorDetailsResponses, GetVisitorFacetsData, GetVisitorFacetsErrors, GetVisitorFacetsResponses, GetVisitorInfoData, GetVisitorInfoErrors, GetVisitorInfoResponses, GetVisitorJourneyData, GetVisitorJourneyErrors, GetVisitorJourneyResponses, GetVisitorsData, GetVisitorsErrors, GetVisitorSessionsData, GetVisitorSessionsErrors, GetVisitorSessionsResponses, GetVisitorsResponses, GetVisitorStatsData, GetVisitorStatsErrors, GetVisitorStatsResponses, GetWebhookData, GetWebhookErrors, GetWebhookResponses, GrantProjectAccessData, GrantProjectAccessErrors, GrantProjectAccessResponses, HandleGitProviderOauthCallbackData, HandleGitProviderOauthCallbackErrors, HasAnalyticsEventsData, HasAnalyticsEventsErrors, HasAnalyticsEventsResponses, HasErrorGroupsData, HasErrorGroupsErrors, HasErrorGroupsResponses, HasPerformanceMetricsData, HasPerformanceMetricsErrors, HasPerformanceMetricsResponses, ImportExternalServiceData, ImportExternalServiceErrors, ImportExternalServiceResponses, IngestLogsByPathData, IngestLogsByPathErrors, IngestLogsByPathResponses, IngestLogsData, IngestLogsErrors, IngestLogsResponses, IngestMetricsByPathData, IngestMetricsByPathErrors, IngestMetricsByPathResponses, IngestMetricsData, IngestMetricsErrors, IngestMetricsResponses, IngestSentryEnvelopeData, IngestSentryEnvelopeErrors, IngestSentryEnvelopeResponses, IngestSentryEventData, IngestSentryEventErrors, IngestSentryEventResponses, IngestTracesByPathData, IngestTracesByPathErrors, IngestTracesByPathResponses, IngestTracesData, IngestTracesErrors, IngestTracesResponses, InitSessionReplayData, InitSessionReplayErrors, InitSessionReplayResponses, InspectDropArchiveData, InspectDropArchiveErrors, InspectDropArchiveResponses, JobLogsData, JobLogsErrors, JobLogsResponses, JobStatusData, JobStatusErrors, JobStatusResponses, KillJobData, KillJobErrors, KillJobResponses, KvDelData, KvDelErrors, KvDelResponses, KvDisableData, KvDisableErrors, KvDisableResponses, KvEnableData, KvEnableErrors, KvEnableResponses, KvExpireData, KvExpireErrors, KvExpireResponses, KvGetData, KvGetErrors, KvGetResponses, KvIncrData, KvIncrErrors, KvIncrResponses, KvKeysData, KvKeysErrors, KvKeysResponses, KvSetData, KvSetErrors, KvSetResponses, KvStatusData, KvStatusErrors, KvStatusResponses, KvTtlData, KvTtlErrors, KvTtlResponses, KvUpdateData, KvUpdateErrors, KvUpdateResponses, LatestRunForSourceData, LatestRunForSourceErrors, LatestRunForSourceResponses, LinkCustomDomainToCertificateData, LinkCustomDomainToCertificateErrors, LinkCustomDomainToCertificateResponses, LinkServiceToProjectData, LinkServiceToProjectErrors, LinkServiceToProjectResponses, ListAgentRunsData, ListAgentRunsErrors, ListAgentRunsResponses, ListAgentsData, ListAgentsErrors, ListAgentsResponses, ListAiProvidersData, ListAiProvidersErrors, ListAiProvidersResponses, ListAlertRulesData, ListAlertRulesErrors, ListAlertRulesResponses, ListAlertsData, ListAlertsErrors, ListAlertsResponses, ListAllConversationsData, ListAllConversationsErrors, ListAllConversationsResponses, ListAllRunsData, ListAllRunsErrors, ListAllRunsResponses, ListApiKeysData, ListApiKeysErrors, ListApiKeysResponses, ListAuditLogsData, ListAuditLogsErrors, ListAuditLogsResponses, ListAvailableContainersData, ListAvailableContainersErrors, ListAvailableContainersResponses, ListBackupAlertsData, ListBackupAlertsErrors, ListBackupAlertsResponses, ListBackupChildrenData, ListBackupChildrenErrors, ListBackupChildrenResponses, ListBackupSchedulesData, ListBackupSchedulesErrors, ListBackupSchedulesResponses, ListBackupsForScheduleData, ListBackupsForScheduleErrors, ListBackupsForScheduleResponses, ListCommitsByRepositoryIdData, ListCommitsByRepositoryIdErrors, ListCommitsByRepositoryIdResponses, ListConnectionsData, ListConnectionsErrors, ListConnectionsResponses, ListContainersAtPathData, ListContainersAtPathErrors, ListContainersAtPathResponses, ListContainersData, ListContainersErrors, ListContainersResponses, ListConversationsData, ListConversationsErrors, ListConversationsResponses, ListCustomDomainsForProjectData, ListCustomDomainsForProjectErrors, ListCustomDomainsForProjectResponses, ListDashboardsData, ListDashboardsErrors, ListDashboardsResponses, ListDeliveriesData, ListDeliveriesErrors, ListDeliveriesResponses, ListDeploymentContainerLogsData, ListDeploymentContainerLogsErrors, ListDeploymentContainerLogsResponses, ListDeploymentTokensData, ListDeploymentTokensErrors, ListDeploymentTokensResponses, ListDnsProvidersData, ListDnsProvidersErrors, ListDnsProvidersResponses, ListDomainsData, ListDomainsErrors, ListDomainsResponses, ListDsnsData, ListDsnsErrors, ListDsnsResponses, ListEmailDomainsData, ListEmailDomainsErrors, ListEmailDomainsResponses, ListEmailProvidersData, ListEmailProvidersErrors, ListEmailProvidersResponses, ListEmailsData, ListEmailsErrors, ListEmailsResponses, ListEnrollmentTokensData, ListEnrollmentTokensErrors, ListEnrollmentTokensResponses, ListEntitiesData, ListEntitiesErrors, ListEntitiesResponses, ListErrorEventsData, ListErrorEventsErrors, ListErrorEventsResponses, ListErrorGroupsData, ListErrorGroupsErrors, ListErrorGroupsResponses, ListEventsData, ListEventsResponses, ListEventTypesData, ListEventTypesResponses, ListExternalImagesData, ListExternalImagesErrors, ListExternalImagesResponses, ListExternalPluginsData, ListExternalPluginsErrors, ListExternalPluginsResponses, ListExternalServiceBackupsData, ListExternalServiceBackupsErrors, ListExternalServiceBackupsResponses, ListFlagsData, ListFlagsErrors, ListFlagsResponses, ListFunnelsData, ListFunnelsErrors, ListFunnelsResponses, ListGitProvidersData, ListGitProvidersErrors, ListGitProvidersResponses, ListGlobalMcpsData, ListGlobalMcpsErrors, ListGlobalMcpsResponses, ListGlobalSkillsData, ListGlobalSkillsErrors, ListGlobalSkillsResponses, ListIncidentsData, ListIncidentsErrors, ListIncidentsResponses, ListInsightsData, ListInsightsErrors, ListInsightsResponses, ListIpAccessControlData, ListIpAccessControlErrors, ListIpAccessControlResponses, ListJobsData, ListJobsErrors, ListJobsResponses, ListKnownAiAgentsData, ListKnownAiAgentsErrors, ListKnownAiAgentsResponses, ListManagedDomainsData, ListManagedDomainsErrors, ListManagedDomainsResponses, ListMcpsData, ListMcpsErrors, ListMcpsResponses, ListMetricLabelKeysData, ListMetricLabelKeysErrors, ListMetricLabelKeysResponses, ListMetricLabelValuesData, ListMetricLabelValuesErrors, ListMetricLabelValuesResponses, ListMetricNamesData, ListMetricNamesErrors, ListMetricNamesResponses, ListModelsData, ListModelsErrors, ListModelsResponses, ListMonitorsData, ListMonitorsErrors, ListMonitorsResponses, ListNotificationProvidersData, ListNotificationProvidersErrors, ListNotificationProvidersResponses, ListOidcProvidersData, ListOidcProvidersResponses, ListOidcProviderUsersData, ListOidcProviderUsersErrors, ListOidcProviderUsersResponses, ListOidcRoleMappingsData, ListOidcRoleMappingsResponses, ListOnDemandCertsData, ListOnDemandCertsErrors, ListOnDemandCertsResponses, ListOrdersData, ListOrdersErrors, ListOrdersResponses, ListPeersData, ListPeersErrors, ListPeersResponses, ListPendingActionsData, ListPendingActionsErrors, ListPendingActionsResponses, ListPgUpgradesData, ListPgUpgradesErrors, ListPgUpgradesResponses, ListPresetsData, ListPresetsErrors, ListPresetsResponses, ListProjectAccessData, ListProjectAccessErrors, ListProjectAccessResponses, ListProjectAlarmsData, ListProjectAlarmsErrors, ListProjectAlarmsResponses, ListProjectScansData, ListProjectScansErrors, ListProjectScansResponses, ListProjectSecretsData, ListProjectSecretsErrors, ListProjectSecretsResponses, ListProjectServicesData, ListProjectServicesErrors, ListProjectServicesResponses, ListProjectTemplatesData, ListProjectTemplatesErrors, ListProjectTemplatesResponses, ListProjectTemplateTagsData, ListProjectTemplateTagsErrors, ListProjectTemplateTagsResponses, ListProviderKeysData, ListProviderKeysErrors, ListProviderKeysResponses, ListProviderZonesData, ListProviderZonesErrors, ListProviderZonesResponses, ListPublicProvidersData, ListPublicProvidersResponses, ListReleaseFilesData, ListReleaseFilesErrors, ListReleaseFilesResponses, ListReleasesData, ListReleasesErrors, ListReleasesResponses, ListRemoteExternalImagesData, ListRemoteExternalImagesErrors, ListRemoteExternalImagesResponses, ListRepositoriesByConnectionData, ListRepositoriesByConnectionErrors, ListRepositoriesByConnectionResponses, ListRepositoriesByProviderData, ListRepositoriesByProviderErrors, ListRepositoriesByProviderResponses, ListRestoreRunsForServiceData, ListRestoreRunsForServiceResponses, ListRootContainersData, ListRootContainersErrors, ListRootContainersResponses, ListRoutesData, ListRoutesErrors, ListRoutesResponses, ListS3SourcesData, ListS3SourcesErrors, ListS3SourcesResponses, ListSandboxesData, ListSandboxesResponses, ListScheduleRunJobsData, ListScheduleRunJobsErrors, ListScheduleRunJobsResponses, ListScheduleRunsData, ListScheduleRunsErrors, ListScheduleRunsResponses, ListScheduleServicesData, ListScheduleServicesErrors, ListScheduleServicesResponses, ListSecretsData, ListSecretsErrors, ListSecretsResponses, ListServiceHealthStatusesData, ListServiceHealthStatusesErrors, ListServiceHealthStatusesResponses, ListServiceProjectsData, ListServiceProjectsErrors, ListServiceProjectsResponses, ListServiceSchedulesData, ListServiceSchedulesErrors, ListServiceSchedulesResponses, ListServicesData, ListServicesErrors, ListServicesResponses, ListSkillsData, ListSkillsErrors, ListSkillsResponses, ListSourceBackupsData, ListSourceBackupsErrors, ListSourceBackupsResponses, ListSourceFilesData, ListSourceFilesErrors, ListSourceFilesResponses, ListSourceMapsData, ListSourceMapsErrors, ListSourceMapsResponses, ListSourcesData, ListSourcesErrors, ListSourcesResponses, ListStaticBundlesData, ListStaticBundlesErrors, ListStaticBundlesResponses, ListSyncedRepositoriesData, ListSyncedRepositoriesErrors, ListSyncedRepositoriesResponses, ListTeamMembersData, ListTeamMembersErrors, ListTeamMembersResponses, ListTeamProjectsData, ListTeamProjectsErrors, ListTeamProjectsResponses, ListTeamsData, ListTeamsErrors, ListTeamsResponses, ListUsersData, ListUsersErrors, ListUsersResponses, ListWebhooksData, ListWebhooksErrors, ListWebhooksResponses, LoginData, LoginErrors, LoginResponses, LogoutData, LogoutErrors, LogoutResponses, LookupDnsARecordsData, LookupDnsARecordsErrors, LookupDnsARecordsResponses, MintEnrollmentTokenData, MintEnrollmentTokenErrors, MintEnrollmentTokenResponses, MkdirData, MkdirErrors, MkdirResponses, NodeHeartbeatData, NodeHeartbeatErrors, NodeHeartbeatResponses, NodeMetricsGetRangeData, NodeMetricsGetRangeErrors, NodeMetricsGetRangeResponses, ObservabilityFullEventData, ObservabilityFullEventErrors, ObservabilityFullEventResponses, ObservabilityListEventsData, ObservabilityListEventsErrors, ObservabilityListEventsResponses, OidcCallbackData, PatchAdminGateData, PatchAdminGateErrors, PatchAdminGateResponses, PatchPreviewGatewaySettingsData, PatchPreviewGatewaySettingsResponses, PauseDeploymentData, PauseDeploymentErrors, PauseDeploymentResponses, PauseSandboxData, PauseSandboxErrors, PauseSandboxResponses, PlanRestoreData, PlanRestoreErrors, PlanRestoreResponses, PostDnsAckData, PostDnsAckErrors, PostDnsAckResponses, PreviewAlertData, PreviewAlertErrors, PreviewAlertResponses, PreviewFunnelMetricsData, PreviewFunnelMetricsErrors, PreviewFunnelMetricsResponses, PreviewHostnameModeData, PreviewHostnameModeErrors, PreviewHostnameModeResponses, PromoteClusterMemberData, PromoteClusterMemberErrors, PromoteClusterMemberResponses, PromoteDeploymentData, PromoteDeploymentErrors, PromoteDeploymentResponses, ProvisionDomainData, ProvisionDomainErrors, ProvisionDomainResponses, PurgeProjectLogsData, PurgeProjectLogsErrors, PurgeProjectLogsResponses, PushExternalImageData, PushExternalImageErrors, PushExternalImageResponses, QueryDataData, QueryDataErrors, QueryDataResponses, QueryGenaiTracesData, QueryGenaiTracesErrors, QueryGenaiTracesResponses, QueryLogsData, QueryLogsErrors, QueryLogsResponses, QueryMetricsData, QueryMetricsErrors, QueryMetricsResponses, QueryTracesData, QueryTracesErrors, QueryTracesResponses, QueryTraceSummariesData, QueryTraceSummariesErrors, QueryTraceSummariesResponses, ReadFileData, ReadFileErrors, ReadFileResponses, ReAnalyzeData, ReAnalyzeErrors, ReAnalyzeResponses, RecordConsoleEventData, RecordConsoleEventErrors, RecordConsoleEventResponses, RecordEventMetricsData, RecordEventMetricsErrors, RecordEventMetricsResponses, RecordFlagExposureData, RecordFlagExposureErrors, RecordFlagExposureResponses, RecordSpeedMetricsData, RecordSpeedMetricsErrors, RecordSpeedMetricsResponses, RefreshRouteTableData, RefreshRouteTableErrors, RefreshRouteTableResponses, RegenerateDsnData, RegenerateDsnErrors, RegenerateDsnResponses, RegisterExternalImageData, RegisterExternalImageErrors, RegisterExternalImageResponses, RegisterNodeData, RegisterNodeErrors, RegisterNodeResponses, ReinstallGitlabWebhookData, ReinstallGitlabWebhookErrors, ReinstallGitlabWebhookResponses, RejectPendingActionData, RejectPendingActionErrors, RejectPendingActionResponses, ReloadPluginsData, ReloadPluginsErrors, ReloadPluginsResponses, RemoveClusterMemberData, RemoveClusterMemberErrors, RemoveClusterMemberResponses, RemoveManagedDomainData, RemoveManagedDomainErrors, RemoveManagedDomainResponses, RemoveRoleData, RemoveRoleErrors, RemoveRoleResponses, RemoveTeamMemberData, RemoveTeamMemberErrors, RemoveTeamMemberResponses, RenameConversationData, RenameConversationErrors, RenameConversationResponses, RenewDomainData, RenewDomainErrors, RenewDomainResponses, RequestPasswordResetData, RequestPasswordResetErrors, RequestPasswordResetResponses, ResetPasswordData, ResetPasswordErrors, ResetPasswordResponses, ResizeSandboxData, ResizeSandboxErrors, ResizeSandboxResponses, ResolveAlarmData, ResolveAlarmErrors, ResolveAlarmResponses, RestartContainerData, RestartContainerErrors, RestartContainerResponses, RestartPreviewGatewayData, RestartPreviewGatewayResponses, RestartSandboxData, RestartSandboxErrors, RestartSandboxResponses, RestoreFlagData, RestoreFlagErrors, RestoreFlagResponses, RestoreUserData, RestoreUserErrors, RestoreUserResponses, ResumeDeploymentData, ResumeDeploymentErrors, ResumeDeploymentResponses, ResumeSandboxData, ResumeSandboxErrors, ResumeSandboxResponses, RetryClusterData, RetryClusterErrors, RetryClusterResponses, RetryDeliveryData, RetryDeliveryErrors, RetryDeliveryResponses, RetryPgUpgradeData, RetryPgUpgradeErrors, RetryPgUpgradeResponses, RetryRunData, RetryRunErrors, RetryRunResponses, RevealGlobalMcpConfigData, RevealGlobalMcpConfigErrors, RevealGlobalMcpConfigResponses, RevealMcpConfigData, RevealMcpConfigErrors, RevealMcpConfigResponses, RevealNotificationProviderConfigData, RevealNotificationProviderConfigErrors, RevealNotificationProviderConfigResponses, RevealServiceParameterData, RevealServiceParameterErrors, RevealServiceParameterResponses, RevenueCreateIntegrationData, RevenueCreateIntegrationErrors, RevenueCreateIntegrationResponses, RevenueDeleteIntegrationData, RevenueDeleteIntegrationResponses, RevenueGlobalEventsData, RevenueGlobalEventsResponses, RevenueImportInvoicesCsvData, RevenueImportInvoicesCsvErrors, RevenueImportInvoicesCsvResponses, RevenueImportSubscriptionsCsvData, RevenueImportSubscriptionsCsvErrors, RevenueImportSubscriptionsCsvResponses, RevenueListIntegrationsData, RevenueListIntegrationsResponses, RevenueListProvidersData, RevenueListProvidersResponses, RevenueMetricsCustomersData, RevenueMetricsCustomersResponses, RevenueMetricsGlobalMrrData, RevenueMetricsGlobalMrrResponses, RevenueMetricsGlobalSummaryData, RevenueMetricsGlobalSummaryResponses, RevenueMetricsMrrData, RevenueMetricsMrrResponses, RevenueMetricsSummaryData, RevenueMetricsSummaryResponses, RevenueRecentEventsData, RevenueRecentEventsResponses, RevenueRotateTokenData, RevenueRotateTokenResponses, RevenueUpdateConfigData, RevenueUpdateConfigErrors, RevenueUpdateConfigResponses, RevenueUpdateSecretData, RevenueUpdateSecretErrors, RevenueUpdateSecretResponses, RevokeDsnData, RevokeDsnErrors, RevokeDsnResponses, RevokeEnrollmentTokenData, RevokeEnrollmentTokenErrors, RevokeEnrollmentTokenResponses, RevokeJoinTokenData, RevokeJoinTokenErrors, RevokeJoinTokenResponses, RevokeProjectAccessData, RevokeProjectAccessErrors, RevokeProjectAccessResponses, RollbackPgUpgradeData, RollbackPgUpgradeErrors, RollbackPgUpgradeResponses, RollbackToDeploymentData, RollbackToDeploymentErrors, RollbackToDeploymentResponses, RootfsGcData, RootfsGcResponses, RootfsReportData, RootfsReportResponses, RotateApiKeyData, RotateApiKeyErrors, RotateApiKeyResponses, RotateDeploymentTokenData, RotateDeploymentTokenErrors, RotateDeploymentTokenResponses, RunBackupForSourceData, RunBackupForSourceErrors, RunBackupForSourceResponses, RunConnectionHealthCheckData, RunConnectionHealthCheckErrors, RunConnectionHealthCheckResponses, RunExternalServiceBackupData, RunExternalServiceBackupErrors, RunExternalServiceBackupResponses, RunScheduleNowData, RunScheduleNowErrors, RunScheduleNowResponses, SandboxCreatePreviewLinkData, SandboxCreatePreviewLinkErrors, SandboxCreatePreviewLinkResponses, SaveAgentTokenData, SaveAgentTokenErrors, SaveAgentTokenResponses, SaveAiProviderCredentialData, SaveAiProviderCredentialErrors, SaveAiProviderCredentialResponses, SearchLogsData, SearchLogsErrors, SearchLogsResponses, SendEmailData, SendEmailErrors, SendEmailResponses, SetDefaultS3SourceData, SetDefaultS3SourceErrors, SetDefaultS3SourceResponses, SetFlagEnvironmentData, SetFlagEnvironmentErrors, SetFlagEnvironmentResponses, SetPreviewPasswordData, SetPreviewPasswordErrors, SetPreviewPasswordResponses, SetupDnsChallengeData, SetupDnsChallengeErrors, SetupDnsChallengeResponses, SetupDnsData, SetupDnsErrors, SetupDnsResponses, SetupEmailTrackingData, SetupEmailTrackingErrors, SetupEmailTrackingResponses, SetupMfaData, SetupMfaErrors, SetupMfaResponses, SleepEnvironmentData, SleepEnvironmentErrors, SleepEnvironmentResponses, SmokeTestAgentData, SmokeTestAgentErrors, SmokeTestAgentResponses, SourceSandboxData, SourceSandboxErrors, SourceSandboxResponses, StartAnalysisData, StartAnalysisErrors, StartAnalysisResponses, StartContainerData, StartContainerErrors, StartContainerResponses, StartFixData, StartFixErrors, StartFixResponses, StartGitProviderOauthData, StartGitProviderOauthErrors, StartOidcLoginBySlugData, StartOidcLoginBySlugErrors, StartPgUpgradeData, StartPgUpgradeErrors, StartPgUpgradeResponses, StartRestoreData, StartRestoreErrors, StartRestoreResponses, StartServiceData, StartServiceErrors, StartServiceResponses, StatPathData, StatPathErrors, StatPathResponses, StopContainerData, StopContainerErrors, StopContainerResponses, StopSandboxData, StopSandboxErrors, StopSandboxResponses, StopServiceData, StopServiceErrors, StopServiceResponses, StreamContainerMetricsData, StreamContainerMetricsErrors, StreamContainerMetricsResponses, StreamEventsData, StreamEventsErrors, StreamEventsResponses, StreamRunEventsData, StreamRunEventsErrors, StreamRunEventsResponses, SyncRepositoriesData, SyncRepositoriesErrors, SyncRepositoriesResponses, TailDeploymentJobLogsData, TailDeploymentJobLogsErrors, TailLogsData, TailLogsErrors, TailLogsResponses, TeardownDeploymentData, TeardownDeploymentErrors, TeardownDeploymentResponses, TeardownEnvironmentData, TeardownEnvironmentErrors, TeardownEnvironmentResponses, TestNotificationProviderData, TestNotificationProviderErrors, TestNotificationProviderResponses, TestOidcProviderData, TestOidcProviderResponses, TestProviderConnectionData, TestProviderConnectionErrors, TestProviderConnectionResponses, TestProviderData, TestProviderErrors, TestProviderKeyByIdData, TestProviderKeyByIdErrors, TestProviderKeyByIdResponses, TestProviderKeyInlineData, TestProviderKeyInlineErrors, TestProviderKeyInlineResponses, TestProviderResponses, TestS3ConnectionPreviewData, TestS3ConnectionPreviewErrors, TestS3ConnectionPreviewResponses, TestS3SourceConnectionData, TestS3SourceConnectionErrors, TestS3SourceConnectionResponses, TrackClickData, TrackClickErrors, TrackOpenData, TrackOpenErrors, TrackOpenResponses, TriggerAgentData, TriggerAgentErrors, TriggerAgentResponses, TriggerProjectPipelineData, TriggerProjectPipelineErrors, TriggerProjectPipelineResponses, TriggerScanData, TriggerScanErrors, TriggerScanResponses, TriggerServiceHealthCheckData, TriggerServiceHealthCheckErrors, TriggerServiceHealthCheckResponses, TriggerWeeklyDigestData, TriggerWeeklyDigestErrors, TriggerWeeklyDigestResponses, UnlinkServiceFromProjectData, UnlinkServiceFromProjectErrors, UnlinkServiceFromProjectResponses, UpdateAgentData, UpdateAgentErrors, UpdateAgentResponses, UpdateAiProviderData, UpdateAiProviderErrors, UpdateAiProviderResponses, UpdateAlertData, UpdateAlertErrors, UpdateAlertResponses, UpdateAlertRuleData, UpdateAlertRuleErrors, UpdateAlertRuleResponses, UpdateApiKeyData, UpdateApiKeyErrors, UpdateApiKeyResponses, UpdateAutomaticDeployData, UpdateAutomaticDeployErrors, UpdateAutomaticDeployResponses, UpdateBackupScheduleData, UpdateBackupScheduleErrors, UpdateBackupScheduleResponses, UpdateCloudflareProviderData, UpdateCloudflareProviderErrors, UpdateCloudflareProviderResponses, UpdateConnectionTokenData, UpdateConnectionTokenErrors, UpdateConnectionTokenResponses, UpdateCustomDomainData, UpdateCustomDomainErrors, UpdateCustomDomainResponses, UpdateDashboardData, UpdateDashboardErrors, UpdateDashboardResponses, UpdateDeploymentTokenData, UpdateDeploymentTokenErrors, UpdateDeploymentTokenResponses, UpdateEmailProviderData, UpdateEmailProviderErrors, UpdateEmailProviderResponses, UpdateEnvironmentSettingsData, UpdateEnvironmentSettingsErrors, UpdateEnvironmentSettingsResponses, UpdateEnvironmentSubdomainData, UpdateEnvironmentSubdomainErrors, UpdateEnvironmentSubdomainResponses, UpdateEnvironmentVariableData, UpdateEnvironmentVariableErrors, UpdateEnvironmentVariableResponses, UpdateErrorGroupData, UpdateErrorGroupErrors, UpdateErrorGroupResponses, UpdateFlagData, UpdateFlagErrors, UpdateFlagResponses, UpdateFunnelData, UpdateFunnelErrors, UpdateFunnelResponses, UpdateGitProviderCredentialsData, UpdateGitProviderCredentialsErrors, UpdateGitProviderCredentialsResponses, UpdateGitSettingsData, UpdateGitSettingsErrors, UpdateGitSettingsResponses, UpdateGlobalMcpData, UpdateGlobalMcpErrors, UpdateGlobalMcpResponses, UpdateGlobalSkillData, UpdateGlobalSkillErrors, UpdateGlobalSkillResponses, UpdateIncidentStatusData, UpdateIncidentStatusErrors, UpdateIncidentStatusResponses, UpdateIpAccessControlData, UpdateIpAccessControlErrors, UpdateIpAccessControlResponses, UpdateManagedDomainData, UpdateManagedDomainErrors, UpdateManagedDomainResponses, UpdateMcpData, UpdateMcpErrors, UpdateMcpResponses, UpdateNotificationEmailProviderData, UpdateNotificationEmailProviderErrors, UpdateNotificationEmailProviderResponses, UpdateNotificationProviderData, UpdateNotificationProviderErrors, UpdateNotificationProviderResponses, UpdateOidcProviderData, UpdateOidcProviderResponses, UpdatePreferencesData, UpdatePreferencesErrors, UpdatePreferencesResponses, UpdateProjectData, UpdateProjectDeploymentConfigData, UpdateProjectDeploymentConfigErrors, UpdateProjectDeploymentConfigResponses, UpdateProjectErrors, UpdateProjectResponses, UpdateProjectSecretData, UpdateProjectSecretErrors, UpdateProjectSecretResponses, UpdateProjectSettingsData, UpdateProjectSettingsErrors, UpdateProjectSettingsResponses, UpdateProviderData, UpdateProviderErrors, UpdateProviderKeyData, UpdateProviderKeyErrors, UpdateProviderKeyResponses, UpdateProviderResponses, UpdateRouteData, UpdateRouteErrors, UpdateRouteResponses, UpdateS3SourceData, UpdateS3SourceErrors, UpdateS3SourceResponses, UpdateSelfData, UpdateSelfErrors, UpdateSelfResponses, UpdateServiceData, UpdateServiceErrors, UpdateServiceResourcesData, UpdateServiceResourcesErrors, UpdateServiceResourcesResponses, UpdateServiceResponses, UpdateSessionDurationData, UpdateSessionDurationErrors, UpdateSessionDurationResponses, UpdateSettingsData, UpdateSettingsErrors, UpdateSettingsResponses, UpdateSkillData, UpdateSkillErrors, UpdateSkillResponses, UpdateSlackProviderData, UpdateSlackProviderErrors, UpdateSlackProviderResponses, UpdateSpeedMetricsData, UpdateSpeedMetricsErrors, UpdateSpeedMetricsResponses, UpdateTeamData, UpdateTeamErrors, UpdateTeamMemberRoleData, UpdateTeamMemberRoleErrors, UpdateTeamMemberRoleResponses, UpdateTeamResponses, UpdateUserData, UpdateUserErrors, UpdateUserResponses, UpdateWebhookData, UpdateWebhookErrors, UpdateWebhookProviderData, UpdateWebhookProviderErrors, UpdateWebhookProviderResponses, UpdateWebhookResponses, UpgradePreviewGatewayData, UpgradePreviewGatewayResponses, UpgradeServiceData, UpgradeServiceErrors, UpgradeServiceResponses, UploadGlobalSkillData, UploadGlobalSkillErrors, UploadGlobalSkillResponses, UploadReleaseFileData, UploadReleaseFileErrors, UploadReleaseFileResponses, UploadSkillData, UploadSkillErrors, UploadSkillResponses, UploadSourceFileData, UploadSourceFileErrors, UploadSourceFileResponses, UploadSourceMapData, UploadSourceMapErrors, UploadSourceMapResponses, UploadStaticBundleData, UploadStaticBundleErrors, UploadStaticBundleResponses, UpsertSecretData, UpsertSecretErrors, UpsertSecretResponses, ValidateConnectionData, ValidateConnectionErrors, ValidateConnectionResponses, ValidateEmailData, ValidateEmailErrors, ValidateEmailResponses, VerifyAndEnableMfaData, VerifyAndEnableMfaErrors, VerifyAndEnableMfaResponses, VerifyDomainData, VerifyDomainErrors, VerifyDomainResponses, VerifyEmailData, VerifyEmailErrors, VerifyEmailResponses, VerifyManagedDomainData, VerifyManagedDomainErrors, VerifyManagedDomainResponses, VerifyMfaChallengeData, VerifyMfaChallengeErrors, VerifyMfaChallengeResponses, VerifyStepUpData, VerifyStepUpErrors, VerifyStepUpResponses, WakeEnvironmentData, WakeEnvironmentErrors, WakeEnvironmentResponses, WebhookTriggerData, WebhookTriggerErrors, WebhookTriggerResponses, WorkflowDryRunData, WorkflowDryRunErrors, WorkflowDryRunResponses, WriteFileData, WriteFileErrors, WriteFileResponses, WriteFilesData, WriteFilesErrors, WriteFilesResponses } from './types.gen'; export type Options = Options2 & { /** @@ -750,6 +750,15 @@ export const startOidcLoginBySlug = (optio export const listPublicProviders = (options?: Options): RequestResult => (options?.client ?? client).get({ url: '/auth/oidc/providers', ...options }); +export const changeRequiredPassword = (options: Options): RequestResult => (options.client ?? client).post({ + url: '/auth/password-change-required', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + export const requestPasswordReset = (options: Options): RequestResult => (options.client ?? client).post({ url: '/auth/password-reset/request', ...options, @@ -6500,9 +6509,14 @@ export const getUniqueCounts = (options: O * deployed later using the deploy/static endpoint. */ export const uploadStaticBundle = (options: Options): RequestResult => (options.client ?? client).post({ + ...formDataBodySerializer, security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/upload/static', - ...options + ...options, + headers: { + 'Content-Type': null, + ...options.headers + } }); export const listProjectScans = (options: Options): RequestResult => (options.client ?? client).get({ diff --git a/web/src/api/client/types.gen.ts b/web/src/api/client/types.gen.ts index b95e0359f..580707203 100644 --- a/web/src/api/client/types.gen.ts +++ b/web/src/api/client/types.gen.ts @@ -1339,7 +1339,10 @@ export type AuthFlavorDto = { export type AuthResponse = { message: string; + mfa_enrollment_required: boolean; mfa_required: boolean; + mfa_setup?: null | MfaSetupResponse; + password_change_required: boolean; success: boolean; user_id?: number | null; }; @@ -3958,6 +3961,7 @@ export type CreateTeamRequest = { export type CreateUserRequest = { email?: string | null; + must_change_password?: boolean; password?: string | null; roles: Array; username: string; @@ -13322,6 +13326,18 @@ export type RequestRow = { user_agent?: string | null; }; +export type RequiredPasswordChangeRequest = { + new_password: string; +}; + +export type RequiredPasswordChangeResponse = { + message: string; + mfa_enrollment_required: boolean; + mfa_setup?: null | MfaSetupResponse; + success: boolean; + user_id: number; +}; + export type ResetPasswordRequest = { new_password: string; token: string; @@ -13830,6 +13846,7 @@ export type RouteUser = { id: number; image: string; mfa_enabled: boolean; + must_change_password: boolean; name: string; updated_at: number; username: string; @@ -22389,6 +22406,37 @@ export type ListPublicProvidersResponses = { export type ListPublicProvidersResponse = ListPublicProvidersResponses[keyof ListPublicProvidersResponses]; +export type ChangeRequiredPasswordData = { + body: RequiredPasswordChangeRequest; + path?: never; + query?: never; + url: '/auth/password-change-required'; +}; + +export type ChangeRequiredPasswordErrors = { + /** + * Password does not meet requirements + */ + 400: unknown; + /** + * Password-change session is missing or expired + */ + 401: unknown; + /** + * Internal server error + */ + 500: unknown; +}; + +export type ChangeRequiredPasswordResponses = { + /** + * Required password change completed + */ + 200: RequiredPasswordChangeResponse; +}; + +export type ChangeRequiredPasswordResponse = ChangeRequiredPasswordResponses[keyof ChangeRequiredPasswordResponses]; + export type RequestPasswordResetData = { body: EmailRequest; path?: never; @@ -43931,7 +43979,7 @@ export type GetUniqueCountsResponses = { export type GetUniqueCountsResponse = GetUniqueCountsResponses[keyof GetUniqueCountsResponses]; export type UploadStaticBundleData = { - body?: never; + body: SourceArchiveUpload; path: { project_id: number; }; @@ -47724,6 +47772,10 @@ export type SetupMfaErrors = { * Unauthorized */ 401: unknown; + /** + * MFA is already enabled; verify and disable it before re-enrollment + */ + 409: unknown; /** * Internal server error */ diff --git a/web/src/components/dashboard/FirstProjectOnboarding.tsx b/web/src/components/dashboard/FirstProjectOnboarding.tsx index 95bac78fe..064deffdf 100644 --- a/web/src/components/dashboard/FirstProjectOnboarding.tsx +++ b/web/src/components/dashboard/FirstProjectOnboarding.tsx @@ -1,4 +1,4 @@ -import { Link } from 'react-router' +import { Link, useNavigate } from 'react-router' import { Activity, ArrowRight, @@ -6,6 +6,8 @@ import { BookOpen, Bug, Database, + FileArchive, + FolderOpen, GitBranch, Mail, Network, @@ -14,11 +16,14 @@ import { Terminal, UploadCloud, } from 'lucide-react' +import { useEffect, useRef, useState } from 'react' import { Button } from '@/components/ui/button' import { CopyButton } from '@/components/ui/copy-button' import { ConnectionList } from '@/components/dashboard/ConnectionList' import { InlineGitConnect } from '@/components/dashboard/InlineGitConnect' import { cn } from '@/lib/utils' +import { filesFromDrop, filesFromInput } from '@/lib/drop-files' +import { handOffDropFiles } from '@/lib/drop-handoff' interface FirstProjectOnboardingProps { /** @@ -227,32 +232,129 @@ export function FirstProjectOnboarding({
    -
    -
    -
    - -
    -
    -

    Drop project files

    -

    - Upload a folder or ZIP; Temps detects and builds it -

    -
    -
    -

    - Create and deploy a project directly from your browser without a - repository or local CLI setup. -

    - -
    + ) } +function EmptyStateDropCard() { + const navigate = useNavigate() + const folderInputRef = useRef(null) + const zipInputRef = useRef(null) + const [isDragging, setIsDragging] = useState(false) + const [error, setError] = useState(null) + + useEffect(() => { + folderInputRef.current?.setAttribute('webkitdirectory', '') + }, []) + + const continueToDrop = (files: ReturnType) => { + if (files.length === 0) return + handOffDropFiles(files) + navigate('/drop') + } + + return ( +
    { + event.preventDefault() + setIsDragging(true) + }} + onDragOver={(event) => event.preventDefault()} + onDragLeave={(event) => { + if (!event.currentTarget.contains(event.relatedTarget as Node)) { + setIsDragging(false) + } + }} + onDrop={async (event) => { + event.preventDefault() + setIsDragging(false) + setError(null) + try { + const files = await filesFromDrop(event) + if (files.length === 0) + throw new Error('Choose a project folder or ZIP') + handOffDropFiles(files) + navigate('/drop') + } catch (caught) { + setError( + caught instanceof Error + ? caught.message + : 'Those project files could not be read' + ) + } + }} + > +
    +
    + +
    +
    +

    Drop project files

    +

    + Package locally, then detect on this Temps instance +

    +
    +
    + +
    +

    + {isDragging + ? 'Release to inspect your project' + : 'Drop a folder or ZIP here'} +

    +

    + Common secret files are excluded before the archive is uploaded for + preset detection. +

    +
    + + +
    +
    + + {error &&

    {error}

    } + + + continueToDrop(filesFromInput(event.target.files))} + /> + continueToDrop(filesFromInput(event.target.files))} + /> +
    + ) +} + /** * One capability, as a compact chip. Replaces the previous card-with-blurb: * eight of those cost a full screen to communicate "you get all of this", diff --git a/web/src/components/dashboard/Sidebar.tsx b/web/src/components/dashboard/Sidebar.tsx index e80cd1c33..f70f9ec6c 100644 --- a/web/src/components/dashboard/Sidebar.tsx +++ b/web/src/components/dashboard/Sidebar.tsx @@ -76,16 +76,10 @@ import { } from 'lucide-react' import { ProjectResponse } from '@/api/client' -import { - getProjectBySlugOptions, - hasAnalyticsEventsOptions, - hasErrorGroupsOptions, - listCustomDomainsForProjectOptions, - listMonitorsOptions, - listProjectServicesOptions, -} from '@/api/client/@tanstack/react-query.gen' +import { getProjectBySlugOptions } from '@/api/client/@tanstack/react-query.gen' import { useAuth } from '@/contexts/AuthContext' import { useGettingStarted } from '@/hooks/useGettingStarted' +import { useProjectSetup } from '@/hooks/useProjectSetup' import { useCanViewAuditLogs } from '@/hooks/useAuditAccess' import { usePluginsContext } from '@/contexts/PluginsContext' import { resolvePluginIcon } from '@/lib/pluginIcons' @@ -991,99 +985,25 @@ const projectBaseNav: ProjectNavItem[] = [ }, ] -interface ProjectSetupStep { - id: string - title: string - href: string - done: boolean - icon: LucideIcon -} - function ProjectSetupNavItem({ project }: { project: ProjectResponse }) { const { isMinimal, isMobile } = useSidebar() const compact = isMinimal && !isMobile + const setup = useProjectSetup(project) + const remainingSteps = setup.steps.filter((step) => !step.done) - const analyticsQuery = useQuery({ - ...hasAnalyticsEventsOptions({ path: { project_id: project.id } }), - }) - const errorsQuery = useQuery({ - ...hasErrorGroupsOptions({ path: { project_id: project.id } }), - }) - const domainsQuery = useQuery({ - ...listCustomDomainsForProjectOptions({ - path: { project_id: project.id }, - }), - }) - const monitorsQuery = useQuery({ - ...listMonitorsOptions({ path: { project_id: project.id } }), - }) - const servicesQuery = useQuery({ - ...listProjectServicesOptions({ path: { project_id: project.id } }), - }) - - const isLoading = - analyticsQuery.isLoading || - errorsQuery.isLoading || - domainsQuery.isLoading || - monitorsQuery.isLoading || - servicesQuery.isLoading - - const steps: ProjectSetupStep[] = [ - { - id: 'analytics', - title: 'Install analytics SDK', - href: `/projects/${project.slug}/analytics/setup`, - done: !!analyticsQuery.data?.has_events, - icon: BarChart3, - }, - { - id: 'errors', - title: 'Install error tracking SDK', - href: `/projects/${project.slug}/errors/setup`, - done: !!errorsQuery.data?.has_error_groups, - icon: ShieldAlert, - }, - { - id: 'domain', - title: 'Connect a custom domain', - href: `/projects/${project.slug}/domains`, - done: (domainsQuery.data?.domains?.length ?? 0) > 0, - icon: Globe, - }, - { - id: 'monitoring', - title: 'Add an uptime monitor', - href: `/projects/${project.slug}/monitors`, - done: (monitorsQuery.data?.length ?? 0) > 0, - icon: Activity, - }, - { - id: 'storage', - title: 'Link database or storage', - href: `/projects/${project.slug}/storage`, - done: (servicesQuery.data?.length ?? 0) > 0, - icon: Database, - }, - ] - - const remainingSteps = steps.filter((step) => !step.done) - const completedCount = steps.length - remainingSteps.length - const percent = Math.round((completedCount / steps.length) * 100) - - if (isLoading || remainingSteps.length === 0) return null + if (setup.isLoading || remainingSteps.length === 0) return null if (compact) { - const nextStep = remainingSteps[0] return ( - + @@ -1099,28 +1019,32 @@ function ProjectSetupNavItem({ project }: { project: ProjectResponse }) { return (
    -
    +
    Project setup - {completedCount}/{steps.length} + {setup.completedCount}/{setup.totalCount} +
    -
    +
      {visibleSteps.map((step) => (
    • @@ -1137,8 +1061,13 @@ function ProjectSetupNavItem({ project }: { project: ProjectResponse }) {
    • ))} {hiddenCount > 0 && ( -
    • - +{hiddenCount} more {hiddenCount === 1 ? 'step' : 'steps'} +
    • + + +{hiddenCount} more {hiddenCount === 1 ? 'step' : 'steps'} +
    • )}
    diff --git a/web/src/components/drop/DetectedPresetCard.tsx b/web/src/components/drop/DetectedPresetCard.tsx new file mode 100644 index 000000000..e1304b827 --- /dev/null +++ b/web/src/components/drop/DetectedPresetCard.tsx @@ -0,0 +1,157 @@ +import type { DropPresetCandidate } from '@/api/client' +import { PresetIcon } from '@/components/presets/PresetIcon' +import { cn } from '@/lib/utils' +import { AnimatePresence, motion, useReducedMotion } from 'framer-motion' +import { CheckCircle2, ScanSearch } from 'lucide-react' +import { useEffect, useState } from 'react' + +export function DetectedPresetCard({ + candidate, + isDetecting, + phase = 'detecting', +}: { + candidate?: DropPresetCandidate + isDetecting: boolean + phase?: 'packing' | 'detecting' +}) { + const reduceMotion = useReducedMotion() + const [elapsedSeconds, setElapsedSeconds] = useState(0) + const transition = reduceMotion + ? { duration: 0 } + : { duration: 0.32, ease: [0.22, 1, 0.36, 1] as const } + + useEffect(() => { + if (!isDetecting) return + const startedAt = Date.now() + const timer = window.setInterval(() => { + setElapsedSeconds(Math.floor((Date.now() - startedAt) / 1000)) + }, 1000) + return () => { + window.clearInterval(timer) + setElapsedSeconds(0) + } + }, [isDetecting]) + + const detectionTitle = + phase === 'packing' ? 'Packaging project files' : 'Inspecting project files' + const detectionDescription = + elapsedSeconds >= 5 + ? `Still working — larger projects can take a little longer. ${elapsedSeconds}s elapsed. You can cancel with the X.` + : phase === 'packing' + ? 'Creating a secure archive in your browser…' + : 'Uploading the archive and reading framework manifests…' + + return ( +
    + + {isDetecting ? ( + +
    + + {!reduceMotion && ( + + )} +
    +
    +

    {detectionTitle}

    +

    + {detectionDescription} +

    +
    + {!reduceMotion && ( + + )} + + ) : candidate ? ( + + + + +
    +
    +

    {candidate.label}

    + + {candidate.confidence} confidence + +
    +

    + {candidate.reason} +

    +
    + +
    + ) : ( + +
    + +
    +
    +

    + Preset detection +

    +

    + Select a folder or archive and Temps will identify the framework + automatically. +

    +
    +
    + )} +
    +
    + ) +} diff --git a/web/src/components/drop/DetectedPresetGrid.tsx b/web/src/components/drop/DetectedPresetGrid.tsx new file mode 100644 index 000000000..77dff39ff --- /dev/null +++ b/web/src/components/drop/DetectedPresetGrid.tsx @@ -0,0 +1,88 @@ +import type { DropPresetCandidate } from '@/api/client' +import { PresetIcon } from '@/components/presets/PresetIcon' +import { cn } from '@/lib/utils' +import { Check, Folder } from 'lucide-react' + +export function DetectedPresetGrid({ + candidates, + selectedIndex, + onSelect, + disabled = false, +}: { + candidates: DropPresetCandidate[] + selectedIndex: number + onSelect: (index: number) => void + disabled?: boolean +}) { + return ( +
    + {candidates.map((candidate, index) => { + const selected = index === selectedIndex + const directory = candidate.directory || '.' + + return ( + + ) + })} +
    + ) +} diff --git a/web/src/components/drop/DropEnvironmentVariables.tsx b/web/src/components/drop/DropEnvironmentVariables.tsx new file mode 100644 index 000000000..daa6702c9 --- /dev/null +++ b/web/src/components/drop/DropEnvironmentVariables.tsx @@ -0,0 +1,160 @@ +import { Button } from '@/components/ui/button' +import { Input } from '@/components/ui/input' +import { Label } from '@/components/ui/label' +import type { DropEnvironmentVariable } from '@/lib/drop-environment-variables' +import { Eye, EyeOff, KeyRound, Plus, Trash2 } from 'lucide-react' +import { useState } from 'react' + +let nextVariableId = 0 + +function createVariableId(): string { + nextVariableId += 1 + return `drop-env-${nextVariableId}` +} + +export function DropEnvironmentVariables({ + variables, + onChange, + disabled = false, +}: { + variables: DropEnvironmentVariable[] + onChange: (variables: DropEnvironmentVariable[]) => void + disabled?: boolean +}) { + const [visibleValues, setVisibleValues] = useState>(new Set()) + + const update = (id: string, field: 'key' | 'value', value: string) => { + onChange( + variables.map((variable) => + variable.id === id ? { ...variable, [field]: value } : variable + ) + ) + } + + const add = () => { + onChange([...variables, { id: createVariableId(), key: '', value: '' }]) + } + + const remove = (id: string) => { + onChange(variables.filter((variable) => variable.id !== id)) + setVisibleValues((current) => { + const next = new Set(current) + next.delete(id) + return next + }) + } + + const toggleVisible = (id: string) => { + setVisibleValues((current) => { + const next = new Set(current) + if (next.has(id)) next.delete(id) + else next.add(id) + return next + }) + } + + return ( +
    +
    +
    + +
    +

    Environment variables

    +

    + Optional values available to the first deployment. +

    +
    +
    + +
    + + {variables.length > 0 && ( +
    + {variables.map((variable, index) => { + const valueVisible = visibleValues.has(variable.id) + return ( +
    +
    + + + update(variable.id, 'key', event.target.value) + } + /> +
    +
    + +
    + + update(variable.id, 'value', event.target.value) + } + /> + +
    +
    + +
    + ) + })} +
    + )} +
    + ) +} diff --git a/web/src/components/git/ConnectionsCompactList.tsx b/web/src/components/git/ConnectionsCompactList.tsx index aa97ef446..11ac77c65 100644 --- a/web/src/components/git/ConnectionsCompactList.tsx +++ b/web/src/components/git/ConnectionsCompactList.tsx @@ -4,7 +4,6 @@ import { deleteConnectionMutation, runConnectionHealthCheckMutation, } from '@/api/client/@tanstack/react-query.gen' -import { isGitHubApp } from '@/lib/provider' import { UpdateTokenDialog } from '@/components/git/UpdateTokenDialog' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' @@ -88,7 +87,13 @@ export function ConnectionsCompactList({ setDeleteDialog({ open: false, connectionId: 0, connectionName: '' }) onConnectionDeleted?.() }, - onError: () => toast.error('Failed to delete connection'), + // The server refuses when projects still deploy from this connection and + // says which ones in the Problem Details `detail`. Swallowing that left the + // user with a bare "Failed to delete connection" and nothing to act on. + onError: (error: any) => + toast.error('Failed to delete connection', { + description: error?.detail || error?.title || error?.message, + }), }) const [healthCheckInFlight, setHealthCheckInFlight] = useState( @@ -176,25 +181,26 @@ export function ConnectionsCompactList({ Update token )} - {provider && isGitHubApp(provider) && ( - <> - - { - e.preventDefault() - setDeleteDialog({ - open: true, - connectionId: c.id, - connectionName: c.account_name, - }) - }} - > - - Delete connection - - - )} + {/* Every provider type, not just GitHub Apps: DELETE /git-connections/ + {id} is generic, and hiding it left PAT/OAuth connections with no + way to be removed — including the ones that block deleting their + provider. The server still refuses when a project depends on the + connection, and now says which. */} + + { + e.preventDefault() + setDeleteDialog({ + open: true, + connectionId: c.id, + connectionName: c.account_name, + }) + }} + > + + Delete connection + ) diff --git a/web/src/components/presets/PresetIcon.tsx b/web/src/components/presets/PresetIcon.tsx new file mode 100644 index 000000000..c5fbd68c2 --- /dev/null +++ b/web/src/components/presets/PresetIcon.tsx @@ -0,0 +1,40 @@ +import { Boxes } from 'lucide-react' +import { useState } from 'react' +import { cn } from '@/lib/utils' +import { presetIconPath } from '@/components/presets/preset-icon-paths' + +export function PresetIcon({ + preset, + label, + className, + imageClassName, +}: { + preset: string + label?: string + className?: string + imageClassName?: string +}) { + const [failedPreset, setFailedPreset] = useState(null) + const iconPath = presetIconPath(preset) + const canShowIcon = !!iconPath && failedPreset !== preset + + return ( +
    + {canShowIcon ? ( + {`${label setFailedPreset(preset)} + /> + ) : ( + + )} +
    + ) +} diff --git a/web/src/components/presets/preset-icon-paths.ts b/web/src/components/presets/preset-icon-paths.ts new file mode 100644 index 000000000..5ab90c3bb --- /dev/null +++ b/web/src/components/presets/preset-icon-paths.ts @@ -0,0 +1,44 @@ +const PRESET_ICON_PATHS: Record = { + angular: '/presets/angular.svg', + astro: '/presets/astro.svg', + autopack: '/presets/autopack.svg', + custom: '/presets/custom.svg', + dart: '/presets/dart.svg', + deno: '/presets/deno.svg', + django: '/presets/django.svg', + docker: '/presets/docker.svg', + dockercompose: '/presets/docker.svg', + dockerfile: '/presets/dockerfile.svg', + docusaurus: '/presets/docusaurus.svg', + dotnet: '/presets/dotnet.svg', + elixir: '/presets/elixir.svg', + fastapi: '/presets/fastapi.svg', + flask: '/presets/flask.svg', + go: '/presets/go.svg', + java: '/presets/java.svg', + laravel: '/presets/laravel.svg', + nextjs: '/presets/nextjs.svg', + nixpacks: '/presets/nixpacks.svg', + nixpacksnode: '/presets/nodejs.svg', + nixpacksstatic: '/presets/static.svg', + node: '/presets/nodejs.svg', + nodejs: '/presets/nodejs.svg', + nuxt: '/presets/nuxt.svg', + php: '/presets/php.svg', + python: '/presets/python.svg', + rails: '/presets/rails.svg', + react: '/presets/react.svg', + remix: '/presets/remix.svg', + rsbuild: '/presets/rsbuild.svg', + ruby: '/presets/ruby.svg', + rust: '/presets/rust.svg', + solidstart: '/presets/solidstart.svg', + static: '/presets/static.svg', + sveltekit: '/presets/sveltekit.svg', + vite: '/presets/vite.svg', + vue: '/presets/vue.svg', +} + +export function presetIconPath(preset: string): string | undefined { + return PRESET_ICON_PATHS[preset.toLowerCase().replace(/[^a-z0-9]/g, '')] +} diff --git a/web/src/components/templates/TemplateImage.tsx b/web/src/components/templates/TemplateImage.tsx index d201c6d2e..35eb25200 100644 --- a/web/src/components/templates/TemplateImage.tsx +++ b/web/src/components/templates/TemplateImage.tsx @@ -1,33 +1,7 @@ import { useState } from 'react' import { GitBranch } from 'lucide-react' import { cn } from '@/lib/utils' - -const PRESET_ICONS: Record = { - nextjs: '/presets/nextjs.svg', - fastapi: '/presets/fastapi.svg', - django: '/presets/django.svg', - remix: '/presets/remix.svg', - nuxt: '/presets/nuxt.svg', - astro: '/presets/astro.svg', - rust: '/presets/rust.svg', - go: '/presets/go.svg', - nixpacks: '/presets/nixpacks.svg', - vite: '/presets/vite.svg', - react: '/presets/react.svg', - vue: '/presets/vue.svg', - angular: '/presets/angular.svg', - flask: '/presets/flask.svg', - laravel: '/presets/laravel.svg', - rails: '/presets/rails.svg', - nodejs: '/presets/nodejs.svg', - sveltekit: '/presets/sveltekit.svg', - solidstart: '/presets/solidstart.svg', - docusaurus: '/presets/docusaurus.svg', - dockerfile: '/presets/dockerfile.svg', - docker: '/presets/docker.svg', - static: '/presets/static.svg', - rsbuild: '/presets/rsbuild.svg', -} +import { presetIconPath } from '@/components/presets/preset-icon-paths' interface TemplateImageProps { imageUrl?: string | null @@ -58,7 +32,7 @@ export function TemplateImage({ const [presetIconFailed, setPresetIconFailed] = useState(false) const showImage = !!imageUrl && !imageFailed - const presetIcon = PRESET_ICONS[preset.toLowerCase()] + const presetIcon = presetIconPath(preset) const showPresetIcon = !showImage && !!presetIcon && !presetIconFailed return ( diff --git a/web/src/components/users/RolePermissionDetails.tsx b/web/src/components/users/RolePermissionDetails.tsx new file mode 100644 index 000000000..0562ebcbb --- /dev/null +++ b/web/src/components/users/RolePermissionDetails.tsx @@ -0,0 +1,132 @@ +import { getApiKeyPermissionsOptions } from '@/api/client/@tanstack/react-query.gen' +import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' +import { Badge } from '@/components/ui/badge' +import { ScrollArea } from '@/components/ui/scroll-area' +import { Skeleton } from '@/components/ui/skeleton' +import { + categoryLabel, + effectivePlatformRole, + groupRolesPermissions, + permissionAction, +} from '@/lib/role-permissions' +import { useQuery } from '@tanstack/react-query' +import { Globe2, ShieldAlert } from 'lucide-react' + +const ROLE_SCOPE = { + user: { + title: 'All-project access', + description: + 'Can access every existing project and every project created later. Project access is not limited to selected projects.', + }, + admin: { + title: 'Full platform control', + description: + 'Can manage all projects, users, roles, settings, and system resources, including destructive operations.', + }, +} as const + +export function RolePermissionDetails({ roleNames }: { roleNames: string[] }) { + const { data, isLoading, isError } = useQuery({ + ...getApiKeyPermissionsOptions({}), + }) + + const uniqueRoleNames = Array.from(new Set(roleNames)) + const roles = + data?.roles.filter((role) => uniqueRoleNames.includes(role.name)) ?? [] + const groups = groupRolesPermissions(roles, data?.permissions ?? []) + const permissionCount = groups.reduce( + (total, group) => total + group.permissions.length, + 0 + ) + const effectiveRoleName = effectivePlatformRole(uniqueRoleNames) + const scope = effectiveRoleName ? ROLE_SCOPE[effectiveRoleName] : undefined + + return ( +
    + {scope && ( + + {effectiveRoleName === 'admin' ? ( + + ) : ( + + )} + {scope.title} + +

    + {scope.description} +

    +
    +
    + )} + +
    +
    +

    Exact permissions

    +

    + {uniqueRoleNames.length > 0 + ? `Effective union of the ${uniqueRoleNames.join(', ')} role${uniqueRoleNames.length === 1 ? '' : 's'}.` + : 'No platform role is currently assigned.'} +

    +
    + {roles.length > 0 && ( + + {permissionCount} permissions + + )} +
    + + {isLoading ? ( +
    + + + +
    + ) : isError || roles.length !== uniqueRoleNames.length ? ( + + Permissions unavailable + +

    + The exact permission list could not be loaded. No user has been + created yet. +

    +
    +
    + ) : ( + +
    + {groups.map((group) => ( +
    +
    +

    + {categoryLabel(group.category)} +

    +
    + {group.permissions.length} +
    +
    +
      + {group.permissions.map((permission) => ( +
    • +
      + {permissionAction(permission.name)} +
      +
      + {permission.name} +
      +
    • + ))} +
    +
    + ))} +
    +
    + )} +
    + ) +} diff --git a/web/src/components/users/UsersManagement.tsx b/web/src/components/users/UsersManagement.tsx index cae75f63f..206efa012 100644 --- a/web/src/components/users/UsersManagement.tsx +++ b/web/src/components/users/UsersManagement.tsx @@ -2,7 +2,6 @@ import { assignRoleMutation, - createUserMutation, deleteUserMutation, removeRoleMutation, } from '@/api/client/@tanstack/react-query.gen' @@ -37,30 +36,11 @@ import { DropdownMenuTrigger, } from '@/components/ui/dropdown-menu' import { EmptyState } from '@/components/ui/empty-state' -import { - Form, - FormControl, - FormField, - FormItem, - FormLabel, - FormMessage, -} from '@/components/ui/form' -import { Input } from '@/components/ui/input' -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from '@/components/ui/select' import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group' import { Label } from '@/components/ui/label' -import { zodResolver } from '@hookform/resolvers/zod' import { useMutation, useQueryClient } from '@tanstack/react-query' import { Edit2, - Eye, - EyeOff, MoreHorizontal, Plus, Shield, @@ -68,27 +48,21 @@ import { UserPlus, } from 'lucide-react' import { useState } from 'react' -import { useForm } from 'react-hook-form' import { useNavigate } from 'react-router' import { toast } from 'sonner' -import { z } from 'zod' - -const createUserSchema = z.object({ - name: z.string().min(3, 'Name must be at least 3 characters'), - email: z.email('Invalid email address'), - password: z.string().min(8, 'Password must be at least 8 characters'), - role: z.string().min(1, 'Please select a role'), -}) - -type CreateUserFormData = z.infer +import { RolePermissionDetails } from './RolePermissionDetails' const availableRoles = [ { value: 'admin', label: 'Administrator', - description: 'Full access to all features', + description: 'Full control of projects, users, settings, and the system.', + }, + { + value: 'user', + label: 'User', + description: 'Can deploy and operate every existing and future project.', }, - { value: 'user', label: 'User', description: 'Standard user access' }, ] interface UsersManagementProps { @@ -96,8 +70,6 @@ interface UsersManagementProps { isLoading: boolean reloadUsers: () => void onEditUser: (user: { id: number; name: string; email: string }) => void - isCreateDialogOpen: boolean - onCreateDialogOpenChange: (open: boolean) => void } export function UsersManagement({ @@ -105,42 +77,13 @@ export function UsersManagement({ isLoading, reloadUsers, onEditUser, - isCreateDialogOpen, - onCreateDialogOpenChange, }: UsersManagementProps) { const [userToDelete, setUserToDelete] = useState(null) const [userToManageRoles, setUserToManageRoles] = useState(null) - const [showPassword, setShowPassword] = useState(false) const queryClient = useQueryClient() const navigate = useNavigate() - const form = useForm({ - resolver: zodResolver(createUserSchema), - defaultValues: { - name: '', - email: '', - password: '', - role: 'user', - }, - }) - - // Use register mutation for creating users with passwords - const createUser = useMutation({ - ...createUserMutation(), - meta: { - errorTitle: 'Failed to create user', - }, - onSuccess: async () => { - // Roles are already assigned in the body during creation - // No need to assign them again here - that would create duplicates - toast.success('User created successfully') - onCreateDialogOpenChange(false) - form.reset() - reloadUsers() - }, - }) - const deleteUser = useMutation({ ...deleteUserMutation(), meta: { @@ -205,17 +148,6 @@ export function UsersManagement({ }, }) - const handleCreateUser = async (data: CreateUserFormData) => { - await createUser.mutateAsync({ - body: { - username: data.name, - email: data.email, - roles: [data.role], - password: data.password, - }, - }) - } - const handleDeleteUser = async (userId: number) => { await deleteUser.mutateAsync({ path: { @@ -271,128 +203,10 @@ export function UsersManagement({

    onCreateDialogOpenChange(true)} + onClick={() => navigate('/settings/users/new')} label="Add User" icon={} /> - - - - Create New User - -
    - - ( - - Name - - - - - - )} - /> - ( - - Email - - - - - - )} - /> - ( - - Password - -
    - - -
    -
    - -
    - )} - /> - ( - - Role - - - - )} - /> - - - - - -
    -
    !open && setUserToManageRoles(null)} > - + Manage User Role

    @@ -500,6 +314,15 @@ export function UsersManagement({ })} )} + {userToManageRoles && ( +

    + role.name)) + )} + /> +
    + )} diff --git a/web/src/hooks/useProjectSetup.test.ts b/web/src/hooks/useProjectSetup.test.ts new file mode 100644 index 000000000..8a9bbe75f --- /dev/null +++ b/web/src/hooks/useProjectSetup.test.ts @@ -0,0 +1,50 @@ +import { describe, expect, test } from 'bun:test' +import { buildProjectSetupSteps } from './useProjectSetup' + +describe('buildProjectSetupSteps', () => { + test('builds every project-scoped setup destination', () => { + const steps = buildProjectSetupSteps('storefront', { + hasAnalyticsEvents: false, + hasErrorGroups: false, + customDomainCount: 0, + monitorCount: 0, + serviceCount: 0, + hasTelemetryTraces: false, + }) + + expect(steps.map((step) => step.id)).toEqual([ + 'analytics', + 'errors', + 'domain', + 'monitoring', + 'storage', + 'telemetry', + ]) + expect(steps.map((step) => step.href)).toEqual([ + '/projects/storefront/analytics/setup', + '/projects/storefront/errors/setup', + '/projects/storefront/domains', + '/projects/storefront/monitors', + '/projects/storefront/storage', + '/projects/storefront/traces#traces-setup', + ]) + }) + + test('derives completion from project activation signals', () => { + const steps = buildProjectSetupSteps('storefront', { + hasAnalyticsEvents: true, + hasErrorGroups: false, + customDomainCount: 2, + monitorCount: 1, + serviceCount: 0, + hasTelemetryTraces: true, + }) + + expect(steps.filter((step) => step.done).map((step) => step.id)).toEqual([ + 'analytics', + 'domain', + 'monitoring', + 'telemetry', + ]) + }) +}) diff --git a/web/src/hooks/useProjectSetup.ts b/web/src/hooks/useProjectSetup.ts new file mode 100644 index 000000000..14e6b54b2 --- /dev/null +++ b/web/src/hooks/useProjectSetup.ts @@ -0,0 +1,183 @@ +import type { ProjectResponse } from '@/api/client' +import { + hasAnalyticsEventsOptions, + hasErrorGroupsOptions, + listCustomDomainsForProjectOptions, + listMonitorsOptions, + listProjectServicesOptions, + queryTraceSummariesOptions, +} from '@/api/client/@tanstack/react-query.gen' +import { useQuery } from '@tanstack/react-query' +import { + Activity, + BarChart3, + Database, + Globe, + ShieldAlert, + Workflow, + type LucideIcon, +} from 'lucide-react' + +export type ProjectSetupStepId = + 'analytics' | 'errors' | 'domain' | 'monitoring' | 'storage' | 'telemetry' + +export interface ProjectSetupStep { + id: ProjectSetupStepId + title: string + description: string + href: string + cta: string + done: boolean + icon: LucideIcon +} + +export interface ProjectSetupSignals { + hasAnalyticsEvents: boolean + hasErrorGroups: boolean + customDomainCount: number + monitorCount: number + serviceCount: number + hasTelemetryTraces: boolean +} + +export function buildProjectSetupSteps( + projectSlug: string, + signals: ProjectSetupSignals +): ProjectSetupStep[] { + const base = `/projects/${projectSlug}` + + return [ + { + id: 'analytics', + title: 'Install the analytics SDK', + description: + 'Understand traffic, pages, visitors, funnels, and performance with project-scoped analytics.', + href: `${base}/analytics/setup`, + cta: 'View analytics setup', + done: signals.hasAnalyticsEvents, + icon: BarChart3, + }, + { + id: 'errors', + title: 'Install the error tracking SDK', + description: + 'Capture application exceptions with stack traces, releases, and the request context needed to debug them.', + href: `${base}/errors/setup`, + cta: 'View error tracking setup', + done: signals.hasErrorGroups, + icon: ShieldAlert, + }, + { + id: 'domain', + title: 'Connect a custom domain', + description: + 'Give the project a production hostname and let Temps provision and renew its TLS certificate.', + href: `${base}/domains`, + cta: 'Manage domains', + done: signals.customDomainCount > 0, + icon: Globe, + }, + { + id: 'monitoring', + title: 'Add an uptime monitor', + description: + 'Continuously check the production endpoint and surface outages before users report them.', + href: `${base}/monitors`, + cta: 'Configure monitoring', + done: signals.monitorCount > 0, + icon: Activity, + }, + { + id: 'storage', + title: 'Link database or storage', + description: + 'Attach a managed service to this project so application data and deployment configuration stay together.', + href: `${base}/storage`, + cta: 'Open project storage', + done: signals.serviceCount > 0, + icon: Database, + }, + { + id: 'telemetry', + title: 'Set up OpenTelemetry', + description: + 'Send distributed traces from this application to connect requests across services and deployments.', + href: `${base}/traces#traces-setup`, + cta: 'View OpenTelemetry setup', + done: signals.hasTelemetryTraces, + icon: Workflow, + }, + ] +} + +export function useProjectSetup(project: ProjectResponse) { + const analyticsQuery = useQuery({ + ...hasAnalyticsEventsOptions({ path: { project_id: project.id } }), + }) + const errorsQuery = useQuery({ + ...hasErrorGroupsOptions({ path: { project_id: project.id } }), + }) + const domainsQuery = useQuery({ + ...listCustomDomainsForProjectOptions({ + path: { project_id: project.id }, + }), + }) + const monitorsQuery = useQuery({ + ...listMonitorsOptions({ path: { project_id: project.id } }), + }) + const servicesQuery = useQuery({ + ...listProjectServicesOptions({ path: { project_id: project.id } }), + }) + const telemetryQuery = useQuery({ + ...queryTraceSummariesOptions({ + query: { + project_id: project.id, + limit: 1, + include_total: false, + }, + }), + }) + + const steps = buildProjectSetupSteps(project.slug, { + hasAnalyticsEvents: !!analyticsQuery.data?.has_events, + hasErrorGroups: !!errorsQuery.data?.has_error_groups, + customDomainCount: domainsQuery.data?.domains?.length ?? 0, + monitorCount: monitorsQuery.data?.length ?? 0, + serviceCount: servicesQuery.data?.length ?? 0, + hasTelemetryTraces: (telemetryQuery.data?.data?.length ?? 0) > 0, + }) + const completedCount = steps.filter((step) => step.done).length + const totalCount = steps.length + + return { + steps, + completedCount, + totalCount, + percent: Math.round((completedCount / totalCount) * 100), + nextStep: steps.find((step) => !step.done), + allDone: completedCount === totalCount, + isLoading: + analyticsQuery.isLoading || + errorsQuery.isLoading || + domainsQuery.isLoading || + monitorsQuery.isLoading || + servicesQuery.isLoading || + telemetryQuery.isLoading, + isError: + analyticsQuery.isError || + errorsQuery.isError || + domainsQuery.isError || + monitorsQuery.isError || + servicesQuery.isError || + telemetryQuery.isError, + refetch: () => + Promise.all([ + analyticsQuery.refetch(), + errorsQuery.refetch(), + domainsQuery.refetch(), + monitorsQuery.refetch(), + servicesQuery.refetch(), + telemetryQuery.refetch(), + ]), + } +} diff --git a/web/src/lib/drop-archive.ts b/web/src/lib/drop-archive.ts index a19eec62e..d44daf5b0 100644 --- a/web/src/lib/drop-archive.ts +++ b/web/src/lib/drop-archive.ts @@ -94,13 +94,27 @@ function writeU32(view: DataView, offset: number, value: number) { view.setUint32(offset, value >>> 0, true) } -function crc32(bytes: Uint8Array): number { +function throwIfAborted(signal?: AbortSignal) { + if (signal?.aborted) { + throw new DOMException('Preset detection was cancelled', 'AbortError') + } +} + +async function crc32(bytes: Uint8Array, signal?: AbortSignal): Promise { let crc = 0xffffffff - for (const byte of bytes) { - crc ^= byte - for (let bit = 0; bit < 8; bit += 1) { - crc = (crc >>> 1) ^ (0xedb88320 & -(crc & 1)) + const yieldEveryBytes = 2 * 1024 * 1024 + for (let offset = 0; offset < bytes.length; offset += yieldEveryBytes) { + throwIfAborted(signal) + const end = Math.min(offset + yieldEveryBytes, bytes.length) + for (let index = offset; index < end; index += 1) { + crc ^= bytes[index] + for (let bit = 0; bit < 8; bit += 1) { + crc = (crc >>> 1) ^ (0xedb88320 & -(crc & 1)) + } } + // Keep the clear button responsive while a large folder is checksummed. + if (end < bytes.length) + await new Promise((resolve) => setTimeout(resolve, 0)) } return (crc ^ 0xffffffff) >>> 0 } @@ -117,7 +131,8 @@ function dosTimestamp(date: Date): { date: number; time: number } { } async function createStoredZip( - entries: Array<{ path: string; contents: Blob }> + entries: Array<{ path: string; contents: Blob }>, + signal?: AbortSignal ): Promise { const localParts: BlobPart[] = [] const centralParts: BlobPart[] = [] @@ -126,9 +141,10 @@ async function createStoredZip( const now = dosTimestamp(new Date()) for (const entry of entries) { + throwIfAborted(signal) const name = textEncoder.encode(cleanPath(entry.path)) const contents = new Uint8Array(await entry.contents.arrayBuffer()) - const checksum = crc32(contents) + const checksum = await crc32(contents, signal) const localHeader = new ArrayBuffer(30) const localView = new DataView(localHeader) @@ -204,8 +220,10 @@ function redirectPage(target: string): Blob { export async function prepareDrop( rawFiles: DropFile[], - selectedRootPage?: string + selectedRootPage?: string, + signal?: AbortSignal ): Promise { + throwIfAborted(signal) if (rawFiles.length === 1 && isDropArchive(rawFiles[0].file.name)) { if (rawFiles[0].file.size > 500 * 1024 * 1024) { throw new Error('Drop exceeds the 500 MB upload limit') @@ -238,7 +256,7 @@ export async function prepareDrop( } } - const archive = await createStoredZip(entries) + const archive = await createStoredZip(entries, signal) return { file: new File([archive], 'temps-drop.zip', { type: 'application/zip' }), fileCount: files.length, diff --git a/web/src/lib/drop-environment-variables.test.ts b/web/src/lib/drop-environment-variables.test.ts new file mode 100644 index 000000000..8fa7a86a1 --- /dev/null +++ b/web/src/lib/drop-environment-variables.test.ts @@ -0,0 +1,37 @@ +import { describe, expect, test } from 'bun:test' +import { + serializeDropEnvironmentVariables, + validateDropEnvironmentVariables, +} from './drop-environment-variables' + +const variable = (key: string, value = '') => ({ id: key, key, value }) + +describe('drop environment variables', () => { + test('accepts empty values and serializes trimmed keys', () => { + const variables = [ + variable(' API_URL ', 'https://example.com'), + variable('EMPTY'), + ] + + expect(validateDropEnvironmentVariables(variables)).toBeNull() + expect(serializeDropEnvironmentVariables(variables)).toEqual([ + ['API_URL', 'https://example.com'], + ['EMPTY', ''], + ]) + }) + + test('rejects missing, invalid, and duplicate keys', () => { + expect(validateDropEnvironmentVariables([variable('')])).toContain( + 'needs a key' + ) + expect(validateDropEnvironmentVariables([variable('1INVALID')])).toContain( + 'not a valid' + ) + expect( + validateDropEnvironmentVariables([ + variable('API_URL'), + variable('API_URL'), + ]) + ).toContain('more than once') + }) +}) diff --git a/web/src/lib/drop-environment-variables.ts b/web/src/lib/drop-environment-variables.ts new file mode 100644 index 000000000..5b3cb2010 --- /dev/null +++ b/web/src/lib/drop-environment-variables.ts @@ -0,0 +1,31 @@ +export interface DropEnvironmentVariable { + id: string + key: string + value: string +} + +const ENVIRONMENT_VARIABLE_KEY = /^[A-Za-z_][A-Za-z0-9_]*$/ + +export function validateDropEnvironmentVariables( + variables: DropEnvironmentVariable[] +): string | null { + const seen = new Set() + + for (const variable of variables) { + const key = variable.key.trim() + if (!key) return 'Every environment variable needs a key' + if (!ENVIRONMENT_VARIABLE_KEY.test(key)) { + return `${key} is not a valid environment variable key` + } + if (seen.has(key)) return `${key} is defined more than once` + seen.add(key) + } + + return null +} + +export function serializeDropEnvironmentVariables( + variables: DropEnvironmentVariable[] +): Array<[string, string]> { + return variables.map((variable) => [variable.key.trim(), variable.value]) +} diff --git a/web/src/lib/drop-handoff.test.ts b/web/src/lib/drop-handoff.test.ts new file mode 100644 index 000000000..fe2b09940 --- /dev/null +++ b/web/src/lib/drop-handoff.test.ts @@ -0,0 +1,14 @@ +import { describe, expect, test } from 'bun:test' +import { consumeDropFilesHandoff, handOffDropFiles } from './drop-handoff' + +describe('drop file handoff', () => { + test('transfers files exactly once without putting them in browser history', () => { + const file = new File(['hello'], 'index.html', { type: 'text/html' }) + handOffDropFiles([{ file, path: 'site/index.html' }]) + + expect(consumeDropFilesHandoff()).toEqual([ + { file, path: 'site/index.html' }, + ]) + expect(consumeDropFilesHandoff()).toBeNull() + }) +}) diff --git a/web/src/lib/drop-handoff.ts b/web/src/lib/drop-handoff.ts new file mode 100644 index 000000000..f585ce0bb --- /dev/null +++ b/web/src/lib/drop-handoff.ts @@ -0,0 +1,16 @@ +import type { DropFile } from './drop-archive' + +// File objects cannot be encoded into a URL and large folders should not be +// copied into browser history state. Keep the selection in memory for the +// single navigation from the project-list empty state to `/drop`. +let pendingDropFiles: DropFile[] | null = null + +export function handOffDropFiles(files: DropFile[]): void { + pendingDropFiles = files +} + +export function consumeDropFilesHandoff(): DropFile[] | null { + const files = pendingDropFiles + pendingDropFiles = null + return files +} diff --git a/web/src/lib/drop-preset-detection.test.ts b/web/src/lib/drop-preset-detection.test.ts new file mode 100644 index 000000000..8aca31b08 --- /dev/null +++ b/web/src/lib/drop-preset-detection.test.ts @@ -0,0 +1,66 @@ +import { describe, expect, test } from 'bun:test' +import { prepareAndInspectDrop } from './drop-preset-detection' + +describe('prepareAndInspectDrop', () => { + test('packages selected files and returns the detected preset', async () => { + let inspectedArchive: File | undefined + const result = await prepareAndInspectDrop( + [ + { + file: new File(['

    Hello

    '], 'index.html'), + path: 'index.html', + }, + ], + undefined, + async (archive) => { + inspectedArchive = archive + return { + suggestedName: 'hello', + candidates: [ + { + confidence: 'high', + directory: '.', + isStatic: true, + label: 'Static site', + preset: 'static', + reason: 'Found index.html', + }, + ], + } + } + ) + + expect(inspectedArchive).toBeInstanceOf(File) + expect(result.archive).toBe(inspectedArchive!) + expect(result.inspection.candidates[0]?.preset).toBe('static') + }) + + test('rejects an inspection with no deployable candidates', async () => { + await expect( + prepareAndInspectDrop( + [{ file: new File(['{}'], 'package.json'), path: 'package.json' }], + undefined, + async () => ({ suggestedName: 'empty', candidates: [] }) + ) + ).rejects.toThrow('No deployable project preset was detected') + }) + + test('cancels before uploading when the user clears the selection', async () => { + const controller = new AbortController() + controller.abort() + let inspectCalled = false + + await expect( + prepareAndInspectDrop( + [{ file: new File(['{}'], 'package.json'), path: 'package.json' }], + undefined, + async () => { + inspectCalled = true + return { suggestedName: 'cancelled', candidates: [] } + }, + { signal: controller.signal } + ) + ).rejects.toMatchObject({ name: 'AbortError' }) + expect(inspectCalled).toBe(false) + }) +}) diff --git a/web/src/lib/drop-preset-detection.ts b/web/src/lib/drop-preset-detection.ts new file mode 100644 index 000000000..83719595e --- /dev/null +++ b/web/src/lib/drop-preset-detection.ts @@ -0,0 +1,32 @@ +import type { DropInspectionResponse } from '@/api/client' +import { prepareDrop, type DropFile } from '@/lib/drop-archive' + +export interface PreparedDropInspection { + archive: File + inspection: DropInspectionResponse +} + +interface PrepareAndInspectOptions { + signal?: AbortSignal + onArchivePrepared?: (archive: File) => void +} + +export async function prepareAndInspectDrop( + files: DropFile[], + rootPage: string | undefined, + inspect: (archive: File) => Promise, + options: PrepareAndInspectOptions = {} +): Promise { + const prepared = await prepareDrop(files, rootPage, options.signal) + options.onArchivePrepared?.(prepared.file) + const inspection = await inspect(prepared.file) + + if (!inspection) { + throw new Error('Preset detection returned no result') + } + if (inspection.candidates.length === 0) { + throw new Error('No deployable project preset was detected') + } + + return { archive: prepared.file, inspection } +} diff --git a/web/src/lib/password-policy.test.ts b/web/src/lib/password-policy.test.ts new file mode 100644 index 000000000..61632471b --- /dev/null +++ b/web/src/lib/password-policy.test.ts @@ -0,0 +1,44 @@ +import { describe, expect, test } from 'bun:test' +import { + PASSWORD_REQUIREMENTS, + generateCompliantPassword, + passwordRequirementResults, + passwordSchema, +} from './password-policy' + +describe('password policy', () => { + test('matches every server-side password requirement', () => { + expect(PASSWORD_REQUIREMENTS.map((requirement) => requirement.id)).toEqual([ + 'length', + 'uppercase', + 'lowercase', + 'number', + 'special', + ]) + expect(passwordSchema.safeParse('ValidPass1!').success).toBe(true) + }) + + test('reports unmet requirements independently', () => { + const results = passwordRequirementResults('password') + expect( + results.filter((result) => result.met).map((result) => result.id) + ).toEqual(['length', 'lowercase']) + }) + + test('generates random passwords that meet the complete policy', () => { + const generated = Array.from({ length: 20 }, () => + generateCompliantPassword() + ) + + expect(generated.every((password) => password.length === 20)).toBe(true) + expect( + generated.every((password) => passwordSchema.safeParse(password).success) + ).toBe(true) + expect(new Set(generated).size).toBe(generated.length) + }) + + test('rejects generated password lengths outside the server limits', () => { + expect(() => generateCompliantPassword(7)).toThrow(RangeError) + expect(() => generateCompliantPassword(129)).toThrow(RangeError) + }) +}) diff --git a/web/src/lib/password-policy.ts b/web/src/lib/password-policy.ts new file mode 100644 index 000000000..d7ad846bb --- /dev/null +++ b/web/src/lib/password-policy.ts @@ -0,0 +1,91 @@ +import { z } from 'zod' + +export const PASSWORD_REQUIREMENTS = [ + { + id: 'length', + label: '8–128 characters', + test: (password: string) => password.length >= 8 && password.length <= 128, + }, + { + id: 'uppercase', + label: 'One uppercase letter', + test: (password: string) => /[A-Z]/.test(password), + }, + { + id: 'lowercase', + label: 'One lowercase letter', + test: (password: string) => /[a-z]/.test(password), + }, + { + id: 'number', + label: 'One number', + test: (password: string) => /[0-9]/.test(password), + }, + { + id: 'special', + label: 'One special character', + test: (password: string) => /[^a-zA-Z0-9]/.test(password), + }, +] as const + +export const passwordSchema = z + .string() + .min(8, 'Password must be at least 8 characters long') + .max(128, 'Password must not exceed 128 characters') + .regex(/[A-Z]/, 'Password must contain at least one uppercase letter') + .regex(/[a-z]/, 'Password must contain at least one lowercase letter') + .regex(/[0-9]/, 'Password must contain at least one digit') + .regex(/[^a-zA-Z0-9]/, 'Password must contain at least one special character') + +export function passwordRequirementResults(password: string) { + return PASSWORD_REQUIREMENTS.map((requirement) => ({ + ...requirement, + met: requirement.test(password), + })) +} + +const PASSWORD_ALPHABETS = { + uppercase: 'ABCDEFGHJKLMNPQRSTUVWXYZ', + lowercase: 'abcdefghijkmnopqrstuvwxyz', + number: '23456789', + special: '!@#$%^&*_-+=', +} as const + +const PASSWORD_CHARACTERS = Object.values(PASSWORD_ALPHABETS).join('') + +function secureRandomIndex(length: number): number { + const maximum = Math.floor(256 / length) * length + const randomByte = new Uint8Array(1) + + do { + crypto.getRandomValues(randomByte) + } while (randomByte[0] >= maximum) + + return randomByte[0] % length +} + +/** Generate a copy-friendly password with every server-required character class. */ +export function generateCompliantPassword(length = 20): string { + if (length < 8 || length > 128) { + throw new RangeError('Password length must be between 8 and 128 characters') + } + + const characters = Object.values(PASSWORD_ALPHABETS).map( + (alphabet) => alphabet[secureRandomIndex(alphabet.length)] + ) + while (characters.length < length) { + characters.push( + PASSWORD_CHARACTERS[secureRandomIndex(PASSWORD_CHARACTERS.length)] + ) + } + + for (let index = characters.length - 1; index > 0; index -= 1) { + const swapIndex = secureRandomIndex(index + 1) + ;[characters[index], characters[swapIndex]] = [ + characters[swapIndex], + characters[index], + ] + } + + return characters.join('') +} diff --git a/web/src/lib/role-permissions.test.ts b/web/src/lib/role-permissions.test.ts new file mode 100644 index 000000000..214542056 --- /dev/null +++ b/web/src/lib/role-permissions.test.ts @@ -0,0 +1,65 @@ +import { describe, expect, test } from 'bun:test' +import type { PermissionInfo, RoleInfo } from '@/api/client' +import { + categoryLabel, + effectivePlatformRole, + groupRolePermissions, + groupRolesPermissions, + permissionAction, +} from './role-permissions' + +const permissions: PermissionInfo[] = [ + { name: 'projects:read', category: 'PROJECTS', description: 'View projects' }, + { name: 'users:manage', category: 'USERS', description: 'Manage users' }, + { + name: 'projects:create', + category: 'PROJECTS', + description: 'Create projects', + }, +] + +const role: RoleInfo = { + name: 'admin', + description: 'Administrator', + permissions: [ + 'users:manage', + 'projects:read', + 'projects:create', + 'projects:read', + ], +} + +describe('role permissions', () => { + test('does not infer all-project access without a recognized role', () => { + expect(effectivePlatformRole([])).toBeNull() + expect(effectivePlatformRole(['unknown'])).toBeNull() + expect(effectivePlatformRole(['user'])).toBe('user') + expect(effectivePlatformRole(['user', 'admin'])).toBe('admin') + }) + + test('groups every granted permission without dropping identifiers', () => { + const groups = groupRolePermissions(role, permissions) + expect(groups.map((group) => group.category)).toEqual(['projects', 'users']) + expect( + groups.flatMap((group) => group.permissions.map((item) => item.name)) + ).toEqual(['projects:read', 'projects:create', 'users:manage']) + }) + + test('formats categories and actions for display', () => { + expect(categoryLabel('api_keys')).toBe('Api Keys') + expect(permissionAction('notification_providers:create')).toBe('create') + }) + + test('shows the de-duplicated effective union for multiple roles', () => { + const userRole: RoleInfo = { + name: 'user', + description: 'User', + permissions: ['projects:read'], + } + const groups = groupRolesPermissions([userRole, role], permissions) + + expect( + groups.flatMap((group) => group.permissions.map((item) => item.name)) + ).toEqual(['projects:read', 'projects:create', 'users:manage']) + }) +}) diff --git a/web/src/lib/role-permissions.ts b/web/src/lib/role-permissions.ts new file mode 100644 index 000000000..b2e108bbc --- /dev/null +++ b/web/src/lib/role-permissions.ts @@ -0,0 +1,68 @@ +import type { PermissionInfo, RoleInfo } from '@/api/client' + +export function effectivePlatformRole( + roleNames: string[] +): 'admin' | 'user' | null { + if (roleNames.includes('admin')) return 'admin' + if (roleNames.includes('user')) return 'user' + return null +} + +export type PermissionGroup = { + category: string + permissions: PermissionInfo[] +} + +export function groupRolePermissions( + role: RoleInfo | undefined, + availablePermissions: PermissionInfo[] +): PermissionGroup[] { + return groupRolesPermissions(role ? [role] : [], availablePermissions) +} + +export function groupRolesPermissions( + roles: RoleInfo[], + availablePermissions: PermissionInfo[] +): PermissionGroup[] { + if (roles.length === 0) return [] + + const permissionByName = new Map( + availablePermissions.map((permission) => [permission.name, permission]) + ) + const groups = new Map() + const seen = new Set() + + for (const role of roles) { + for (const name of role.permissions) { + if (seen.has(name)) continue + seen.add(name) + const permission = permissionByName.get(name) ?? { + name, + category: name.split(':')[0] || 'OTHER', + description: 'Permission for this resource', + } + const category = permission.category.toLowerCase() + const existing = groups.get(category) ?? [] + existing.push(permission) + groups.set(category, existing) + } + } + + return Array.from(groups, ([category, permissions]) => ({ + category, + permissions, + })).sort((left, right) => left.category.localeCompare(right.category)) +} + +export function permissionAction(permissionName: string): string { + const segments = permissionName.split(':') + const action = segments[segments.length - 1] ?? permissionName + return action.replace(/_/g, ' ') +} + +export function categoryLabel(category: string): string { + return category + .split(/[_-]/) + .map((part) => part.charAt(0).toUpperCase() + part.slice(1)) + .join(' ') +} diff --git a/web/src/pages/Account.tsx b/web/src/pages/Account.tsx index 2dc6477ea..bb88bd6d3 100644 --- a/web/src/pages/Account.tsx +++ b/web/src/pages/Account.tsx @@ -60,16 +60,14 @@ type FormValues = z.infer const passwordSchema = z .object({ current_password: z.string().min(1, 'Current password is required'), - new_password: z - .string() - .min(8, 'Password must be at least 8 characters'), + new_password: z.string().min(8, 'Password must be at least 8 characters'), confirm_password: z.string().min(1, 'Please confirm your new password'), mfa_code: z .string() .optional() .refine( (v) => !v || /^\d{6}$/.test(v) || v.length >= 8, - 'Enter a 6-digit TOTP code or a recovery code', + 'Enter a 6-digit TOTP code or a recovery code' ), revoke_other_sessions: z.boolean(), }) @@ -150,16 +148,18 @@ export function Account() { }, }) - const { mutate: changePassword, isPending: isChangingPassword } = useMutation({ - ...changePasswordSelfMutation(), - meta: { - errorTitle: 'Failed to change password', - }, - onSuccess: () => { - toast.success('Password changed successfully') - passwordForm.reset() - }, - }) + const { mutate: changePassword, isPending: isChangingPassword } = useMutation( + { + ...changePasswordSelfMutation(), + meta: { + errorTitle: 'Failed to change password', + }, + onSuccess: () => { + toast.success('Password changed successfully') + passwordForm.reset() + }, + } + ) const mfaForm = useForm({ resolver: zodResolver(mfaVerifySchema), @@ -300,7 +300,9 @@ export function Account() {
    Role
    - + {user.role} @@ -511,6 +513,25 @@ export function Account() { {mfaSetupData?.secret_key}
    + {mfaSetupData?.recovery_codes?.length ? ( +
    +
    Recovery codes
    +

    + Save these somewhere secure before enabling MFA. Each code can + be used once. +

    +
    + {mfaSetupData.recovery_codes.map((code) => ( + {code} + ))} +
    +
    + ) : ( +

    + Recovery codes could not be prepared. Close this dialog and + restart MFA setup. +

    + )}
    - +
    +

    + Create user +

    +

    + Create login credentials, choose the platform role, and review + every permission before granting access. +

    +
    +
    +
    + + + +
    + + + Account details + + +
    + ( + + Name + + + + + + )} + /> + ( + + Email + + + + + + )} + /> +
    + + ( + + Temporary password + +
    + + + + + + + Generate secure password + + + +
    +
    + + The password must meet every requirement below. + + +
      + {PASSWORD_REQUIREMENTS.map((requirement, index) => { + const met = requirementResults[index]?.met ?? false + return ( +
    • + {met ? ( + + ) : ( + + )} +
      {requirement.label}
      +
    • + ) + })} +
    +
    + )} + /> + + ( + +
    + + + +
    + + Require a new password at first sign-in + + + The temporary password only starts a protected + password-change session. The user cannot access the + platform until they choose a new password. + +
    +
    +
    + )} + /> +
    +
    + + + + Role + + + ( + + + + {ROLE_OPTIONS.map((role) => ( + + ))} + + + + + )} + /> + + + + + + Team membership + + +
    + ( + + Team + + + Optional. Adds the user to the selected team after + creating their account. + + {teamsQuery.isError && ( +

    + Teams could not be loaded. You can still create the + user and add them from the Teams page later. +

    + )} + +
    + )} + /> + + ( + + Team role + + + { + TEAM_ROLE_OPTIONS.find( + (role) => role.value === selectedTeamRole + )?.description + } + + + + )} + /> +
    + + {selectedTeamId && ( +
    + Team membership and the platform role are separate. A User + still has all-project access from their platform role; + joining a team does not narrow those permissions. +
    + )} +
    +
    + +
    + {teamAssignmentFailure ? ( + + + Account created; team assignment pending + + +

    + The account is ready, but it has not been added to the + selected team. Retry safely without creating a duplicate + account. +

    +
    + + +
    +
    +
    + ) : ( + <> + + + + )} +
    +
    + + + + + {selectedRole === 'admin' ? 'Administrator' : 'User'} access + + + + + + + + + + ) +} diff --git a/web/src/pages/Drop.tsx b/web/src/pages/Drop.tsx index dacc86442..cb6770f5b 100644 --- a/web/src/pages/Drop.tsx +++ b/web/src/pages/Drop.tsx @@ -5,11 +5,15 @@ import { deployFromStatic, getEnvironments, inspectDropArchive, + uploadStaticBundle, type DropInspectionResponse, type EnvironmentResponse, type ProjectResponse, } from '@/api/client' import { DropZone } from '@/components/drop/DropZone' +import { DropEnvironmentVariables } from '@/components/drop/DropEnvironmentVariables' +import { DetectedPresetCard } from '@/components/drop/DetectedPresetCard' +import { DetectedPresetGrid } from '@/components/drop/DetectedPresetGrid' import { PageContainer } from '@/components/layout/PageContainer' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' @@ -24,17 +28,30 @@ import { import { useBreadcrumbs } from '@/contexts/BreadcrumbContext' import { usePageTitle } from '@/hooks/usePageTitle' import { - formatDetectedProjectLabel, htmlRootCandidates, isDropArchive, - prepareDrop, type DropFile, } from '@/lib/drop-archive' import { dropErrorMessage, inferredProjectName } from '@/lib/drop-files' +import { consumeDropFilesHandoff } from '@/lib/drop-handoff' +import { + serializeDropEnvironmentVariables, + validateDropEnvironmentVariables, + type DropEnvironmentVariable, +} from '@/lib/drop-environment-variables' +import { prepareAndInspectDrop } from '@/lib/drop-preset-detection' import { ensureDropProjectName } from '@/lib/drop-project-name' import { cn } from '@/lib/utils' -import { ArrowRight, Check, Loader2, RotateCcw, UploadCloud } from 'lucide-react' -import { useEffect, useMemo, useState } from 'react' +import { AnimatePresence, motion, useReducedMotion } from 'framer-motion' +import { + ArrowRight, + Check, + Loader2, + RotateCcw, + UploadCloud, + X, +} from 'lucide-react' +import { useEffect, useMemo, useRef, useState } from 'react' import { Link, useNavigate } from 'react-router' type DropStage = @@ -46,7 +63,11 @@ type DropStage = | 'deploying' | 'done' -function stageLabel(stage: DropStage): string { +function stageLabel( + stage: DropStage, + detectedLabel?: string, + hasFiles = false +): string { switch (stage) { case 'packing': return 'Packing files locally' @@ -61,12 +82,14 @@ function stageLabel(stage: DropStage): string { case 'done': return 'Deployment started' default: - return 'Ready to deploy' + if (detectedLabel) return `Deploy ${detectedLabel}` + return hasFiles ? 'Retry preset detection' : 'Select project files' } } export function Drop() { const navigate = useNavigate() + const reduceMotion = useReducedMotion() const { setBreadcrumbs } = useBreadcrumbs() const [files, setFiles] = useState([]) const [projectName, setProjectName] = useState('') @@ -83,6 +106,12 @@ export function Drop() { null ) const [selectedCandidateIndex, setSelectedCandidateIndex] = useState('0') + const [environmentVariables, setEnvironmentVariables] = useState< + DropEnvironmentVariable[] + >([]) + const [handedOffFiles] = useState(() => consumeDropFilesHandoff()) + const detectionRunRef = useRef(0) + const detectionAbortRef = useRef(null) usePageTitle('Drop') useEffect(() => { @@ -91,6 +120,12 @@ export function Drop() { { label: 'Drop' }, ]) }, [setBreadcrumbs]) + useEffect( + () => () => { + detectionAbortRef.current?.abort() + }, + [] + ) const normalizedCandidates = useMemo(() => htmlRootCandidates(files), [files]) const hasRootIndex = normalizedCandidates.some( @@ -98,8 +133,70 @@ export function Drop() { ) const isArchive = files.length === 1 && isDropArchive(files[0].file.name) const isBusy = !['idle', 'done'].includes(stage) + const selectedCandidate = + inspection?.candidates[Number(selectedCandidateIndex)] + const transition = reduceMotion + ? { duration: 0 } + : { duration: 0.32, ease: [0.22, 1, 0.36, 1] as const } + + const inspectArchive = async (archive: File, signal?: AbortSignal) => { + const response = await inspectDropArchive({ + throwOnError: true, + body: { file: archive }, + signal, + }) + return response.data + } + + async function detectSelection( + nextFiles: DropFile[], + nextRootPage: string, + runId: number + ) { + detectionAbortRef.current?.abort() + const controller = new AbortController() + detectionAbortRef.current = controller + try { + setStage('packing') + const result = await prepareAndInspectDrop( + nextFiles, + nextRootPage || undefined, + (archive) => inspectArchive(archive, controller.signal), + { + signal: controller.signal, + onArchivePrepared: (archive) => { + if (detectionRunRef.current !== runId) return + setPreparedArchive(archive) + setStage('detecting') + }, + } + ) + if (detectionRunRef.current !== runId) return + + setPreparedArchive(result.archive) + setInspection(result.inspection) + setSelectedCandidateIndex('0') + if (!nameWasEdited) { + setProjectName(ensureDropProjectName(result.inspection.suggestedName)) + } + setStage('idle') + } catch (caught) { + if (detectionRunRef.current !== runId) return + setError(dropErrorMessage(caught)) + setPreparedArchive(null) + setInspection(null) + setStage('idle') + } finally { + if (detectionAbortRef.current === controller) { + detectionAbortRef.current = null + } + } + } const setSelection = (nextFiles: DropFile[]) => { + const runId = ++detectionRunRef.current + detectionAbortRef.current?.abort() + detectionAbortRef.current = null setFiles(nextFiles) setError(null) setProject(null) @@ -112,13 +209,31 @@ export function Drop() { const hasIndex = candidates.some( (path) => path.toLowerCase() === 'index.html' ) - setRootPage(hasIndex ? '' : candidates[0] || '') + const nextRootPage = hasIndex ? '' : candidates[0] || '' + setRootPage(nextRootPage) if (!nameWasEdited) { setProjectName(ensureDropProjectName(inferredProjectName(nextFiles))) } + if (nextFiles.length > 0) { + void detectSelection(nextFiles, nextRootPage, runId) + } } + useEffect(() => { + if (!handedOffFiles?.length) return + const startHandoff = window.setTimeout( + () => setSelection(handedOffFiles), + 0 + ) + return () => window.clearTimeout(startHandoff) + // The handoff is deliberately consumed only on the first `/drop` mount. + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [handedOffFiles]) + const reset = () => { + detectionRunRef.current += 1 + detectionAbortRef.current?.abort() + detectionAbortRef.current = null setFiles([]) setProjectName('') setNameWasEdited(false) @@ -130,6 +245,7 @@ export function Drop() { setPreparedArchive(null) setInspection(null) setSelectedCandidateIndex('0') + setEnvironmentVariables([]) } const deploy = async () => { @@ -141,27 +257,18 @@ export function Drop() { setProjectName(normalizedProjectName) setError(null) try { - let archive = preparedArchive - let detected = inspection + const archive = preparedArchive + const detected = inspection if (!archive || !detected) { - setStage('packing') - const prepared = await prepareDrop(files, rootPage || undefined) - archive = prepared.file - setPreparedArchive(archive) + const runId = ++detectionRunRef.current + await detectSelection(files, rootPage, runId) + return + } - setStage('detecting') - const inspectResponse = await inspectDropArchive({ - throwOnError: true, - body: { file: archive }, - }) - detected = inspectResponse.data - if (!detected) throw new Error('Preset detection returned no result') - setInspection(detected) - setSelectedCandidateIndex('0') - if (!nameWasEdited) { - setProjectName(ensureDropProjectName(detected.suggestedName)) - } - setStage('idle') + const environmentVariableError = + validateDropEnvironmentVariables(environmentVariables) + if (environmentVariableError) { + setError(environmentVariableError) return } @@ -183,6 +290,8 @@ export function Drop() { project_type: candidate.isStatic ? 'static' : 'server', automatic_deploy: false, storage_service_ids: [], + environment_variables: + serializeDropEnvironmentVariables(environmentVariables), }, }) createdProject = projectResult.data @@ -201,8 +310,6 @@ export function Drop() { throw new Error('The project has no deployment environment') setStage('uploading') - const body = new FormData() - body.append('file', archive) if (!candidate.isStatic) { const sourceResponse = await deployFromUploadedSource({ throwOnError: true, @@ -221,19 +328,13 @@ export function Drop() { ) return } - const uploadResponse = await fetch( - `/api/projects/${createdProject.id}/upload/static`, - { method: 'POST', credentials: 'include', body } - ) - if (!uploadResponse.ok) { - const problem = (await uploadResponse.json().catch(() => null)) as { - detail?: string - } | null - throw new Error( - problem?.detail || `Upload failed (${uploadResponse.status})` - ) - } - const bundle = (await uploadResponse.json()) as { id: number } + const uploadResponse = await uploadStaticBundle({ + throwOnError: true, + path: { project_id: createdProject.id }, + body: { file: archive }, + }) + const bundle = uploadResponse.data + if (!bundle) throw new Error('Static upload returned no bundle') setStage('deploying') await deployFromStatic({ @@ -332,161 +433,200 @@ export function Drop() { -
    - - - + +

    + Failed setup is rolled back automatically. +

    + + )} +
    - ) } diff --git a/web/src/pages/GitProviderDetail.tsx b/web/src/pages/GitProviderDetail.tsx index 7ddc1b61f..df7ed6e20 100644 --- a/web/src/pages/GitProviderDetail.tsx +++ b/web/src/pages/GitProviderDetail.tsx @@ -1,7 +1,8 @@ import { deleteGitProviderMutation, getGitProviderOptions, - listConnectionsOptions, + getProviderConnectionsOptions, + getProviderConnectionsQueryKey, listConnectionsQueryKey, syncRepositoriesMutation, } from '@/api/client/@tanstack/react-query.gen' @@ -89,26 +90,38 @@ export default function GitProviderDetail() { isLoading: connectionsLoading, refetch: refetchConnections, } = useQuery({ - ...listConnectionsOptions({}), + // Provider-scoped endpoint, not the caller's own connection list: the + // per-user list hides connections owned by someone else (or by nobody), + // and those are exactly the ones that block deleting the provider. Showing + // "No connections found" next to "cannot delete, it has 1 connection" left + // the user with nothing to act on. + ...getProviderConnectionsOptions({ path: { provider_id: providerId } }), retry: false, enabled: !!provider, - select: (data) => - data?.connections?.filter( - (connection) => connection.provider_id === providerId - ) || [], + select: (data) => data || [], // Poll every 2s while any connection under this provider is syncing so // the running repo count + "Syncing" badge advance live. Polling stops // automatically once no connection reports `syncing=true`, keeping idle // tabs quiet. refetchInterval: (query) => { - const anySyncing = query.state.data?.connections?.some( - (c) => c.provider_id === providerId && c.syncing, - ) + const anySyncing = query.state.data?.some((c) => c.syncing) return anySyncing ? 2000 : false }, refetchIntervalInBackground: false, }) + // Connection state shows up in two places: this provider-scoped list and the + // per-user list the dashboard renders. Refresh both together so neither goes + // stale after a sync or a delete. + const invalidateConnectionQueries = () => { + queryClient.invalidateQueries({ + queryKey: getProviderConnectionsQueryKey({ + path: { provider_id: providerId }, + }), + }) + queryClient.invalidateQueries({ queryKey: listConnectionsQueryKey({}) }) + } + const syncMutation = useMutation({ ...syncRepositoriesMutation(), meta: { @@ -119,7 +132,7 @@ export default function GitProviderDetail() { // already in its syncing state. Without this the user saw nothing change // until the full sync finished (potentially minutes on 20k-repo orgs). onMutate: () => { - queryClient.invalidateQueries({ queryKey: listConnectionsQueryKey({}) }) + invalidateConnectionQueries() }, onSuccess: () => { // 202 = sync started, not finished. The background task updates @@ -127,12 +140,12 @@ export default function GitProviderDetail() { // progresses; the periodic refetch on this page surfaces that. showSuccess('Repository sync started') refetchConnections() - queryClient.invalidateQueries({ queryKey: listConnectionsQueryKey({}) }) + invalidateConnectionQueries() }, onError: (error: any) => { // The backend's drop-guard resets `syncing=false` on failure too, so // refresh the list to clear any stale "syncing" spinner. - queryClient.invalidateQueries({ queryKey: listConnectionsQueryKey({}) }) + invalidateConnectionQueries() // Surface the failure. RFC 7807 Problem Details puts the human // message in `detail`; fall back to `title` then `message`. @@ -147,7 +160,7 @@ export default function GitProviderDetail() { // Failures surface via the global mutation error handler in App.tsx, // which renders Problem Details as a toast: errorTitle becomes the // toast title and the API's `detail` becomes the description (e.g. - // "Cannot delete provider X because it has N connection(s)"). + // "Cannot delete provider X because it is used by N project(s): ..."). meta: { errorTitle: 'Failed to delete provider' }, onSuccess: () => { toast.success('Git provider deleted successfully') @@ -566,8 +579,10 @@ export default function GitProviderDetail() { Delete Git Provider Are you sure you want to delete "{provider.name}"? This - action cannot be undone. Providers with existing connections - cannot be deleted — remove connections first. + action cannot be undone. Its {connections?.length ?? 0}{' '} + connection(s) and their synced repositories are deleted with it. + Projects still deployed from this provider block the delete — the + error names them. diff --git a/web/src/pages/Login.tsx b/web/src/pages/Login.tsx index a176d76ae..9a89c187a 100644 --- a/web/src/pages/Login.tsx +++ b/web/src/pages/Login.tsx @@ -21,25 +21,35 @@ import { consumeReturnTo } from '@/lib/return-to' * through to a generic message. */ const OIDC_ERROR_MESSAGES: Record = { - idp_error: 'Your identity provider rejected the login. Check that your account is allowed.', - idp_unreachable: "We couldn't reach your identity provider. Try again in a moment.", - idp_rejected_code: 'Your identity provider rejected the authorization code. Try signing in again.', - state_invalid: 'This SSO link is invalid or has already been used. Start sign-in again.', + idp_error: + 'Your identity provider rejected the login. Check that your account is allowed.', + idp_unreachable: + "We couldn't reach your identity provider. Try again in a moment.", + idp_rejected_code: + 'Your identity provider rejected the authorization code. Try signing in again.', + state_invalid: + 'This SSO link is invalid or has already been used. Start sign-in again.', state_expired: 'This SSO link expired. Start sign-in again.', - id_token_invalid: 'Your identity provider returned an invalid token. Contact your administrator.', + id_token_invalid: + 'Your identity provider returned an invalid token. Contact your administrator.', callback_invalid: 'The SSO callback was malformed. Start sign-in again.', - email_missing: 'Your identity provider did not return an email address. Grant the "email" scope and try again.', - email_not_verified: 'Your identity provider has not confirmed your email. Verify it at the IdP, then try again.', - user_not_provisioned: 'No Temps account exists for this email. Ask an administrator to create one.', + email_missing: + 'Your identity provider did not return an email address. Grant the "email" scope and try again.', + email_not_verified: + 'Your identity provider has not confirmed your email. Verify it at the IdP, then try again.', + user_not_provisioned: + 'No Temps account exists for this email. Ask an administrator to create one.', provider_disabled: 'This SSO provider is currently disabled.', provider_not_found: 'The SSO provider configuration was not found.', - no_provider_configured: 'No SSO provider is configured on this Temps instance.', + no_provider_configured: + 'No SSO provider is configured on this Temps instance.', issuer_invalid: 'The SSO provider URL is invalid.', return_to_invalid: 'Invalid post-login redirect target.', role_invalid: 'The role assigned by the SSO provider is invalid.', role_mapping_not_found: 'No matching SSO role mapping.', provider_conflict: 'SSO provider configuration conflict.', - internal_error: 'An internal error occurred while processing the SSO callback.', + internal_error: + 'An internal error occurred while processing the SSO callback.', } function oidcErrorMessage(reason: string | null): string { @@ -76,12 +86,26 @@ export const Login = () => { errorTitle: 'Login failed', }, onSuccess: async (data) => { + if (data.password_change_required) { + navigate('/auth/change-password', { replace: true }) + return + } + if (data.mfa_required) { toast.success('Please complete MFA verification') navigate('/mfa-verify') return } + if (data.mfa_enrollment_required && data.mfa_setup) { + toast.success('Set up multi-factor authentication to continue') + navigate('/auth/change-password', { + replace: true, + state: { mfaSetup: data.mfa_setup }, + }) + return + } + toast.success('Logged in successfully') await queryClient.invalidateQueries({ queryKey: ['getCurrentUser'] }) await refetch() @@ -134,7 +158,9 @@ export const Login = () => { onSubmit={handleSubmit} isLoading={isLoading || login.isPending} oidcProviders={emailStatus?.oidc_providers ?? []} - passwordResetAvailable={emailStatus?.password_reset_available ?? false} + passwordResetAvailable={ + emailStatus?.password_reset_available ?? false + } /> diff --git a/web/src/pages/ProjectDetail.tsx b/web/src/pages/ProjectDetail.tsx index 53640afe4..98f6c4caa 100644 --- a/web/src/pages/ProjectDetail.tsx +++ b/web/src/pages/ProjectDetail.tsx @@ -49,6 +49,7 @@ import Traces from './Traces' import LogsList from './LogsList' import Metrics from './Metrics' import { ProjectTour } from '@/components/project/ProjectTour' +import { ProjectSetup } from './ProjectSetup' import { ProjectAgentActivity } from './AiGateway' import { AutofixerPage } from '@/components/autofixer/AutofixerPage' import { AutofixRedirect } from '@/components/autofixer/AutofixRedirect' @@ -347,6 +348,7 @@ export function ProjectDetail() { /> } /> + } /> } diff --git a/web/src/pages/ProjectDrop.tsx b/web/src/pages/ProjectDrop.tsx index 487412f7c..18a5cc8a5 100644 --- a/web/src/pages/ProjectDrop.tsx +++ b/web/src/pages/ProjectDrop.tsx @@ -3,11 +3,14 @@ import { deployFromUploadedSource, getEnvironments, inspectDropArchive, + uploadStaticBundle, updateProjectSettings, type DropInspectionResponse, type EnvironmentResponse, type ProjectResponse, } from '@/api/client' +import { DetectedPresetCard } from '@/components/drop/DetectedPresetCard' +import { DetectedPresetGrid } from '@/components/drop/DetectedPresetGrid' import { DropZone } from '@/components/drop/DropZone' import { Button } from '@/components/ui/button' import { Label } from '@/components/ui/label' @@ -20,21 +23,26 @@ import { } from '@/components/ui/select' import { usePageTitle } from '@/hooks/usePageTitle' import { - formatDetectedProjectLabel, htmlRootCandidates, isDropArchive, - prepareDrop, type DropFile, } from '@/lib/drop-archive' import { dropErrorMessage } from '@/lib/drop-files' +import { prepareAndInspectDrop } from '@/lib/drop-preset-detection' import { cn } from '@/lib/utils' -import { Loader2, UploadCloud } from 'lucide-react' -import { useEffect, useMemo, useState } from 'react' +import { AnimatePresence, motion, useReducedMotion } from 'framer-motion' +import { Loader2, UploadCloud, X } from 'lucide-react' +import { useEffect, useMemo, useRef, useState } from 'react' import { useNavigate } from 'react-router' -type Stage = 'idle' | 'packing' | 'detecting' | 'saving' | 'uploading' | 'deploying' +type Stage = + 'idle' | 'packing' | 'detecting' | 'saving' | 'uploading' | 'deploying' -function stageLabel(stage: Stage, detected: boolean): string { +function stageLabel( + stage: Stage, + detectedLabel?: string, + hasFiles = false +): string { switch (stage) { case 'packing': return 'Packing files locally' @@ -47,7 +55,8 @@ function stageLabel(stage: Stage, detected: boolean): string { case 'deploying': return 'Starting deployment' default: - return detected ? 'Deploy' : 'Detect preset' + if (detectedLabel) return `Deploy ${detectedLabel}` + return hasFiles ? 'Retry preset detection' : 'Select project files' } } @@ -70,6 +79,7 @@ function stageLabel(stage: Stage, detected: boolean): string { */ export function ProjectDrop({ project }: { project: ProjectResponse }) { const navigate = useNavigate() + const reduceMotion = useReducedMotion() const [files, setFiles] = useState([]) const [rootPage, setRootPage] = useState('') const [stage, setStage] = useState('idle') @@ -81,6 +91,8 @@ export function ProjectDrop({ project }: { project: ProjectResponse }) { const [candidateIndex, setCandidateIndex] = useState('0') const [environments, setEnvironments] = useState([]) const [environmentId, setEnvironmentId] = useState('') + const detectionRunRef = useRef(0) + const detectionAbortRef = useRef(null) usePageTitle(`Upload source · ${project.name}`) @@ -89,6 +101,9 @@ export function ProjectDrop({ project }: { project: ProjectResponse }) { const hasRootIndex = htmlPages.some((p) => p.toLowerCase() === 'index.html') const isArchive = files.length === 1 && isDropArchive(files[0].file.name) const candidate = inspection?.candidates[Number(candidateIndex)] + const transition = reduceMotion + ? { duration: 0 } + : { duration: 0.32, ease: [0.22, 1, 0.36, 1] as const } // Environments are needed before the first deploy; production is the sane // default so the common case is zero clicks. @@ -113,19 +128,71 @@ export function ProjectDrop({ project }: { project: ProjectResponse }) { } }, [project.id]) - // Once detection returns, prefer the candidate matching the project's current - // build directory — a repeat upload of the same app should not silently - // switch which directory gets built. - useEffect(() => { - if (!inspection) return - const current = (project.directory || '.').replace(/^\.\/+/, '') || '.' - const match = inspection.candidates.findIndex( - (c) => (c.directory || '.') === current - ) - setCandidateIndex(String(match >= 0 ? match : 0)) - }, [inspection, project.directory]) + useEffect( + () => () => { + detectionAbortRef.current?.abort() + }, + [] + ) + + const inspectArchive = async (archive: File, signal?: AbortSignal) => { + const response = await inspectDropArchive({ + throwOnError: true, + body: { file: archive }, + signal, + }) + return response.data + } + + async function detectSelection( + nextFiles: DropFile[], + nextRootPage: string, + runId: number + ) { + detectionAbortRef.current?.abort() + const controller = new AbortController() + detectionAbortRef.current = controller + try { + setStage('packing') + const result = await prepareAndInspectDrop( + nextFiles, + nextRootPage || undefined, + (archive) => inspectArchive(archive, controller.signal), + { + signal: controller.signal, + onArchivePrepared: (archive) => { + if (detectionRunRef.current !== runId) return + setPreparedArchive(archive) + setStage('detecting') + }, + } + ) + if (detectionRunRef.current !== runId) return + setPreparedArchive(result.archive) + setInspection(result.inspection) + const current = (project.directory || '.').replace(/^\.\/+/, '') || '.' + const match = result.inspection.candidates.findIndex( + (candidate) => (candidate.directory || '.') === current + ) + setCandidateIndex(String(match >= 0 ? match : 0)) + setStage('idle') + } catch (caught) { + if (detectionRunRef.current !== runId) return + setError(dropErrorMessage(caught)) + setPreparedArchive(null) + setInspection(null) + setStage('idle') + } finally { + if (detectionAbortRef.current === controller) { + detectionAbortRef.current = null + } + } + } const select = (next: DropFile[]) => { + const runId = ++detectionRunRef.current + detectionAbortRef.current?.abort() + detectionAbortRef.current = null setFiles(next) setError(null) setPreparedArchive(null) @@ -134,37 +201,33 @@ export function ProjectDrop({ project }: { project: ProjectResponse }) { setStage('idle') const candidates = htmlRootCandidates(next) const hasIndex = candidates.some((p) => p.toLowerCase() === 'index.html') - setRootPage(hasIndex ? '' : candidates[0] || '') + const nextRootPage = hasIndex ? '' : candidates[0] || '' + setRootPage(nextRootPage) + if (next.length > 0) { + void detectSelection(next, nextRootPage, runId) + } } const run = async () => { if (files.length === 0 || isBusy || !environmentId) return setError(null) try { - // First press packs + detects and stops, so the user can confirm the - // detected directory before anything is written. if (!preparedArchive || !inspection) { - setStage('packing') - const prepared = await prepareDrop(files, rootPage || undefined) - setPreparedArchive(prepared.file) - - setStage('detecting') - const response = await inspectDropArchive({ - throwOnError: true, - body: { file: prepared.file }, - }) - if (!response.data) throw new Error('Preset detection returned no result') - setInspection(response.data) - setStage('idle') + const runId = ++detectionRunRef.current + await detectSelection(files, rootPage, runId) return } if (!candidate) throw new Error('Choose a detected project') // Only persist directory/preset, and only when they actually changed. - const currentDirectory = (project.directory || '.').replace(/^\.\/+/, '') || '.' + const currentDirectory = + (project.directory || '.').replace(/^\.\/+/, '') || '.' const nextDirectory = candidate.directory || '.' - if (nextDirectory !== currentDirectory || candidate.preset !== project.preset) { + if ( + nextDirectory !== currentDirectory || + candidate.preset !== project.preset + ) { setStage('saving') await updateProjectSettings({ throwOnError: true, @@ -177,21 +240,13 @@ export function ProjectDrop({ project }: { project: ProjectResponse }) { if (candidate.isStatic) { setStage('uploading') - const body = new FormData() - body.append('file', preparedArchive) - const uploadResponse = await fetch( - `/api/projects/${project.id}/upload/static`, - { method: 'POST', credentials: 'include', body } - ) - if (!uploadResponse.ok) { - const problem = (await uploadResponse.json().catch(() => null)) as { - detail?: string - } | null - throw new Error( - problem?.detail || `Upload failed (${uploadResponse.status})` - ) - } - const bundle = (await uploadResponse.json()) as { id: number } + const uploadResponse = await uploadStaticBundle({ + throwOnError: true, + path: { project_id: project.id }, + body: { file: preparedArchive }, + }) + const bundle = uploadResponse.data + if (!bundle) throw new Error('Static upload returned no bundle') setStage('deploying') await deployFromStatic({ @@ -236,144 +291,179 @@ export function ProjectDrop({ project }: { project: ProjectResponse }) {

    -
    - - - + + + )} +
    ) diff --git a/web/src/pages/ProjectSetup.tsx b/web/src/pages/ProjectSetup.tsx new file mode 100644 index 000000000..4a24fc184 --- /dev/null +++ b/web/src/pages/ProjectSetup.tsx @@ -0,0 +1,226 @@ +import type { ProjectResponse } from '@/api/client' +import { ErrorAlert } from '@/components/utils/ErrorAlert' +import { Button } from '@/components/ui/button' +import { Card, CardContent } from '@/components/ui/card' +import { Skeleton } from '@/components/ui/skeleton' +import { useProjectSetup } from '@/hooks/useProjectSetup' +import { usePageTitle } from '@/hooks/usePageTitle' +import { cn } from '@/lib/utils' +import { + ArrowRight, + BadgeCheck, + Check, + CheckCircle2, + Sparkles, +} from 'lucide-react' +import { Link } from 'react-router' + +export function ProjectSetup({ project }: { project: ProjectResponse }) { + const setup = useProjectSetup(project) + usePageTitle(`${project.name} setup`) + + if (setup.isLoading) { + return + } + + if (setup.isError) { + return ( +
    + setup.refetch()} + /> +
    + ) + } + + return ( +
    +
    +
    +
    + + Production readiness +
    +

    + Project setup +

    +

    + Connect the pieces that make {project.name} observable, reachable, + and ready to operate in production. +

    +
    +
    + + {setup.completedCount} + + + / {setup.totalCount} complete + +
    +
    + + + +
    +
    + {setup.allDone ? ( +
    +
    + +
    +
    +

    + Setup complete +

    +

    + This project is production-ready +

    +

    + Every recommended project integration is connected and + reporting. +

    +
    +
    + ) : ( +
    +
    + +
    +
    +

    + Recommended next step +

    +

    + {setup.nextStep?.title} +

    +

    + {setup.nextStep?.description} +

    +
    +
    + )} + + {setup.nextStep && ( + + )} +
    + +
    +
    +
    +
    + + {setup.percent}% + +
    +
    + + + +
    +
    +

    All project setup items

    +

    + Completed items remain available so you can revisit their + configuration at any time. +

    +
    + +
    + {setup.steps.map((step, index) => { + const Icon = step.icon + return ( + +
    +
    + {step.done ? ( + + ) : ( + + )} +
    + + {String(index + 1).padStart(2, '0')} + +
    + +
    +
    +

    {step.title}

    + {step.done && ( + + Complete + + )} +
    +

    + {step.description} +

    +
    + + + {step.done ? 'Review configuration' : step.cta} + + + + ) + })} +
    +
    +
    + ) +} + +function ProjectSetupSkeleton() { + return ( +
    +
    + + + +
    + +
    + {Array.from({ length: 6 }).map((_, index) => ( + + ))} +
    +
    + ) +} diff --git a/web/src/pages/RequiredPasswordChange.tsx b/web/src/pages/RequiredPasswordChange.tsx new file mode 100644 index 000000000..c0d3ff6ff --- /dev/null +++ b/web/src/pages/RequiredPasswordChange.tsx @@ -0,0 +1,300 @@ +import { + changeRequiredPasswordMutation, + verifyMfaChallengeMutation, +} from '@/api/client/@tanstack/react-query.gen' +import type { MfaSetupResponse } from '@/api/client' +import { Button } from '@/components/ui/button' +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from '@/components/ui/card' +import { + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, +} from '@/components/ui/form' +import { Input } from '@/components/ui/input' +import { usePageTitle } from '@/hooks/usePageTitle' +import { + PASSWORD_REQUIREMENTS, + passwordRequirementResults, + passwordSchema, +} from '@/lib/password-policy' +import { zodResolver } from '@hookform/resolvers/zod' +import { useMutation } from '@tanstack/react-query' +import { Check, Circle, Loader2 } from 'lucide-react' +import { useState } from 'react' +import { useForm } from 'react-hook-form' +import { useLocation, useNavigate } from 'react-router' +import { toast } from 'sonner' +import { z } from 'zod' + +const requiredPasswordChangeSchema = z + .object({ + newPassword: passwordSchema, + confirmPassword: z.string(), + }) + .refine((data) => data.newPassword === data.confirmPassword, { + message: 'Passwords do not match', + path: ['confirmPassword'], + }) + +type RequiredPasswordChangeFormData = z.infer< + typeof requiredPasswordChangeSchema +> + +const mfaCodeSchema = z.object({ + code: z.string().regex(/^\d{6}$/, 'Enter the 6-digit code'), +}) + +type MfaCodeFormData = z.infer + +export function RequiredPasswordChange() { + usePageTitle('Choose a new password') + const navigate = useNavigate() + const location = useLocation() + const resumedSetup = ( + location.state as { mfaSetup?: MfaSetupResponse } | null + )?.mfaSetup + const [mfaSetup, setMfaSetup] = useState( + resumedSetup ?? null + ) + const form = useForm({ + resolver: zodResolver(requiredPasswordChangeSchema), + defaultValues: { newPassword: '', confirmPassword: '' }, + }) + const newPassword = form.watch('newPassword') + const requirementResults = passwordRequirementResults(newPassword) + const mfaForm = useForm({ + resolver: zodResolver(mfaCodeSchema), + defaultValues: { code: '' }, + }) + + const changePassword = useMutation({ + ...changeRequiredPasswordMutation(), + meta: { errorTitle: 'Password change failed' }, + onSuccess: (data) => { + if (data.mfa_enrollment_required && data.mfa_setup) { + setMfaSetup(data.mfa_setup) + toast.success('Password changed. Set up MFA to continue.') + return + } + toast.success('Password changed. Log in with your new password.') + navigate('/', { replace: true }) + }, + }) + + const verifyMfa = useMutation({ + ...verifyMfaChallengeMutation(), + meta: { errorTitle: 'MFA verification failed' }, + onSuccess: () => { + toast.success('MFA enabled successfully') + navigate('/dashboard', { replace: true }) + }, + }) + + const handleSubmit = async (data: RequiredPasswordChangeFormData) => { + await changePassword.mutateAsync({ + body: { new_password: data.newPassword }, + }) + } + + if (mfaSetup) { + return ( +
    + + + Secure your administrator account + + Scan this code with an authenticator app, save the recovery codes, + then enter the current 6-digit code. + + + +
    + QR code for multi-factor authentication +
    +
    +
    Manual setup key
    + + {mfaSetup.secret_key} + +
    + {mfaSetup.recovery_codes.length > 0 ? ( +
    +
    Recovery codes
    +

    + Store these somewhere safe. Each code can be used once. +

    +
    + {mfaSetup.recovery_codes.map((code) => ( + {code} + ))} +
    +
    + ) : ( +

    + Recovery codes could not be prepared. Log in again to restart + MFA setup before enabling it. +

    + )} +
    + + verifyMfa.mutate({ body: data }) + )} + className="space-y-4" + > + ( + + Verification code + + + + + + )} + /> + + + +
    +
    +
    + ) + } + + return ( +
    +
    +
    + Temps logo +
    Temps
    +
    + + + + + Choose a new password + + + Your administrator requires you to replace the temporary password + before accessing Temps. + + + +
    + + ( + + New password + + + + + Meet every requirement below. + + +
      + {PASSWORD_REQUIREMENTS.map((requirement, index) => { + const met = requirementResults[index]?.met ?? false + return ( +
    • + {met ? ( + + ) : ( + + )} +
      {requirement.label}
      +
    • + ) + })} +
    +
    + )} + /> + ( + + Confirm new password + + + + + + )} + /> + + + +
    +
    +
    +
    + ) +} diff --git a/web/src/pages/ResetPassword.tsx b/web/src/pages/ResetPassword.tsx index 3260d8ef8..39893fb81 100644 --- a/web/src/pages/ResetPassword.tsx +++ b/web/src/pages/ResetPassword.tsx @@ -25,24 +25,11 @@ import { Link, useNavigate, useSearchParams } from 'react-router' import { toast } from 'sonner' import { z } from 'zod' import { usePageTitle } from '@/hooks/usePageTitle' +import { passwordSchema } from '@/lib/password-policy' -// Mirrors `validate_password_complexity` in -// temps-auth/src/auth_service.rs. Kept in sync so the user gets inline -// feedback instead of a round-trip 400. The server remains the source -// of truth and re-validates. const resetPasswordSchema = z .object({ - newPassword: z - .string() - .min(8, 'Password must be at least 8 characters long') - .max(128, 'Password must not exceed 128 characters') - .regex(/[A-Z]/, 'Password must contain at least one uppercase letter') - .regex(/[a-z]/, 'Password must contain at least one lowercase letter') - .regex(/[0-9]/, 'Password must contain at least one digit') - .regex( - /[^a-zA-Z0-9]/, - 'Password must contain at least one special character', - ), + newPassword: passwordSchema, confirmPassword: z.string(), }) .refine((data) => data.newPassword === data.confirmPassword, { diff --git a/web/src/pages/Users.tsx b/web/src/pages/Users.tsx index eb9ceaf1e..6a33735f9 100644 --- a/web/src/pages/Users.tsx +++ b/web/src/pages/Users.tsx @@ -6,6 +6,7 @@ import { useKeyboardShortcut } from '@/hooks/useKeyboardShortcut' import { usePageTitle } from '@/hooks/usePageTitle' import { useEffect, useState } from 'react' import { UserEditDialog } from '@/components/users/UserEditDialog' +import { useNavigate } from 'react-router' export function Users() { const { setBreadcrumbs } = useBreadcrumbs() @@ -14,7 +15,7 @@ export function Users() { name: string email: string } | null>(null) - const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false) + const navigate = useNavigate() const { data: users, @@ -34,7 +35,7 @@ export function Users() { useKeyboardShortcut({ key: 'n', - callback: () => setIsCreateDialogOpen(true), + callback: () => navigate('/settings/users/new'), }) usePageTitle('Users') @@ -47,8 +48,6 @@ export function Users() { isLoading={isLoading} reloadUsers={refetch} onEditUser={setSelectedUser} - isCreateDialogOpen={isCreateDialogOpen} - onCreateDialogOpenChange={setIsCreateDialogOpen} />
    {selectedUser && ( From ae616e684093cd0a1db69784ba18c7464a4309b3 Mon Sep 17 00:00:00 2001 From: David Viejo Date: Wed, 5 Aug 2026 14:08:40 +0200 Subject: [PATCH 4/9] feat(console): find Temps Cloud from the command palette MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sidebar entry existed but the palette did not, so ⌘K -- the way most people navigate the console -- could not reach managed cloud at all. Keywords cover what someone actually types when they are shopping for it (retention, backup, managed) rather than only the product name, and the e2e spec asserts both routes to it. --- web/e2e/anonymous/command-palette.spec.ts | 17 ++++++++++++++++ web/src/components/command/CommandPalette.tsx | 20 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/web/e2e/anonymous/command-palette.spec.ts b/web/e2e/anonymous/command-palette.spec.ts index e7859a877..332e7fe4a 100644 --- a/web/e2e/anonymous/command-palette.spec.ts +++ b/web/e2e/anonymous/command-palette.spec.ts @@ -94,4 +94,21 @@ test.describe('command palette', () => { }) await expect(navigation.locator(':scope > svg')).toHaveCount(1) }) + + test('finds Temps Cloud by name and by what it does', async ({ page }) => { + const search = page.getByPlaceholder('Type a command or search...') + const entry = page + .locator('[cmdk-item]') + .filter({ hasText: 'Temps Cloud' }) + + await search.fill('temps cloud') + await expect(entry).toBeVisible() + + // Someone hunting for managed retention will not type "temps cloud". + await search.fill('retention') + await expect(entry).toBeVisible() + + await entry.first().click() + await expect(page).toHaveURL(/\/settings\/cloud$/) + }) }) diff --git a/web/src/components/command/CommandPalette.tsx b/web/src/components/command/CommandPalette.tsx index f547b8d42..206fe611d 100644 --- a/web/src/components/command/CommandPalette.tsx +++ b/web/src/components/command/CommandPalette.tsx @@ -405,6 +405,26 @@ const settingsNavItems: NavigationItem[] = [ icon: HardDrive, keywords: ['disk', 'space', 'storage', 'alerts', 'monitoring'], }, + { + title: 'Temps Cloud', + url: '/settings/cloud', + icon: Cloud, + // "connect"/"link"/"enroll" are what the docs and the CLI call this, and + // "backup"/"retention" are what someone is actually shopping for when they + // go looking for it. + keywords: [ + 'cloud', + 'temps cloud', + 'managed', + 'connect', + 'link', + 'enroll', + 'telemetry', + 'retention', + 'backup', + 'subscription', + ], + }, { title: 'Metrics Monitoring', url: '/settings/metrics-monitoring', From fbec55d83240ad74ddddc77f21ca633ffa4866ee Mon Sep 17 00:00:00 2001 From: David Viejo Date: Thu, 6 Aug 2026 11:28:17 +0200 Subject: [PATCH 5/9] feat(cloud): integrate managed alert routing --- Cargo.lock | 3 + crates/temps-cloud-client/src/lib.rs | 99 +++++++++- crates/temps-cloud-client/src/link.rs | 51 +++++- crates/temps-cloud-client/src/state.rs | 33 ++++ crates/temps-cloud-protocol/src/lib.rs | 8 +- crates/temps-cloud-protocol/src/messages.rs | 170 ++++++++++++++++++ crates/temps-cloud/Cargo.toml | 1 + crates/temps-cloud/src/service.rs | 13 ++ crates/temps-notifications/Cargo.toml | 2 + crates/temps-notifications/src/handlers.rs | 2 +- crates/temps-notifications/src/plugin.rs | 4 +- crates/temps-notifications/src/services.rs | 131 +++++++++++++- .../temps-otel/src/services/otel_service.rs | 1 + .../authenticated/cloud-onboarding.spec.ts | 11 +- web/src/api/client/types.gen.ts | 1 + web/src/pages/settings/CloudSettingsPage.tsx | 5 + 16 files changed, 524 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 897e2d649..f99106250 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10707,6 +10707,7 @@ dependencies = [ "tempfile", "temps-auth", "temps-cloud-client", + "temps-cloud-protocol", "temps-config", "temps-core", "thiserror 2.0.19", @@ -11968,6 +11969,8 @@ dependencies = [ "serde", "serde_json", "temps-auth", + "temps-cloud", + "temps-cloud-protocol", "temps-core", "temps-database", "temps-entities", diff --git a/crates/temps-cloud-client/src/lib.rs b/crates/temps-cloud-client/src/lib.rs index c2e651353..c7f87dd5b 100644 --- a/crates/temps-cloud-client/src/lib.rs +++ b/crates/temps-cloud-client/src/lib.rs @@ -32,7 +32,11 @@ pub use status::{LinkStatus, MirrorHealth}; use std::time::Duration; -use temps_cloud_protocol::{EnrollRequest, EnrollResponse, IngestAck, SpanRecord, TelemetryBatch}; +use temps_cloud_protocol::{ + EnrollRequest, EnrollResponse, IngestAck, ManagedAiAnalysisRequest, ManagedAiAnalysisResponse, + ManagedAiCapability, ManagedNotificationAccepted, ManagedNotificationRequest, SpanRecord, + TelemetryBatch, +}; use thiserror::Error; use uuid::Uuid; @@ -116,6 +120,7 @@ impl BackendUrl { /// Deliberately short. This runs alongside the instance's own work, and a slow /// backend must never become the instance's latency. const REQUEST_TIMEOUT: Duration = Duration::from_secs(10); +const AI_REQUEST_TIMEOUT: Duration = Duration::from_secs(60); #[derive(Debug, Error)] pub enum CloudError { @@ -254,6 +259,68 @@ impl CloudClient { } } + /// Describe managed inference without reading or uploading local context. + pub async fn managed_ai_capability( + &self, + token: &str, + ) -> Result { + let response = self + .http + .get(self.backend.endpoint("/v1/ai/capability")) + .bearer_auth(token) + .send() + .await + .map_err(|error| CloudError::Unreachable { + reason: error.to_string(), + spooled_bytes: 0, + })?; + decode_managed_response(response).await + } + + /// Submit the exact manifest the operator approved in the OSS AI surface. + /// Source telemetry is never fetched by Cloud and BYO credentials never use + /// this path; local BYO continues through the OSS AI gateway directly. + pub async fn managed_ai_analysis( + &self, + token: &str, + request: &ManagedAiAnalysisRequest, + ) -> Result { + let response = self + .http + .post(self.backend.endpoint("/v1/ai/analyses")) + .bearer_auth(token) + .timeout(AI_REQUEST_TIMEOUT) + .json(request) + .send() + .await + .map_err(|error| CloudError::Unreachable { + reason: error.to_string(), + spooled_bytes: 0, + })?; + decode_managed_response(response).await + } + + /// Queue one OSS alert for Cloud-owned fan-out. A retry with the same + /// source id is idempotent at the backend. + pub async fn send_notification( + &self, + token: &str, + request: &ManagedNotificationRequest, + ) -> Result { + let response = self + .http + .post(self.backend.endpoint("/v1/notifications")) + .bearer_auth(token) + .json(request) + .send() + .await + .map_err(|error| CloudError::Unreachable { + reason: error.to_string(), + spooled_bytes: 0, + })?; + decode_managed_response(response).await + } + /// Mirror a batch of spans. Never called on a request path. pub async fn ship( &self, @@ -321,6 +388,36 @@ impl CloudClient { } } +async fn decode_managed_response( + response: reqwest::Response, +) -> Result { + let status = response.status(); + if status.is_success() { + return response + .json::() + .await + .map_err(|error| CloudError::Rejected { + detail: format!("managed backend returned an unreadable response: {error}"), + }); + } + if matches!(status.as_u16(), 401 | 403) { + return Err(CloudError::CredentialRejected); + } + if matches!(status.as_u16(), 429 | 500..=599) { + return Err(CloudError::Unreachable { + reason: format!("managed backend returned {status}"), + spooled_bytes: 0, + }); + } + let detail = response + .json::() + .await + .ok() + .and_then(|value| value["detail"].as_str().map(str::to_string)) + .unwrap_or_else(|| format!("managed backend returned {status}")); + Err(CloudError::Rejected { detail }) +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/temps-cloud-client/src/link.rs b/crates/temps-cloud-client/src/link.rs index 150099641..994be9c50 100644 --- a/crates/temps-cloud-client/src/link.rs +++ b/crates/temps-cloud-client/src/link.rs @@ -19,7 +19,10 @@ use std::sync::atomic::{AtomicBool, AtomicU64, AtomicUsize, Ordering}; use std::sync::{Mutex, RwLock}; use tokio::sync::mpsc; -use temps_cloud_protocol::SpanRecord; +use temps_cloud_protocol::{ + ManagedAiAnalysisRequest, ManagedAiAnalysisResponse, ManagedAiCapability, + ManagedNotificationAccepted, ManagedNotificationRequest, SpanRecord, +}; use uuid::Uuid; use crate::spool::Spool; @@ -195,6 +198,14 @@ impl CloudLink { .map(|s| s.instance_id) } + pub fn account_email(&self) -> Option { + self.state + .read() + .unwrap_or_else(|p| p.into_inner()) + .as_ref() + .and_then(|state| state.account_email.clone()) + } + /// Lock-free fast-path hint for telemetry producers. Enrollment can race /// with an offer; generation tagging prevents a raced batch crossing links. pub fn is_linked(&self) -> bool { @@ -286,6 +297,7 @@ impl CloudLink { let mut next = current.clone(); next.token = Some(res.instance_token); next.tenant_id = Some(res.tenant_id); + next.account_email = res.account_email; // Clone → save → swap: a failed disk write cannot leave a credential // alive only in memory. next.save(&self.state_path) @@ -316,6 +328,43 @@ impl CloudLink { CloudClient::new(backend)?.revoke(&token).await } + pub async fn managed_ai_capability(&self) -> Result { + let (base_url, token) = self.linked_credential()?; + let backend = self.parse_backend(&base_url)?; + CloudClient::new(backend)? + .managed_ai_capability(&token) + .await + } + + pub async fn managed_ai_analysis( + &self, + request: &ManagedAiAnalysisRequest, + ) -> Result { + let (base_url, token) = self.linked_credential()?; + let backend = self.parse_backend(&base_url)?; + CloudClient::new(backend)? + .managed_ai_analysis(&token, request) + .await + } + + pub async fn send_notification( + &self, + request: &ManagedNotificationRequest, + ) -> Result { + let (base_url, token) = self.linked_credential()?; + let backend = self.parse_backend(&base_url)?; + CloudClient::new(backend)? + .send_notification(&token, request) + .await + } + + fn linked_credential(&self) -> Result<(String, String), CloudError> { + let guard = self.state.read().unwrap_or_else(|p| p.into_inner()); + let state = guard.as_ref().ok_or(CloudError::NotEnrolled)?; + let token = state.token.clone().ok_or(CloudError::NotEnrolled)?; + Ok((state.base_url.clone(), token)) + } + /// Forget the credential. Keeps the instance identity so re-linking later /// reattaches to the same record. pub fn disconnect(&self) -> Result<(), crate::state::StateError> { diff --git a/crates/temps-cloud-client/src/state.rs b/crates/temps-cloud-client/src/state.rs index dd2ca1c48..ece63cd68 100644 --- a/crates/temps-cloud-client/src/state.rs +++ b/crates/temps-cloud-client/src/state.rs @@ -41,6 +41,11 @@ pub struct EnrollmentState { pub token: Option, pub tenant_id: Option, + + /// Cloud account shown in the local UI. Older state files legitimately do + /// not contain it and can refresh it by reconnecting. + #[serde(default)] + pub account_email: Option, } impl std::fmt::Debug for EnrollmentState { @@ -50,6 +55,7 @@ impl std::fmt::Debug for EnrollmentState { .field("base_url", &self.base_url) .field("token", &self.token.as_ref().map(|_| "[REDACTED]")) .field("tenant_id", &self.tenant_id) + .field("account_email", &self.account_email) .finish() } } @@ -62,6 +68,7 @@ impl EnrollmentState { base_url: base_url.into(), token: None, tenant_id: None, + account_email: None, } } @@ -172,6 +179,7 @@ impl EnrollmentState { pub fn unlink(&mut self) { self.token = None; self.tenant_id = None; + self.account_email = None; } } @@ -198,6 +206,7 @@ mod tests { let mut s = EnrollmentState::new("https://cloud.test"); s.token = Some("inst_abc".into()); s.tenant_id = Some(Uuid::new_v4()); + s.account_email = Some("owner@example.com".into()); s.save(&p).unwrap(); assert_eq!(EnrollmentState::load(&p).unwrap(), Some(s)); @@ -230,14 +239,38 @@ mod tests { let id = s.instance_id; s.token = Some("inst_abc".into()); s.tenant_id = Some(Uuid::new_v4()); + s.account_email = Some("owner@example.com".into()); s.unlink(); assert!(!s.is_linked()); assert!(s.tenant_id.is_none()); + assert!(s.account_email.is_none()); assert_eq!(s.instance_id, id, "re-linking must reattach, not orphan"); } + #[test] + fn legacy_state_without_an_account_email_still_loads() { + let (_d, p) = temp(); + std::fs::create_dir_all(p.parent().unwrap()).unwrap(); + let instance_id = Uuid::new_v4(); + std::fs::write( + &p, + serde_json::json!({ + "instance_id": instance_id, + "base_url": "https://cloud.test", + "token": "inst_legacy", + "tenant_id": Uuid::new_v4() + }) + .to_string(), + ) + .unwrap(); + + let state = EnrollmentState::load(&p).unwrap().unwrap(); + assert_eq!(state.instance_id, instance_id); + assert!(state.account_email.is_none()); + } + #[test] fn saving_twice_leaves_no_temp_file_behind() { let (_d, p) = temp(); diff --git a/crates/temps-cloud-protocol/src/lib.rs b/crates/temps-cloud-protocol/src/lib.rs index 3d11308f7..b5f5f4fb1 100644 --- a/crates/temps-cloud-protocol/src/lib.rs +++ b/crates/temps-cloud-protocol/src/lib.rs @@ -30,7 +30,10 @@ pub mod messages; pub use messages::{ BackupCompleted, BackupTarget, BackupTargetRequest, EnrollRequest, EnrollResponse, Envelope, - Heartbeat, IngestAck, SpanRecord, TelemetryBatch, + Heartbeat, HeartbeatAck, IngestAck, ManagedAiAnalysisRequest, ManagedAiAnalysisResponse, + ManagedAiCapability, ManagedAiCitation, ManagedAiEvidence, ManagedAiTask, + ManagedNotificationAccepted, ManagedNotificationRequest, ManagedNotificationSeverity, + SpanRecord, TelemetryBatch, }; use serde::{Deserialize, Serialize}; @@ -53,6 +56,9 @@ pub enum Capability { /// Instance accepts managed DNS records and certificate material for a /// subdomain issued by the backend. ManagedSubdomain, + /// Instance may submit an operator-approved, locally redacted manifest for + /// credit-backed managed inference. Source telemetry never moves implicitly. + ManagedAiInference, } /// First frame on every connection, sent by both sides. diff --git a/crates/temps-cloud-protocol/src/messages.rs b/crates/temps-cloud-protocol/src/messages.rs index 3c4dfaec3..57053b87c 100644 --- a/crates/temps-cloud-protocol/src/messages.rs +++ b/crates/temps-cloud-protocol/src/messages.rs @@ -71,6 +71,10 @@ impl std::fmt::Debug for EnrollRequest { #[derive(Clone, Serialize, Deserialize)] pub struct EnrollResponse { pub tenant_id: Uuid, + /// Human-readable Cloud account identity for the local connection UI. + /// Optional for compatibility with older managed backends. + #[serde(default)] + pub account_email: Option, /// Bearer token for the management channel and the ingest endpoint. /// Scoped to this instance and this tenant, nothing else. pub instance_token: String, @@ -88,6 +92,7 @@ impl std::fmt::Debug for EnrollResponse { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("EnrollResponse") .field("tenant_id", &self.tenant_id) + .field("account_email", &self.account_email) .field("instance_token", &"[REDACTED]") .field("capabilities", &self.capabilities) .finish() @@ -161,6 +166,11 @@ pub struct BackupTargetRequest { /// What is being backed up, e.g. a service or database name. pub source: String, pub estimated_bytes: u64, + /// SHA-256 of the finished artifact. New clients compute the backup before + /// requesting a target so object storage can validate the bytes during the + /// direct PUT. Optional only for wire compatibility; Cloud may require it. + #[serde(default)] + pub checksum_sha256: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -170,6 +180,10 @@ pub struct BackupTarget { pub upload_url: String, pub object_key: String, pub expires_at_millis: i64, + /// Headers covered by the presigned request. The uploader must send these + /// exact values; notably the provider-verified content checksum. + #[serde(default)] + pub headers: std::collections::BTreeMap, } /// Instance reports the upload finished. Until this arrives the object is not @@ -183,6 +197,112 @@ pub struct BackupCompleted { pub checksum_sha256: String, } +// --------------------------------------------------------------------------- +// Managed AI — context is assembled and approved on the OSS instance +// --------------------------------------------------------------------------- + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum ManagedAiTask { + Standard, + Deep, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ManagedAiEvidence { + /// Tenant-keyed opaque aliases. Raw application trace/span identifiers do + /// not cross the managed boundary. + pub trace_id: String, + pub span_id: String, + pub occurred_at: chrono::DateTime, + /// One fixed category from the protocol allow-list, never a raw span name. + pub operation: String, + pub duration_ms: f64, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ManagedAiAnalysisRequest { + pub analysis_id: Uuid, + pub question: String, + pub range_start: chrono::DateTime, + pub range_end: chrono::DateTime, + pub context_manifest_sha256: String, + pub task: ManagedAiTask, + pub evidence: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ManagedAiCitation { + pub trace_id: String, + pub span_id: String, + pub reason: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ManagedAiAnalysisResponse { + pub id: Uuid, + pub state: String, + pub task: ManagedAiTask, + pub estimated_credits: u64, + pub settled_credits: u64, + pub provider: String, + pub model: String, + pub rate_card_version: String, + pub input_tokens: Option, + pub output_tokens: Option, + pub answer: Option, + pub grounded: Option, + pub citations: Vec, + pub failure_reason: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ManagedAiCapability { + pub configured: bool, + pub managed_provider: Option, + pub managed_model: Option, + pub destination_origin: Option, + pub inference_region: Option, + pub reason: Option, + pub setup_path: String, +} + +// --------------------------------------------------------------------------- +// Managed notifications — Cloud fans one local provider out to many sinks +// --------------------------------------------------------------------------- + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum ManagedNotificationSeverity { + Debug, + Info, + Warning, + Error, + Critical, + Emergency, +} + +/// A bounded notification produced by OSS and durably accepted by Cloud. +/// +/// The stable source id makes retries safe. Cloud never trusts the timestamp +/// for ordering, billing, or retry decisions; it records server receive time. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ManagedNotificationRequest { + pub source_notification_id: String, + pub title: String, + pub message: String, + pub severity: ManagedNotificationSeverity, + #[serde(default)] + pub metadata: std::collections::BTreeMap, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ManagedNotificationAccepted { + pub event_id: Uuid, + pub queued_deliveries: u32, + pub duplicate: bool, +} + // --------------------------------------------------------------------------- // Liveness // --------------------------------------------------------------------------- @@ -199,6 +319,15 @@ pub struct Heartbeat { pub pending_spool_bytes: u64, } +/// Cloud acknowledgement for a durably recorded heartbeat. +/// +/// The instance may use the Cloud timestamp for skew diagnostics, but never +/// for a local authorization or billing decision. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct HeartbeatAck { + pub received_at_millis: i64, +} + #[cfg(test)] mod tests { use super::*; @@ -215,6 +344,32 @@ mod tests { assert_eq!(back.pending_spool_bytes, 42); } + #[test] + fn managed_notification_round_trips_without_provider_details() { + let request = ManagedNotificationRequest { + source_notification_id: "alert-42".into(), + title: "Database unavailable".into(), + message: "postgres did not answer its health check".into(), + severity: ManagedNotificationSeverity::Critical, + metadata: [("service".into(), "postgres".into())].into(), + }; + let json = serde_json::to_string(&request).unwrap(); + assert!(!json.contains("slack")); + assert!(!json.contains("email")); + let decoded: ManagedNotificationRequest = serde_json::from_str(&json).unwrap(); + assert_eq!(decoded.source_notification_id, "alert-42"); + } + + #[test] + fn heartbeat_ack_is_additive_and_round_trips() { + let ack = HeartbeatAck { + received_at_millis: 1_700_000_000_000, + }; + let env = Envelope::new("heartbeat_ack", &ack).unwrap(); + let decoded: HeartbeatAck = env.decode("heartbeat_ack").unwrap(); + assert_eq!(decoded.received_at_millis, ack.received_at_millis); + } + #[test] fn unknown_kind_decodes_to_none_rather_than_erroring() { // The forward-compatibility guarantee: a v1 peer receiving a v3 frame @@ -259,6 +414,7 @@ mod tests { }; let response = EnrollResponse { tenant_id: Uuid::new_v4(), + account_email: Some("owner@example.com".into()), instance_token: "inst_secret".into(), capabilities: vec![], }; @@ -266,4 +422,18 @@ mod tests { assert!(!format!("{request:?}").contains("secret-code")); assert!(!format!("{response:?}").contains("inst_secret")); } + + #[test] + fn enrollment_response_accepts_backends_without_an_account_email() { + let tenant_id = Uuid::new_v4(); + let response: EnrollResponse = serde_json::from_value(serde_json::json!({ + "tenant_id": tenant_id, + "instance_token": "inst_legacy" + })) + .unwrap(); + + assert_eq!(response.tenant_id, tenant_id); + assert!(response.account_email.is_none()); + assert!(response.capabilities.is_empty()); + } } diff --git a/crates/temps-cloud/Cargo.toml b/crates/temps-cloud/Cargo.toml index 41402cb4f..c05157cea 100644 --- a/crates/temps-cloud/Cargo.toml +++ b/crates/temps-cloud/Cargo.toml @@ -8,6 +8,7 @@ description = "Host integration for the optional Temps managed control plane." [dependencies] temps-auth = { path = "../temps-auth" } temps-cloud-client = { path = "../temps-cloud-client" } +temps-cloud-protocol = { path = "../temps-cloud-protocol" } temps-config = { path = "../temps-config" } temps-core = { path = "../temps-core" } diff --git a/crates/temps-cloud/src/service.rs b/crates/temps-cloud/src/service.rs index 8d3162d6c..d36ab87fc 100644 --- a/crates/temps-cloud/src/service.rs +++ b/crates/temps-cloud/src/service.rs @@ -2,6 +2,7 @@ use std::sync::{Arc, Mutex}; use serde::Serialize; use temps_cloud_client::{BackendUrl, CloudError, CloudLink}; +use temps_cloud_protocol::{ManagedNotificationAccepted, ManagedNotificationRequest}; use temps_config::{ConfigService, ConfigServiceError}; use thiserror::Error; use tokio::sync::watch; @@ -37,6 +38,7 @@ pub struct CloudStatus { pub health_message: String, #[schema(value_type = Option)] pub instance_id: Option, + pub account_email: Option, pub spooled_spans: usize, pub backend_url: String, } @@ -127,6 +129,7 @@ impl CloudService { health: health_name(&health).to_string(), health_message: health.message(), instance_id: self.link.instance_id(), + account_email: self.link.account_email(), spooled_spans: self.link.spooled(), backend_url: settings.cloud.backend_url, }) @@ -157,6 +160,16 @@ impl CloudService { self.status().await } + pub async fn send_notification( + &self, + request: &ManagedNotificationRequest, + ) -> Result { + self.link + .send_notification(request) + .await + .map_err(CloudServiceError::Client) + } + pub async fn shutdown(&self) { let _ = self.cancel.send(true); let task = self diff --git a/crates/temps-notifications/Cargo.toml b/crates/temps-notifications/Cargo.toml index 993f5ec4c..be5946d62 100644 --- a/crates/temps-notifications/Cargo.toml +++ b/crates/temps-notifications/Cargo.toml @@ -12,6 +12,8 @@ temps-auth = { path = "../temps-auth" } temps-core = { path = "../temps-core" } temps-database = { path = "../temps-database" } temps-entities = { path = "../temps-entities" } +temps-cloud = { path = "../temps-cloud" } +temps-cloud-protocol = { path = "../temps-cloud-protocol" } tokio = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } diff --git a/crates/temps-notifications/src/handlers.rs b/crates/temps-notifications/src/handlers.rs index 43a350a8c..75b7e0cd3 100644 --- a/crates/temps-notifications/src/handlers.rs +++ b/crates/temps-notifications/src/handlers.rs @@ -848,7 +848,7 @@ async fn test_notification_provider( } let message = if result { - Some("Test email sent successfully".to_string()) + Some("Test notification sent successfully".to_string()) } else { Some("Test failed - provider connection or configuration issue".to_string()) }; diff --git a/crates/temps-notifications/src/plugin.rs b/crates/temps-notifications/src/plugin.rs index db7fb86b3..b2550bb13 100644 --- a/crates/temps-notifications/src/plugin.rs +++ b/crates/temps-notifications/src/plugin.rs @@ -51,11 +51,13 @@ impl TempsPlugin for NotificationsPlugin { // Get required dependencies from the service registry let db = context.require_service::(); let encryption_service = context.require_service::(); + let cloud_service = context.require_service::(); // Create NotificationService - let notification_service = Arc::new(NotificationService::new( + let notification_service = Arc::new(NotificationService::new_with_cloud( db.clone(), encryption_service.clone(), + cloud_service, )); context.register_service(notification_service.clone()); diff --git a/crates/temps-notifications/src/services.rs b/crates/temps-notifications/src/services.rs index 587306ff7..c7d92dbc2 100644 --- a/crates/temps-notifications/src/services.rs +++ b/crates/temps-notifications/src/services.rs @@ -13,6 +13,8 @@ use sea_orm::{ }; use serde::{Deserialize, Serialize}; use std::sync::Arc; +use temps_cloud::CloudService; +use temps_cloud_protocol::{ManagedNotificationRequest, ManagedNotificationSeverity}; use temps_core::notifications::{ EmailMessage, NotificationData, NotificationError as CoreNotificationError, NotificationService as CoreNotificationService, @@ -505,6 +507,50 @@ pub trait NotificationProvider: Send + Sync { async fn health_check(&self) -> Result; } +/// The only managed provider exposed by OSS. Cloud owns all concrete sinks. +pub struct TempsCloudProvider { + cloud: Arc, +} + +#[async_trait] +impl NotificationProvider for TempsCloudProvider { + async fn initialize(&mut self, _db: Arc) -> Result<()> { + Ok(()) + } + + async fn send(&self, notification: &Notification) -> Result<()> { + let severity = match notification.effective_severity() { + NotificationSeverity::Debug => ManagedNotificationSeverity::Debug, + NotificationSeverity::Info => ManagedNotificationSeverity::Info, + NotificationSeverity::Warning => ManagedNotificationSeverity::Warning, + NotificationSeverity::Error => ManagedNotificationSeverity::Error, + NotificationSeverity::Critical => ManagedNotificationSeverity::Critical, + NotificationSeverity::Emergency => ManagedNotificationSeverity::Emergency, + }; + let metadata = notification + .metadata + .iter() + .filter(|(key, _)| !key.starts_with('_')) + .map(|(key, value)| (key.clone(), value.clone())) + .collect(); + self.cloud + .send_notification(&ManagedNotificationRequest { + source_notification_id: notification.id.clone(), + title: notification.title.clone(), + message: notification.message.clone(), + severity, + metadata, + }) + .await + .map(|_| ()) + .map_err(anyhow::Error::from) + } + + async fn health_check(&self) -> Result { + Ok(self.cloud.status().await?.status == "linked") + } +} + impl EmailProvider { async fn get_admin_users(&self) -> Result> { let db = self.db.as_ref(); @@ -1337,6 +1383,7 @@ impl NotificationProvider for WebhookProvider { pub struct NotificationService { db: Arc, encryption_service: Arc, + cloud: Option>, } impl NotificationService { @@ -1347,9 +1394,63 @@ impl NotificationService { Self { db, encryption_service, + cloud: None, } } + pub fn new_with_cloud( + db: Arc, + encryption_service: Arc, + cloud: Arc, + ) -> Self { + Self { + db, + encryption_service, + cloud: Some(cloud), + } + } + + async fn sync_cloud_provider(&self) -> Result<()> { + let Some(cloud) = &self.cloud else { + return Ok(()); + }; + let linked = cloud + .status() + .await + .map(|status| status.status == "linked")?; + let existing = notification_providers::Entity::find() + .filter(notification_providers::Column::ProviderType.eq("cloud")) + .one(self.db.as_ref()) + .await?; + if let Some(existing) = existing { + if existing.enabled != linked || existing.name != "Temps Cloud" { + let mut active: notification_providers::ActiveModel = existing.into(); + active.name = Set("Temps Cloud".to_string()); + active.enabled = Set(linked); + active.update(self.db.as_ref()).await?; + } + } else if linked { + let encrypted = self + .encryption_service + .encrypt_string("{}") + .map_err(|error| { + anyhow::anyhow!("Failed to encrypt Cloud provider marker: {error}") + })?; + notification_providers::ActiveModel { + name: Set("Temps Cloud".to_string()), + provider_type: Set("cloud".to_string()), + config: Set(encrypted), + enabled: Set(true), + created_at: Set(Utc::now()), + updated_at: Set(Utc::now()), + ..Default::default() + } + .insert(self.db.as_ref()) + .await?; + } + Ok(()) + } + fn get_batch_key(notification: &Notification) -> String { format!( "{}:{}:{}", @@ -1358,6 +1459,9 @@ impl NotificationService { } async fn get_enabled_providers(&self) -> Result>> { + if let Err(error) = self.sync_cloud_provider().await { + error!(%error, "Could not synchronize the optional Temps Cloud provider"); + } let db_providers = notification_providers::Entity::find() .filter(notification_providers::Column::Enabled.eq(true)) .all(self.db.as_ref()) @@ -1559,6 +1663,9 @@ impl NotificationService { } pub async fn is_configured(&self) -> Result { + if let Err(error) = self.sync_cloud_provider().await { + error!(%error, "Could not synchronize the optional Temps Cloud provider"); + } let count = notification_providers::Entity::find() .filter(notification_providers::Column::Enabled.eq(true)) .paginate(self.db.as_ref(), 1) @@ -1573,6 +1680,9 @@ impl NotificationService { } pub async fn list_providers(&self) -> Result> { + if let Err(error) = self.sync_cloud_provider().await { + error!(%error, "Could not synchronize the optional Temps Cloud provider"); + } let providers = notification_providers::Entity::find() .all(self.db.as_ref()) .await?; @@ -1584,6 +1694,9 @@ impl NotificationService { page: u64, page_size: u64, ) -> Result> { + if let Err(error) = self.sync_cloud_provider().await { + error!(%error, "Could not synchronize the optional Temps Cloud provider"); + } let providers = notification_providers::Entity::find() .paginate(self.db.as_ref(), page_size) .fetch_page(page - 1) @@ -1765,6 +1878,13 @@ impl NotificationService { &self, record: ¬ification_providers::Model, ) -> Result> { + if record.provider_type == "cloud" { + let cloud = self + .cloud + .clone() + .ok_or_else(|| anyhow::anyhow!("Temps Cloud service is unavailable"))?; + return Ok(Box::new(TempsCloudProvider { cloud })); + } // Decrypt the config before parsing let decrypted_config = self .encryption_service @@ -1899,8 +2019,15 @@ impl NotificationService { if let Some(provider) = provider { let notification_provider = self.load_provider(&provider).await?; - // Let the error propagate instead of swallowing it - notification_provider.health_check().await + let notification = Notification::new( + "Temps test notification", + "This is a test alert from your Temps notification settings. No action is required.", + ); + // A provider test must exercise delivery, not only configuration. + // Otherwise the UI can report success while credentials, routing, + // or the remote destination are unable to accept a message. + notification_provider.send(¬ification).await?; + Ok(true) } else { Err(anyhow::anyhow!( "Notification provider with ID {} not found", diff --git a/crates/temps-otel/src/services/otel_service.rs b/crates/temps-otel/src/services/otel_service.rs index 4a6869b7b..fb1a1770b 100644 --- a/crates/temps-otel/src/services/otel_service.rs +++ b/crates/temps-otel/src/services/otel_service.rs @@ -526,6 +526,7 @@ mod tests { base_url: "https://cloud.test/".to_string(), token: Some("instance-token".to_string()), tenant_id: Some(uuid::Uuid::new_v4()), + account_email: Some("owner@example.com".to_string()), } .save(&state_path) .unwrap(); diff --git a/web/e2e/authenticated/cloud-onboarding.spec.ts b/web/e2e/authenticated/cloud-onboarding.spec.ts index 08578a0c3..da5ec0b9b 100644 --- a/web/e2e/authenticated/cloud-onboarding.spec.ts +++ b/web/e2e/authenticated/cloud-onboarding.spec.ts @@ -2,6 +2,7 @@ import type { Page } from '@playwright/test' import { expect, expectAppMounted, test } from '../fixtures' const cloudStatus = (linked: boolean) => ({ + account_email: linked ? 'owner@example.com' : null, backend_url: 'http://localhost:19200', health: linked ? 'healthy' : 'disconnected', health_message: linked ? 'Signals are reaching Temps Cloud' : 'Not linked', @@ -72,14 +73,16 @@ test.describe('Temps Cloud activation onboarding', () => { await expect( page.getByRole('heading', { name: 'Connect this instance' }) ).toBeVisible() - await expect(page.getByRole('link', { name: 'Get a code' })).toHaveAttribute( - 'href', - 'http://localhost:19200' - ) + await expect( + page.getByRole('link', { name: 'Get a code' }) + ).toHaveAttribute('href', 'http://localhost:19200') await page.getByLabel('1. Paste enrollment code').fill('ABCD-EFGH') await page.getByRole('button', { name: '2. Connect' }).click() await expect(page.getByRole('heading', { name: 'Connected' })).toBeVisible() + await expect( + page.getByText('Cloud account: owner@example.com') + ).toBeVisible() await expect(page.getByText('instance-e2')).toBeVisible() expect(cloud.enrollmentCodes).toEqual(['ABCD-EFGH']) diff --git a/web/src/api/client/types.gen.ts b/web/src/api/client/types.gen.ts index 580707203..e80faeb0d 100644 --- a/web/src/api/client/types.gen.ts +++ b/web/src/api/client/types.gen.ts @@ -2151,6 +2151,7 @@ export type CloudSettings = { }; export type CloudStatus = { + account_email?: string | null; backend_url: string; health: string; health_message: string; diff --git a/web/src/pages/settings/CloudSettingsPage.tsx b/web/src/pages/settings/CloudSettingsPage.tsx index 57833d6fe..92aad60c7 100644 --- a/web/src/pages/settings/CloudSettingsPage.tsx +++ b/web/src/pages/settings/CloudSettingsPage.tsx @@ -159,6 +159,11 @@ export function CloudSettingsPage() {

    Connected

    + {status.data?.account_email + ? `Cloud account: ${status.data.account_email}` + : 'Cloud account unavailable — reconnect to refresh it'} +

    +

    {status.data?.status_message}

    From 98dbf84221625cabd29a895678640505b62d8f34 Mon Sep 17 00:00:00 2001 From: David Viejo Date: Thu, 6 Aug 2026 12:04:32 +0200 Subject: [PATCH 6/9] fix(openapi): preserve canonical cloud schema diff --- apps/temps-cli/openapi-ts.config.ts | 6 +- apps/temps-cli/openapi.json | 91893 +++++++++++++++- apps/temps-cli/src/api/client.gen.ts | 4 +- apps/temps-cli/src/api/client/client.gen.ts | 326 +- apps/temps-cli/src/api/client/index.ts | 2 + apps/temps-cli/src/api/client/types.gen.ts | 67 +- apps/temps-cli/src/api/client/utils.gen.ts | 54 +- apps/temps-cli/src/api/core/auth.gen.ts | 10 +- .../src/api/core/bodySerializer.gen.ts | 38 +- apps/temps-cli/src/api/core/params.gen.ts | 50 +- .../src/api/core/pathSerializer.gen.ts | 30 +- .../src/api/core/queryKeySerializer.gen.ts | 33 +- .../src/api/core/serverSentEvents.gen.ts | 46 +- apps/temps-cli/src/api/core/types.gen.ts | 30 +- apps/temps-cli/src/api/core/utils.gen.ts | 15 +- apps/temps-cli/src/api/index.ts | 4 +- apps/temps-cli/src/api/sdk.gen.ts | 1706 +- apps/temps-cli/src/api/types.gen.ts | 271 +- 18 files changed, 93118 insertions(+), 1467 deletions(-) diff --git a/apps/temps-cli/openapi-ts.config.ts b/apps/temps-cli/openapi-ts.config.ts index c17bf158e..3f7d3a41e 100644 --- a/apps/temps-cli/openapi-ts.config.ts +++ b/apps/temps-cli/openapi-ts.config.ts @@ -6,9 +6,5 @@ export default defineConfig({ output: { path: 'src/api', }, - client: '@hey-api/client-fetch', - plugins: [ - '@hey-api/sdk', - '@hey-api/typescript', - ], + plugins: ['@hey-api/sdk', '@hey-api/typescript'], }) diff --git a/apps/temps-cli/openapi.json b/apps/temps-cli/openapi.json index 8e86287d4..a5b04ab0d 100644 --- a/apps/temps-cli/openapi.json +++ b/apps/temps-cli/openapi.json @@ -1 +1,91892 @@ -{"openapi":"3.1.0","info":{"title":"Temps","description":"An API for managing projects, deployments, and infrastructure resources","contact":{"name":"Temps Support","url":"https://temps.sh"},"version":"1.0.0"},"servers":[{"url":"/api","description":"Base path for all API endpoints"}],"paths":{"/.well-known/temps.json":{"get":{"tags":["Platform"],"summary":"Get platform information","operationId":"get_platform_info","responses":{"200":{"description":"Successfully retrieved platform information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlatformInfo"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/0/organizations/{org_slug}/chunk-upload/":{"get":{"tags":["sentry-compat"],"summary":"Chunk upload options (stub for sentry-cli compatibility).","description":"sentry-cli checks this endpoint to determine if chunk-based upload is supported.\nWe return a response indicating that chunk upload is NOT supported, which forces\nsentry-cli to fall back to the standard file-by-file upload.","operationId":"chunk_upload_options","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Chunk upload options","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryChunkUploadResponse"}}}}}}},"/0/organizations/{org_slug}/releases/":{"post":{"tags":["sentry-compat"],"summary":"Create a release (stub for sentry-cli compatibility).","description":"sentry-cli calls this before uploading files. Since Temps implicitly creates\nreleases when source maps are uploaded, this is a no-op that returns the\nexpected response format.","operationId":"create_release","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored in single-tenant mode)","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryCreateReleaseRequest"}}},"required":true},"responses":{"201":{"description":"Release created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryReleaseResponse"}}}},"401":{"description":"Unauthorized"}}}},"/0/projects/{org_slug}/{project_slug}/releases/":{"post":{"tags":["sentry-compat"],"summary":"Create a release for a specific project (stub for sentry-cli compatibility).","description":"sentry-cli calls this endpoint (instead of /organizations/.../releases/) when\nboth SENTRY_ORG and SENTRY_PROJECT env vars are set. Behaves identically to\nthe organizations endpoint but validates the project slug.","operationId":"create_project_release","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored in single-tenant mode)","required":true,"schema":{"type":"string"}},{"name":"project_slug","in":"path","description":"Project slug or numeric ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryCreateReleaseRequest"}}},"required":true},"responses":{"201":{"description":"Release created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryReleaseResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"}}}},"/0/projects/{org_slug}/{project_slug}/releases/{version}/":{"put":{"tags":["sentry-compat"],"summary":"Finalize a release (stub for sentry-cli compatibility).","description":"sentry-cli calls `releases finalize` after uploading source maps. This sets\nthe dateReleased on the release. Since Temps stores source maps independently\nof releases, this is a no-op that returns the expected response.","operationId":"finalize_project_release","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored)","required":true,"schema":{"type":"string"}},{"name":"project_slug","in":"path","description":"Project slug or numeric ID","required":true,"schema":{"type":"string"}},{"name":"version","in":"path","description":"Release version to finalize","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Release finalized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryReleaseResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"}}}},"/0/projects/{org_slug}/{project_slug}/releases/{version}/files/":{"get":{"tags":["sentry-compat"],"summary":"List files for a release.","description":"Returns all source maps stored for a specific release in sentry-cli compatible format.","operationId":"list_release_files","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored)","required":true,"schema":{"type":"string"}},{"name":"project_slug","in":"path","description":"Project slug or numeric ID","required":true,"schema":{"type":"string"}},{"name":"version","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of release files","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SentryReleaseFileResponse"}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"}}},"post":{"tags":["sentry-compat"],"summary":"Upload a source map file for a release.","description":"Accepts the same multipart format as the Sentry release files API.\nThe `name` field should be the URL path of the file (e.g., `~/dist/bundle.js.map`).\n\nThe route has a 50 MiB body limit applied at the router level (Fix #4).\nA per-field size check provides an additional defense-in-depth layer.","operationId":"upload_release_file","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored)","required":true,"schema":{"type":"string"}},{"name":"project_slug","in":"path","description":"Project slug or numeric ID","required":true,"schema":{"type":"string"}},{"name":"version","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"File uploaded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryReleaseFileResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"},"413":{"description":"Source map file exceeds the 50 MiB per-field limit"}}}},"/_temps/event":{"post":{"tags":["Metrics"],"summary":"Record analytics event","operationId":"record_event_metrics","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventMetricsPayload"}}},"required":true},"responses":{"204":{"description":"Event recorded successfully"},"400":{"description":"Bad request"},"500":{"description":"Internal server error"}}}},"/_temps/session-replay/events":{"post":{"tags":["Analytics"],"summary":"Add events to existing session replay","operationId":"add_session_replay_events","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionReplayEventsRequest"}}},"required":true},"responses":{"200":{"description":"Events added successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddEventsResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/_temps/session-replay/init":{"post":{"tags":["Analytics"],"summary":"Initialize session replay with metadata","operationId":"init_session_replay","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionReplayInitRequest"}}},"required":true},"responses":{"201":{"description":"Session initialized successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionReplayInitResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/_temps/speed":{"post":{"tags":["Performance"],"summary":"Record performance metrics from client","operationId":"record_speed_metrics","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpeedMetricsPayload"}}},"required":true},"responses":{"204":{"description":"Metrics recorded successfully"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Host not found in route table","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/_temps/speed/update":{"post":{"tags":["Performance"],"summary":"Update late performance metrics","operationId":"update_speed_metrics","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSpeedMetricsPayload"}}},"required":true},"responses":{"204":{"description":"Metrics updated successfully"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Host not found or metrics not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/admin/gate-settings":{"get":{"tags":["AdminGate"],"operationId":"get_admin_gate","responses":{"200":{"description":"Current admin gate config","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminGateResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["AdminGate"],"operationId":"patch_admin_gate","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAdminGateRequest"}}},"required":true},"responses":{"200":{"description":"Updated admin gate config","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminGateResponse"}}}},"400":{"description":"Invalid IP/CIDR/host"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"409":{"description":"Env-overridden or would lock out caller"}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers":{"get":{"tags":["Authentication"],"operationId":"list_oidc_providers","responses":{"200":{"description":"OIDC providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OidcProviderResponse"}}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Authentication"],"operationId":"create_oidc_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOidcProviderRequest"}}},"required":true},"responses":{"201":{"description":"OIDC provider created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcProviderResponse"}}}},"409":{"description":"Another OIDC provider already uses that name"}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers/{provider_id}":{"delete":{"tags":["Authentication"],"operationId":"delete_oidc_provider","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"OIDC provider deleted"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Authentication"],"operationId":"update_oidc_provider","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOidcProviderRequest"}}},"required":true},"responses":{"200":{"description":"OIDC provider updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcProviderResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers/{provider_id}/role-mappings":{"get":{"tags":["Authentication"],"operationId":"list_oidc_role_mappings","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"OIDC role mappings","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OidcRoleMappingResponse"}}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Authentication"],"operationId":"create_oidc_role_mapping","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOidcRoleMappingRequest"}}},"required":true},"responses":{"201":{"description":"Role mapping created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcRoleMappingResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers/{provider_id}/test":{"post":{"tags":["Authentication"],"operationId":"test_oidc_provider","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcTestConnectionResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers/{provider_id}/users":{"get":{"tags":["Authentication"],"operationId":"list_oidc_provider_users","parameters":[{"name":"provider_id","in":"path","description":"OIDC provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Users authenticated via this OIDC provider","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OidcProviderUserResponse"}}}}},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/role-mappings/{mapping_id}":{"delete":{"tags":["Authentication"],"operationId":"delete_oidc_role_mapping","parameters":[{"name":"mapping_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Role mapping deleted"}},"security":[{"bearer_auth":[]}]}},"/agents/webhook/{webhook_id}":{"post":{"tags":["Agents"],"summary":"Public webhook endpoint. Authenticated via `X-Webhook-Token` header.","description":"`POST /api/agents/webhook/{webhook_id}`\nHeader: `X-Webhook-Token: `\n\nThe `webhook_id` in the URL is a short non-secret identifier (safe to log).\nThe actual credential is the secret token in the header.\n\nAccepts any JSON body, which is passed as `user_context` to the agent run.","operationId":"webhook_trigger","parameters":[{"name":"webhook_id","in":"path","description":"Webhook ID (non-secret)","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookTriggerRequest"}}},"required":true},"responses":{"202":{"description":"Agent run created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookTriggerResponse"}}}},"401":{"description":"Missing or invalid X-Webhook-Token header"},"404":{"description":"Invalid webhook ID"},"422":{"description":"Agent disabled"}}}},"/ai/conversations":{"get":{"tags":["AI Chat"],"summary":"List every active conversation across all projects, most-recently-active\nfirst, annotated with project name/slug. Powers the unified \"all chats\"\nswitcher in the AI assistant dock.","operationId":"list_all_conversations","responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GlobalConversationResponse"}}}}},"401":{"description":""},"403":{"description":""}},"security":[{"bearer_auth":[]}]}},"/ai/pricing":{"get":{"tags":["AI Gateway Pricing"],"operationId":"get_pricing","responses":{"200":{"description":"Model pricing information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PricingResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/providers":{"get":{"tags":["AI Gateway Admin"],"operationId":"list_provider_keys","responses":{"200":{"description":"List of provider keys","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderKeyResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["AI Gateway Admin"],"operationId":"create_provider_key","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProviderKeyRequest"}}},"required":true},"responses":{"201":{"description":"Provider key created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderKeyResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/providers/test":{"post":{"tags":["AI Gateway Admin"],"operationId":"test_provider_key_inline","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestProviderKeyRequest"}}},"required":true},"responses":{"200":{"description":"Test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestProviderKeyResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/providers/{id}":{"delete":{"tags":["AI Gateway Admin"],"operationId":"delete_provider_key","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Provider key deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["AI Gateway Admin"],"operationId":"update_provider_key","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProviderKeyRequest"}}},"required":true},"responses":{"200":{"description":"Provider key updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderKeyResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/providers/{id}/test":{"post":{"tags":["AI Gateway Admin"],"operationId":"test_provider_key_by_id","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestProviderKeyResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Provider key not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/by-provider":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_by_provider","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Usage broken down by provider","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderUsage"}}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/conversations":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_conversations","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max results (defaults to 50, max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"user_id","in":"query","description":"Filter by user ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"tags","in":"query","description":"Filter by tags (comma-separated)","required":false,"schema":{"type":"string"}},{"name":"model","in":"query","description":"Filter by model name","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Conversation summaries","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ConversationSummary"}}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/conversations/{conversation_id}":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_conversation_detail","parameters":[{"name":"conversation_id","in":"path","description":"Conversation ID","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max results (defaults to 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Invocations within a conversation","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UsageLogEntry"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/recent":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_recent","parameters":[{"name":"limit","in":"query","description":"Page size (defaults to 20, max 50)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Number of results to skip for pagination (defaults to 0)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"provider","in":"query","description":"Filter by provider name","required":false,"schema":{"type":"string"}},{"name":"model","in":"query","description":"Filter by model name","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Filter by HTTP status code (exact match)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"cost_gte","in":"query","description":"Cost greater-than-or-equal, in microcents","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"cost_gt","in":"query","description":"Cost strictly greater-than, in microcents","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"cost_lte","in":"query","description":"Cost less-than-or-equal, in microcents","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"cost_lt","in":"query","description":"Cost strictly less-than, in microcents","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tokens_gte","in":"query","description":"Total tokens greater-than-or-equal","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tokens_gt","in":"query","description":"Total tokens strictly greater-than","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tokens_lte","in":"query","description":"Total tokens less-than-or-equal","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tokens_lt","in":"query","description":"Total tokens strictly less-than","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Page of recent usage log entries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageLogPage"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/summary":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_summary","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Usage summary for the time range","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageSummary"}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/timeseries":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_timeseries","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}},{"name":"bucket","in":"query","description":"Bucket size: hour, day, week (defaults to day)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Time-series usage data","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TimeseriesBucket"}}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/top-models":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_top_models","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max results (defaults to 10)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Top models by request count","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ModelUsage"}}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/v1/chat/completions":{"post":{"tags":["AI Gateway"],"operationId":"chat_completions","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatCompletionRequest"}}},"required":true},"responses":{"200":{"description":"Chat completion response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatCompletionResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"404":{"description":"Model not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/v1/embeddings":{"post":{"tags":["AI Gateway"],"operationId":"embeddings","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmbeddingRequest"}}},"required":true},"responses":{"200":{"description":"Embedding response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmbeddingResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"404":{"description":"Model not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/v1/models":{"get":{"tags":["AI Gateway"],"operationId":"list_models","responses":{"200":{"description":"List of available models","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/analytics/active-visitors":{"get":{"tags":["Analytics"],"summary":"Get detailed active visitors","operationId":"get_analytics_active_visitors","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Deployment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"window_minutes","in":"query","description":"Time window in minutes for active visitors (default: 5)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved active visitors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActiveVisitorsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/event-detail":{"get":{"tags":["Analytics"],"summary":"Get detailed analytics for a specific event","operationId":"get_event_detail","parameters":[{"name":"event_name","in":"query","description":"Event name to get details for","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"bucket_interval","in":"query","description":"Bucket interval: hour, day, week, month (default: auto)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved event details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventDetailResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/event-entries":{"get":{"tags":["Analytics"],"summary":"Get paginated list of raw occurrences of a specific event, including custom JSON properties","operationId":"get_event_entries","parameters":[{"name":"event_name","in":"query","description":"Event name to list occurrences for","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (1-based, default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Successfully retrieved event entries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventEntriesResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/event-visitors":{"get":{"tags":["Analytics"],"summary":"Get paginated list of visitors who triggered a specific event","operationId":"get_event_visitors","parameters":[{"name":"event_name","in":"query","description":"Event name to list visitors for","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (1-based, default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Successfully retrieved event visitors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventVisitorsResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/events":{"get":{"tags":["Analytics"],"operationId":"get_analytics_events_count","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Maximum number of results to return","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"custom_events_only","in":"query","description":"Only return custom events, excluding system events like page_view, page_leave, heartbeat (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"breakdown","in":"query","description":"Breakdown by geography: 'country', 'region', or 'city' (optional)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved event counts","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventCount"}}}}},"400":{"description":"Invalid date format, missing required parameters, or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/general-stats":{"get":{"tags":["Analytics"],"summary":"Get general statistics across all projects for a time frame","operationId":"get_general_stats","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_ids","in":"query","description":"Optional: Filter by specific project IDs (comma-separated)","required":false,"schema":{"type":"array","items":{"type":"integer","format":"int32"}}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"include_project_breakdown","in":"query","description":"Whether to include per-project breakdown (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Successfully retrieved general statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeneralStatsResponse"}}}},"400":{"description":"Invalid date format or parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/has-events":{"get":{"tags":["Analytics"],"operationId":"check_analytics_has_events","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Analytics events existence check","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HasAnalyticsEventsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/live-visitors":{"get":{"tags":["Analytics"],"summary":"Get list of currently live visitors from visitor table","operationId":"get_live_visitors_list","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"window_minutes","in":"query","description":"Time window in minutes for live visitors (default: 5)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved live visitors list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LiveVisitorsListResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-flow":{"get":{"tags":["Analytics"],"summary":"Get page flow analytics: entry pages, exit pages, drop-off points, and page transitions","operationId":"get_page_flow","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max entry/exit pages to return (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"transitions_limit","in":"query","description":"Max page transitions to return (default: 50, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"min_views_for_dropoff","in":"query","description":"Minimum views for drop-off analysis (default: 5)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved page flow analytics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PageFlowResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-hourly-sessions":{"get":{"tags":["Analytics"],"operationId":"get_page_hourly_sessions","parameters":[{"name":"page_path","in":"query","description":"The page path to get sessions for","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","description":"Start time in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"bucket_interval","in":"query","description":"Bucket interval: 'hour', 'day', 'week', or 'month' (default: auto-determined based on range)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved page sessions with time buckets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PageHourlySessionsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-path-detail":{"get":{"tags":["Analytics"],"summary":"Get detailed analytics for a specific page path\nReturns visitors, page views, activity over time, geographic distribution, and referrers","operationId":"get_page_path_detail","parameters":[{"name":"page_path","in":"query","description":"The page path to get details for (URL-encoded)","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"bucket_interval","in":"query","description":"Bucket interval for time series: 'hour', 'day', 'week', 'month' (default: auto based on date range)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved page path detail analytics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PagePathDetailResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-path-visitors":{"get":{"tags":["Analytics"],"summary":"Get individual visitor sessions for a specific page path","operationId":"get_page_path_visitors","parameters":[{"name":"page_path","in":"query","description":"The page path to get visitors for (URL-encoded)","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (1-based, default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Successfully retrieved page path visitors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PagePathVisitorsResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-paths":{"get":{"tags":["Analytics"],"operationId":"get_page_paths","parameters":[{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS (optional)","required":false,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS (optional)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Maximum number of page paths to return (default: 100, max: 1000)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved page paths","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PagePathsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-paths-sparklines":{"get":{"tags":["Analytics"],"operationId":"get_page_paths_sparklines","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","description":"Start time in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"page_paths","in":"query","description":"Comma-separated list of page paths","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sparkline data for all requested page paths","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PagePathsSparklineResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/recent-activity":{"get":{"tags":["Analytics"],"summary":"Get recent activity events for real-time activity feed","operationId":"get_recent_activity","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"since_id","in":"query","description":"Return events with ID greater than this (cursor-based polling)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"limit","in":"query","description":"Max events to return (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved recent activity events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecentActivityResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/sessions/{session_id}":{"get":{"tags":["Analytics"],"summary":"Get detailed information about a specific session including events and request logs","operationId":"get_session_details","parameters":[{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved session details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionDetails"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Session not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/sessions/{session_id}/events":{"get":{"tags":["Analytics"],"operationId":"get_analytics_session_events","parameters":[{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":false,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Number of results to return (default: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Number of results to skip (default: 0)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved session events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionEventsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Session not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/sessions/{session_id}/logs":{"get":{"tags":["Analytics"],"operationId":"get_session_logs","parameters":[{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":false,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Number of results to return (default: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Number of results to skip (default: 0)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved session logs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionLogsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Session not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitor-facets":{"get":{"tags":["Analytics"],"summary":"Get filter dropdown contents for the visitors page. Returns the top\nvalues per dimension with distinct visitor counts so the UI can render\n\"Country — 1,234 visitors\" rows. Each dimension is computed against the\nsegment minus its own filter, so a selected value never collapses its\nown dropdown.","operationId":"get_visitor_facets","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"include_crawlers","in":"query","description":"Include crawlers (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"has_activity_only","in":"query","description":"Hide ghost visitors (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"per_facet_limit","in":"query","description":"Top N values per dimension (default: 50, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"filter_country","in":"query","description":"Geolocation country","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Geolocation region","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Geolocation city","required":false,"schema":{"type":"string"}},{"name":"filter_channel","in":"query","description":"First-touch channel","required":false,"schema":{"type":"string"}},{"name":"filter_referrer","in":"query","description":"First-touch referrer hostname (use 'Direct' for null)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Top values per dimension","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorFacets"}}}},"400":{"description":"Invalid date format or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors":{"get":{"tags":["Analytics"],"summary":"Get list of visitors with summary information","operationId":"get_visitors","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"include_crawlers","in":"query","description":"Include crawlers (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Maximum number of visitors to return (default: 50)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Number of visitors to skip (default: 0)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"has_activity_only","in":"query","description":"Filter to only include visitors with recorded activity (events/sessions). When true, excludes ghost visitors (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"filter_country","in":"query","description":"Geolocation country","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Geolocation region","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Geolocation city","required":false,"schema":{"type":"string"}},{"name":"filter_channel","in":"query","description":"First-touch channel","required":false,"schema":{"type":"string"}},{"name":"filter_referrer","in":"query","description":"First-touch referrer hostname (use 'Direct' for null)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved visitors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorsResponse"}}}},"400":{"description":"Invalid date format, missing required parameters, or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/guid/{visitor_id}":{"get":{"tags":["Analytics"],"summary":"Get visitor by GUID with geolocation data","operationId":"get_visitor_by_guid","parameters":[{"name":"visitor_id","in":"path","description":"Visitor GUID (supports enc_ prefix for encrypted IDs)","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor with geolocation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorWithGeolocation"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/id/{id}":{"get":{"tags":["Analytics"],"summary":"Get visitor by numeric ID with geolocation data","operationId":"get_visitor_by_id","parameters":[{"name":"id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor with geolocation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorWithGeolocation"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}":{"get":{"tags":["Analytics"],"summary":"Get detailed information about a specific visitor by numeric ID","operationId":"get_visitor_details","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorDetails"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/enrich":{"put":{"tags":["Analytics"],"operationId":"enrich_visitor","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID - can be numeric ID, GUID, or encrypted GUID (enc_xxx)","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnrichVisitorRequest"}}},"required":true},"responses":{"200":{"description":"Successfully enriched visitor data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnrichVisitorResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/info":{"get":{"tags":["Analytics"],"summary":"Get visitor record from database","operationId":"get_visitor_info","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor info","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorRecord"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/journey":{"get":{"tags":["Analytics"],"summary":"Get the complete visitor journey: all events across all sessions, grouped by session","operationId":"get_visitor_journey","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"limit_sessions","in":"query","description":"Maximum number of sessions to return (default: 50)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor journey","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorJourneyResponse"}}}},"400":{"description":"Invalid parameters"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/sessions":{"get":{"tags":["Analytics"],"summary":"Get all sessions for a specific visitor by numeric ID","operationId":"get_analytics_visitor_sessions","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Maximum number of sessions to return (default: 100)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor sessions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorSessionsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/stats":{"get":{"tags":["Analytics"],"summary":"Get visitor statistics","operationId":"get_visitor_stats","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorStats"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys":{"get":{"tags":["API Keys"],"operationId":"list_api_keys","parameters":[{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default: 20)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"API keys retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["API Keys"],"operationId":"create_api_key","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyRequest"}}},"required":true},"responses":{"201":{"description":"API key created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"409":{"description":"Conflict - API key name already exists"},"428":{"description":"Recent MFA verification required"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/permissions":{"get":{"tags":["API Keys"],"operationId":"get_api_key_permissions","responses":{"200":{"description":"Available permissions and roles retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AvailablePermissions"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/{id}":{"get":{"tags":["API Keys"],"operationId":"get_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"API key retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["API Keys"],"operationId":"update_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateApiKeyRequest"}}},"required":true},"responses":{"200":{"description":"API key updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"409":{"description":"Conflict - API key name already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["API Keys"],"operationId":"delete_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"API key deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/{id}/activate":{"post":{"tags":["API Keys"],"operationId":"activate_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"API key activated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/{id}/deactivate":{"post":{"tags":["API Keys"],"operationId":"deactivate_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"API key deactivated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/{id}/rotate":{"post":{"tags":["API Keys"],"operationId":"rotate_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"API key rotated successfully; the response contains the new plaintext secret, shown only once","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"428":{"description":"Recent MFA verification required"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/auth/cli/device/approve":{"post":{"tags":["Authentication"],"operationId":"cli_device_approve","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceApproveRequest"}}},"required":true},"responses":{"200":{"description":"Session approved; CLI can now claim the API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceApproveResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Browser session required"},"404":{"description":"Unknown user_code"},"409":{"description":"Already resolved"},"410":{"description":"Session expired"},"428":{"description":"Recent MFA verification required"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/auth/cli/device/deny":{"post":{"tags":["Authentication"],"operationId":"cli_device_deny","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceApproveRequest"}}},"required":true},"responses":{"200":{"description":"Session denied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceApproveResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Unknown user_code"},"409":{"description":"Already resolved"},"410":{"description":"Session expired"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/auth/cli/device/lookup":{"get":{"tags":["Authentication"],"operationId":"cli_device_lookup","parameters":[{"name":"user_code","in":"query","description":"`user_code` as displayed in the CLI / pasted into the URL.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Device session metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceLookupResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Unknown user_code"},"410":{"description":"Device session expired"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/auth/cli/device/poll":{"post":{"tags":["Authentication"],"operationId":"cli_device_poll","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDevicePollRequest"}}},"required":true},"responses":{"200":{"description":"Poll result; check `status` field","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDevicePollResponse"}}}},"404":{"description":"Unknown device_code"},"500":{"description":"Internal server error"}}}},"/auth/cli/device/start":{"post":{"tags":["Authentication"],"operationId":"cli_device_start","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceStartRequest"}}},"required":true},"responses":{"200":{"description":"Device session created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceStartResponse"}}}},"500":{"description":"Internal server error"}}}},"/auth/cli/logout":{"post":{"tags":["Authentication"],"operationId":"cli_logout","responses":{"204":{"description":"API key revoked"},"401":{"description":"Not authenticated"},"403":{"description":"Endpoint requires API key authentication"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/auth/email-status":{"get":{"tags":["Authentication"],"operationId":"email_status","responses":{"200":{"description":"Email configuration status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailStatusResponse"}}}},"500":{"description":"Internal server error"}}}},"/auth/login":{"post":{"tags":["Authentication"],"operationId":"login","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginRequest"}}},"required":true},"responses":{"200":{"description":"Login successful, session cookie set","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"401":{"description":"Invalid credentials, or the account's role requires MFA enrollment that has not been completed"},"500":{"description":"Internal server error"}}}},"/auth/oidc/callback":{"get":{"tags":["Authentication"],"operationId":"oidc_callback","parameters":[{"name":"code","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"state","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"error","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"error_description","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"302":{"description":"Redirect to app with session cookie or login error"}}}},"/auth/oidc/login/{slug}":{"get":{"tags":["Authentication"],"operationId":"start_oidc_login_by_slug","parameters":[{"name":"slug","in":"path","description":"OIDC provider slug (from /email-status or /auth/oidc/providers)","required":true,"schema":{"type":"string"}},{"name":"return_to","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"302":{"description":"Redirect to IdP authorize URL"},"404":{"description":"Provider not found"},"503":{"description":"OIDC provider unreachable"}}}},"/auth/oidc/providers":{"get":{"tags":["Authentication"],"operationId":"list_public_providers","responses":{"200":{"description":"Enabled OIDC providers for login page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcProvidersListResponse"}}}}}}},"/auth/password-change-required":{"post":{"tags":["Authentication"],"operationId":"change_required_password","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequiredPasswordChangeRequest"}}},"required":true},"responses":{"200":{"description":"Required password change completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequiredPasswordChangeResponse"}}}},"400":{"description":"Password does not meet requirements"},"401":{"description":"Password-change session is missing or expired"},"500":{"description":"Internal server error"}}}},"/auth/password-reset/request":{"post":{"tags":["Authentication"],"operationId":"request_password_reset","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailRequest"}}},"required":true},"responses":{"200":{"description":"Reset email sent if account exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"503":{"description":"Email service not configured"}}}},"/auth/password-reset/verify":{"post":{"tags":["Authentication"],"operationId":"reset_password","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPasswordRequest"}}},"required":true},"responses":{"200":{"description":"Password reset successful","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"400":{"description":"Invalid or expired token"},"500":{"description":"Internal server error"}}}},"/auth/step-up":{"post":{"tags":["Authentication"],"operationId":"verify_step_up","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyStepUpRequest"}}},"required":true},"responses":{"200":{"description":"Session elevated for sensitive actions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StepUpResponse"}}}},"400":{"description":"Verification code is empty"},"401":{"description":"Invalid code or expired session"},"403":{"description":"Browser session required"},"428":{"description":"MFA setup required"},"429":{"description":"Too many verification attempts"},"500":{"description":"Verification infrastructure failed"}},"security":[{"session_token":[]}]}},"/auth/verify-email":{"get":{"tags":["Authentication"],"operationId":"verify_email","parameters":[{"name":"token","in":"query","description":"Email verification token","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Email verified successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"400":{"description":"Invalid or expired token"},"500":{"description":"Internal server error"}}}},"/auth/verify-mfa":{"post":{"tags":["Authentication"],"operationId":"verify_mfa_challenge","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaVerificationRequest"}}},"required":true},"responses":{"204":{"description":"MFA verification successful"},"400":{"description":"Invalid request"},"401":{"description":"Invalid MFA code"},"500":{"description":"Internal server error"}}}},"/backups/alerts":{"get":{"tags":["Backups"],"summary":"List open backup alerts.","description":"Returns all alerts that have not yet been resolved, ordered by `opened_at`\ndescending (newest first). The UI renders these as a banner above the\nBackups page content. Alerts are auto-opened by the watcher and\nauto-resolved when the triggering condition clears.\n\n**Schedule overdue** — the backup scheduler did not enqueue a job within\nthe expected window (1 hour past `next_run`). Usually means the scheduler\ntask is dead or wedged.\n\n**Job stalled** — a `backup_jobs` row has been in `state='pending'` for\nmore than 1 hour. The runner never claimed the job. Usually means the\nrunner task is dead or the runner concurrency cap is too low.","operationId":"list_backup_alerts","responses":{"200":{"description":"List of open backup alerts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupAlertListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/cleanup":{"post":{"tags":["Backups"],"summary":"Preview or run retention using each selected schedule's configured retention days.","operationId":"cleanup_expired_backups","parameters":[{"name":"dry_run","in":"query","description":"Return the backups selected by retention without deleting anything.","required":false,"schema":{"type":"boolean"}},{"name":"schedule_id","in":"query","description":"Limit cleanup to one backup schedule.","required":false,"schema":{"type":["integer","null"],"format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CleanupExpiredBackupsRequest"}}},"required":true},"responses":{"200":{"description":"Retention cleanup completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RetentionCleanupReport"}}}},"400":{"description":"Missing or invalid preview candidate list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule or backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"409":{"description":"Cleanup preview is stale","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Cleanup could not be started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/external-services/{id}/run":{"post":{"tags":["Backups"],"summary":"Run a backup for an external service manually.","description":"Enqueues the backup for asynchronous execution via the `BackupRunner`\n(ADR-014). Returns `202 Accepted` immediately: pending parent and child\nrows are inserted, and a `backup_jobs` row is enqueued for the resolved\nengine. Poll `GET /backups/{id}` to observe `pending → running → completed`.","operationId":"run_external_service_backup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunExternalServiceBackupRequest"}}},"required":true},"responses":{"202":{"description":"Backup enqueued for async execution","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceBackupResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"External service or S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/external-services/{service_id}/backups":{"get":{"tags":["Backups"],"summary":"List all backups for a specific external service (DB-only, no S3 scan).","description":"Returns a paginated list of backups that belong to this service.\nCompletes in <100 ms regardless of S3 endpoint latency because it\nnever touches S3.","operationId":"list_external_service_backups","parameters":[{"name":"service_id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based). Defaults to 1.","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"page_size","in":"query","description":"Items per page. Defaults to 20, max 100.","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Paginated list of backups for this service","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceBackupListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/external-services/{service_id}/schedules":{"get":{"tags":["Backups"],"summary":"List the schedules that target a specific external service. Useful for\nthe service detail page (\"which schedules back this DB up?\").","operationId":"list_service_schedules","parameters":[{"name":"service_id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Schedules backing up this service","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Service not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources":{"get":{"tags":["Backups"],"summary":"List all S3 sources","operationId":"list_s3_sources","responses":{"200":{"description":"List of S3 sources","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/S3SourceResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Backups"],"summary":"Create a new S3 source","operationId":"create_s3_source","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateS3SourceRequest"}}},"required":true},"responses":{"201":{"description":"S3 source created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3SourceResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/test":{"post":{"tags":["Backups"],"summary":"Test S3 connectivity against a prospective source configuration (before creating it).\nThe credentials are NOT persisted. Useful for validating the form in the UI.","operationId":"test_s3_connection_preview","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateS3SourceRequest"}}},"required":true},"responses":{"200":{"description":"Connection test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3ConnectionTestResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}":{"get":{"tags":["Backups"],"summary":"Get an S3 source by ID","operationId":"get_s3_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"S3 source details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3SourceResponse"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Backups"],"summary":"Delete an S3 source","operationId":"delete_s3_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"S3 source deleted"},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Backups"],"summary":"Update an S3 source","operationId":"update_s3_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateS3SourceRequest"}}},"required":true},"responses":{"200":{"description":"S3 source updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3SourceResponse"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}/backups":{"get":{"tags":["Backups"],"summary":"List all backups in an S3 source","operationId":"list_source_backups","parameters":[{"name":"include_s3_scan","in":"query","description":"When `true`, scan the S3 bucket for backups not tracked in the\nlocal database (useful after disaster-recovery from another Temps\ninstance). Defaults to `false` — the fast DB-only path.","required":false,"schema":{"type":"boolean"}},{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of all backups in the source","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceBackupIndexResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"S3 source not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}/run":{"post":{"tags":["Backups"],"summary":"Run a backup immediately for an S3 source.","description":"Enqueues the backup for asynchronous execution via the `BackupRunner`\n(ADR-014). Returns `202 Accepted` immediately: a `backups` row is inserted\nwith `state='pending'` and a `backup_jobs` row is enqueued for the\n`ControlPlaneEngine`. Poll `GET /backups/{id}` to observe\n`pending → running → completed`.","operationId":"run_backup_for_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunBackupRequest"}}},"required":true},"responses":{"202":{"description":"Backup enqueued for async execution","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}/set-default":{"post":{"tags":["Backups"],"summary":"Mark an S3 source as the default. All new backups/schedules/services that do not\nexplicitly reference a source will use the default. Returns the updated source.","operationId":"set_default_s3_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"S3 source marked as default","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3SourceResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}/test":{"post":{"tags":["Backups"],"summary":"Test connectivity to an existing S3 source using its stored credentials.","operationId":"test_s3_source_connection","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3ConnectionTestResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedule-runs/{id}/cancel":{"post":{"tags":["Backups"],"summary":"Cancel every non-terminal child backup belonging to a schedule run.","description":"Loops over `state IN ('pending','running')` children and flips each via\nthe same path as the per-backup cancel endpoint. The parent\n`schedule_runs.finished_at` is stamped automatically once no live\nchildren remain. Idempotent: cancelling a run with no live children is\na 200 with `cancelled = 0`.","operationId":"cancel_schedule_run","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Cancel processed (idempotent)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelBackupResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule run not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedule-runs/{id}/jobs":{"get":{"tags":["Backups"],"summary":"List the individual backup jobs for a single scheduler run.","description":"Returns each child `backups` row joined with its external service name and\nthe most-recent `backup_jobs` engine key. Used by the schedule detail\naccordion to show per-job detail on row expand.\n\n`page_size` defaults to 50 and is capped at 200.","operationId":"list_schedule_run_jobs","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Jobs for this scheduler run","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ScheduleRunJobEntry"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules":{"get":{"tags":["Backups"],"summary":"List all backup schedules","operationId":"list_backup_schedules","responses":{"200":{"description":"List of backup schedules","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Backups"],"summary":"Create a new backup schedule","operationId":"create_backup_schedule","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBackupScheduleRequest"}}},"required":true},"responses":{"201":{"description":"Backup schedule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}":{"get":{"tags":["Backups"],"summary":"Get a backup schedule by ID","operationId":"get_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Backup schedule details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"404":{"description":"Backup schedule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Backups"],"summary":"Delete a backup schedule","operationId":"delete_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Backup schedule deleted"},"404":{"description":"Backup schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Backups"],"summary":"Update a backup schedule (partial update).","description":"All request fields are optional; only fields that are present in the\nJSON body are updated. Absent fields leave the corresponding column\nunchanged. If `schedule_expression` is changed, `next_run` is\nrecomputed automatically.","operationId":"update_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBackupScheduleRequest"}}},"required":true},"responses":{"200":{"description":"Schedule updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/backups":{"get":{"tags":["Backups"],"summary":"List backups for a schedule","operationId":"list_backups_for_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of backups for the schedule","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BackupResponse"}}}}},"404":{"description":"Backup schedule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/disable":{"patch":{"tags":["Backups"],"summary":"Disable a backup schedule","operationId":"disable_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Backup schedule disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"404":{"description":"Backup schedule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/enable":{"patch":{"tags":["Backups"],"summary":"Enable a backup schedule","operationId":"enable_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Backup schedule enabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"404":{"description":"Backup schedule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/run":{"post":{"tags":["Backups"],"summary":"Immediately fan-out a run for the given schedule (Run Now).","description":"Creates one `schedule_runs` row, one control-plane backup job, and one\nbackup job per supported external service — all in a single transaction.\nReturns `202 Accepted` with a [`ScheduleRunResponse`] containing the new\n`schedule_run_id` and the list of enqueued jobs. Returns `409 Conflict` if\na run for this schedule is already in flight or if the schedule is disabled.","operationId":"run_schedule_now","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Fan-out run enqueued for async execution","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduleRunResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"409":{"description":"Run already in flight or schedule disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/runs":{"get":{"tags":["Backups"],"summary":"Paginated run history for a backup schedule (one row per scheduler tick).","description":"Returns one [`ScheduleRunSummary`] per scheduler tick, with child backup\ncounts aggregated in a single SQL round-trip. Legacy `backups` rows (pre-\nfan-out) are surfaced as synthetic single-job runs so history does not\ndisappear. Ordered by `started_at DESC` (newest first).\n\nUse `GET /backups/schedule-runs/{run_id}/jobs` to drill into a single run.","operationId":"list_schedule_runs","parameters":[{"name":"page","in":"query","description":"Page number (1-based, defaults to 1, clamped to 1 if < 1).","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"page_size","in":"query","description":"Items per page (defaults to 20, clamped to 100 if > 100).","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Paginated run history for the schedule","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduleRunSummaryList"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/services":{"get":{"tags":["Backups"],"summary":"List the external services attached to a backup schedule.","operationId":"list_schedule_services","parameters":[{"name":"id","in":"path","description":"Schedule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Services attached to this schedule","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ExternalServiceSummary"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Backups"],"summary":"Attach one or more external services to a backup schedule. Idempotent —\nservices that are already attached are silently skipped (`ON CONFLICT\nDO NOTHING`). Returns the count of newly inserted rows + the total\nmembership after the operation.","operationId":"attach_schedule_services","parameters":[{"name":"id","in":"path","description":"Schedule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachScheduleServicesRequest"}}},"required":true},"responses":{"200":{"description":"Services attached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachScheduleServicesResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/services/{service_id}":{"delete":{"tags":["Backups"],"summary":"Detach a single external service from a backup schedule. Idempotent —\nreturns `204` whether or not a row was actually removed.","operationId":"detach_schedule_service","parameters":[{"name":"id","in":"path","description":"Schedule ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"service_id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Service detached (or was not attached)"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/{id}":{"get":{"tags":["Backups"],"summary":"Get a backup by ID","operationId":"get_backup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Backup details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Backups"],"summary":"Permanently delete one terminal backup from object storage and the database.","operationId":"delete_backup","parameters":[{"name":"id","in":"path","description":"Backup UUID","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Backup deleted"},"400":{"description":"Backup artifact cannot be safely attributed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"409":{"description":"Backup is running, referenced, or lacks safe artifact identity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Object storage or database error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/{id}/cancel":{"post":{"tags":["Backups"],"summary":"Cancel a single in-flight backup.","description":"Flips the parent `backups` row + its latest `backup_jobs` row to\n`failed` with reason `\"cancelled by user \"`. The in-process\n`CancellationToken` is observed on the next heartbeat tick (≤5s), so the\nengine exits cleanly and rollback reaps the sidecar. Idempotent: cancelling\nan already-terminal backup is a 200 with `cancelled = 0`.","operationId":"cancel_backup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Cancel processed (idempotent)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelBackupResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/{id}/children":{"get":{"tags":["Backups"],"summary":"List the external-service child backups that belong to a parent backup.","description":"Each entry in `children` corresponds to one `external_service_backups` row,\njoined with `external_services` so the caller receives the service name and\ntype without a second request.\n\nReturns an empty `{ \"children\": [] }` — **not 404** — when the parent\nbackup exists but has no children (e.g. control-plane backups).\nReturns 404 when the parent backup itself does not exist.","operationId":"list_backup_children","parameters":[{"name":"id","in":"path","description":"Integer row id of the parent backup","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Child backup list (may be empty)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChildBackupListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Parent backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/blob":{"get":{"tags":["Blob"],"summary":"List blobs","operationId":"blob_list","parameters":[{"name":"limit","in":"query","description":"Maximum number of items to return","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"prefix","in":"query","description":"Prefix to filter by","required":false,"schema":{"type":"string"}},{"name":"cursor","in":"query","description":"Continuation token for pagination","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of blobs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListBlobsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Blob"],"summary":"Upload a blob","operationId":"blob_put","requestBody":{"description":"Binary blob data","content":{"application/octet-stream":{"schema":{"type":"string"}}},"required":true},"responses":{"201":{"description":"Blob uploaded successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlobResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Blob"],"summary":"Delete blobs","operationId":"blob_delete","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteBlobRequest"}}},"required":true},"responses":{"200":{"description":"Blobs deleted successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteBlobResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/blob/copy":{"post":{"tags":["Blob"],"summary":"Copy a blob to a new location","operationId":"blob_copy","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CopyBlobRequest"}}},"required":true},"responses":{"200":{"description":"Blob copied successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlobResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Source blob not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/blob/disable":{"delete":{"tags":["Blob Management"],"summary":"Disable Blob service","operationId":"blob_disable","responses":{"200":{"description":"Blob service disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DisableBlobResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Blob service not enabled"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/blob/enable":{"post":{"tags":["Blob Management"],"summary":"Enable Blob service","operationId":"blob_enable","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnableBlobRequest"}}},"required":true},"responses":{"200":{"description":"Blob service enabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnableBlobResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/blob/status":{"get":{"tags":["Blob Management"],"summary":"Get Blob service status","operationId":"blob_status","responses":{"200":{"description":"Blob service status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlobStatusResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/blob/update":{"patch":{"tags":["Blob Management"],"summary":"Update Blob service configuration","operationId":"blob_update","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBlobRequest"}}},"required":true},"responses":{"200":{"description":"Blob service updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBlobResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Blob service not enabled"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/blob/{project_id}/{path}":{"get":{"tags":["Blob"],"summary":"Download a blob","operationId":"blob_download","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","description":"Blob path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Blob content"},"404":{"description":"Blob not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"head":{"tags":["Blob"],"summary":"Get blob metadata","operationId":"blob_head","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","description":"Blob path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Blob metadata in headers"},"404":{"description":"Blob not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/cloud":{"delete":{"tags":["Cloud"],"operationId":"disconnect_cloud","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CloudStatus"}}}}},"security":[{"bearer_auth":[]}]}},"/cloud/capability":{"get":{"tags":["Cloud"],"operationId":"get_cloud_capability","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CloudCapability"}}}}},"security":[{"bearer_auth":[]}]}},"/cloud/enroll":{"post":{"tags":["Cloud"],"operationId":"enroll_cloud","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnrollCloudRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CloudStatus"}}}}},"security":[{"bearer_auth":[]}]}},"/cloud/status":{"get":{"tags":["Cloud"],"operationId":"get_cloud_status","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CloudStatus"}}}}},"security":[{"bearer_auth":[]}]}},"/dashboard/projects-analytics":{"get":{"tags":["Events"],"summary":"Get dashboard analytics for multiple projects in a single batch request","description":"Returns unique visitor counts and hourly sparkline data for all requested projects\nusing only 2 SQL queries instead of 2×N per-project queries.","operationId":"get_dashboard_projects_analytics","parameters":[{"name":"project_ids","in":"query","description":"Comma-separated list of project IDs","required":true,"schema":{"type":"string"}},{"name":"start_date","in":"query","description":"Start date for filtering","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved batch analytics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DashboardProjectsAnalyticsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/deployments/activity-graph":{"get":{"tags":["Deployments"],"summary":"Get deployment activity graph showing daily deployment counts\nSimilar to GitHub's contribution graph","operationId":"get_activity_graph","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"days","in":"query","description":"Number of days to include (default: 365)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved activity graph","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivityGraphResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/deployments/{deployment_id}/vulnerability-scan":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_scan_by_deployment","parameters":[{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Scan for the specified deployment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"No scan found for deployment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/deployments/{id}/metrics":{"get":{"tags":["Metrics"],"summary":"Fetch a time-series range for a single metric on a deployment.","operationId":"DeploymentMetricsGetRange","parameters":[{"name":"id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric","in":"query","description":"Metric name, e.g. `\"pg.connections_active\"`.","required":true,"schema":{"type":"string"}},{"name":"range","in":"query","description":"Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`.","required":false,"schema":{"type":"string"}},{"name":"percentile","in":"query","description":"Optional histogram percentile (0–100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile.","required":false,"schema":{"type":["number","null"],"format":"double"}}],"responses":{"200":{"description":"Metric time series data points","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MetricDataPoint"}}}}},"400":{"description":"Invalid query parameters"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/deployments/{id}/metrics/enable":{"patch":{"tags":["Metrics"],"summary":"Enable or disable OTLP metric ingestion for a deployment.","description":"When `enabled=true`, seeds the default container alert rules for the\ndeployment via [`temps_monitoring::seed_default_container_rules`] (idempotent).","operationId":"DeploymentMetricsToggle","parameters":[{"name":"id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToggleDeploymentMetricsRequest"}}},"required":true},"responses":{"200":{"description":"Metrics toggle applied"},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/deployments/{id}/metrics/latest":{"get":{"tags":["Metrics"],"summary":"Fetch the most-recent metric values for a deployment.","operationId":"DeploymentMetricsGetLatest","parameters":[{"name":"id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Map of metric name to latest value","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"number","format":"double"},"propertyNames":{"type":"string"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/dns-providers":{"get":{"tags":["DNS Providers"],"summary":"List all DNS providers","operationId":"list_dns_providers","responses":{"200":{"description":"List of DNS providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DnsProviderResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["DNS Providers"],"summary":"Create a new DNS provider","description":"The provider's credentials will be tested before creation.\nIf the connection test fails, the provider will not be created.","operationId":"create_dns_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDnsProviderRequest"}}},"required":true},"responses":{"201":{"description":"DNS provider created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsProviderResponse"}}}},"400":{"description":"Invalid request or connection test failed"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{id}":{"get":{"tags":["DNS Providers"],"summary":"Get a DNS provider by ID","operationId":"get_dns_provider","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"DNS provider details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsProviderResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["DNS Providers"],"summary":"Update a DNS provider","description":"If new credentials are supplied, they are tested before the update is\npersisted (same as creation) -- otherwise a provider's credentials (and,\nfor Pebble, its target URL) could be swapped for something invalid or\nunsafe without ever going through validation.","operationId":"update_provider","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDnsProviderRequest"}}},"required":true},"responses":{"200":{"description":"DNS provider updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsProviderResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["DNS Providers"],"summary":"Delete a DNS provider","operationId":"delete_dns_provider","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"DNS provider deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{id}/domains":{"get":{"tags":["DNS Providers"],"summary":"List managed domains for a provider","operationId":"list_managed_domains","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of managed domains","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ManagedDomainResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["DNS Providers"],"summary":"Add a managed domain to a provider","operationId":"add_managed_domain","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddManagedDomainApiRequest"}}},"required":true},"responses":{"201":{"description":"Managed domain added","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedDomainResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{id}/test":{"post":{"tags":["DNS Providers"],"summary":"Test provider connection","operationId":"test_provider_connection","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionTestResult"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{id}/zones":{"get":{"tags":["DNS Providers"],"summary":"List zones available in a provider","operationId":"list_provider_zones","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of zones","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ZoneListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{provider_id}/domains/{domain}":{"delete":{"tags":["DNS Providers"],"summary":"Remove a managed domain","operationId":"remove_managed_domain","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Managed domain removed"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["DNS Providers"],"summary":"Update a managed domain's settings (hostname mode, sync opt-in, auto-manage).","operationId":"update_managed_domain","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateManagedDomainApiRequest"}}},"required":true},"responses":{"200":{"description":"Managed domain updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedDomainResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{provider_id}/domains/{domain}/apply-hostname-mode":{"post":{"tags":["DNS Providers"],"summary":"Apply a hostname mode to a managed domain (persist + optional DNS sync +\nroute reload).","operationId":"apply_hostname_mode","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplyHostnameModeRequest"}}},"required":true},"responses":{"200":{"description":"Hostname mode applied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HostnamePreviewResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions or token lacks zone access"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{provider_id}/domains/{domain}/hostname-preview":{"get":{"tags":["DNS Providers"],"summary":"Preview the impact of switching a managed domain's hostname mode.","operationId":"preview_hostname_mode","parameters":[{"name":"mode","in":"query","description":"Target mode: standard|flat","required":true,"schema":{"type":"string"}},{"name":"sync","in":"query","description":"Include DNS record changes","required":false,"schema":{"type":"boolean"}},{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Hostname mode preview","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HostnamePreviewResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{provider_id}/domains/{domain}/verify":{"post":{"tags":["DNS Providers"],"summary":"Verify a managed domain","operationId":"verify_managed_domain","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Domain verification result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedDomainResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]}},"/dns/lookup":{"get":{"tags":["DNS"],"summary":"Lookup DNS A records for a domain","operationId":"lookup_dns_a_records","parameters":[{"name":"domain","in":"query","description":"Domain name to lookup","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved DNS A records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsLookupResponse"}}}},"400":{"description":"Invalid domain name or lookup failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsLookupError"}}}}}}},"/domains":{"get":{"tags":["Domains"],"summary":"List all domains","operationId":"list_domains","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"search","in":"query","description":"Search domains by name (substring match)","required":false,"schema":{"type":["string","null"]},"example":"example.com"}],"responses":{"200":{"description":"Domains retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListDomainsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Domains"],"summary":"Create a new domain","description":"Creates a new domain and automatically requests a Let's Encrypt challenge.\nYou can specify the challenge type (HTTP-01 or DNS-01) in the request.\n\n- **HTTP-01**: Validates domain ownership by placing a file on your web server at `/.well-known/acme-challenge/`\n- **DNS-01**: Validates domain ownership by adding a TXT record to your DNS (required for wildcard domains)","operationId":"create_domain","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDomainRequest"}}},"required":true},"responses":{"201":{"description":"Domain created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/by-host/{hostname}":{"get":{"tags":["Domains"],"summary":"Get domain details by hostname","operationId":"get_domain_by_host","parameters":[{"name":"hostname","in":"path","description":"Domain hostname","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Domain details retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/by-host/{hostname}/cert-status":{"get":{"tags":["Domains"],"summary":"Get on-demand TLS certificate status for a hostname","description":"Returns the current cert lifecycle state for a single hostname (from the\n`domains` row) plus the most recent on-demand issuance attempt (from the\n`on_demand_cert_attempts` audit log). This is the operator's first-line\ndiagnostic, surfaced by `temps domain cert-status` (ADR-018 §5). Returns the\nhostname with `None` fields when no on-demand activity exists for it (never a\n404, so the CLI can render \"no attempts recorded\").","operationId":"get_on_demand_cert_status","parameters":[{"name":"hostname","in":"path","description":"Domain hostname","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"On-demand cert status retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CertStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/on-demand-certs":{"get":{"tags":["Domains"],"summary":"List on-demand TLS certificate attempts","description":"Returns rows from the append-only `on_demand_cert_attempts` audit log\n(ADR-018 §5), newest first, each joined with the current authoritative cert\nstate (`status`, `expiration_time`, `backoff_until`) from the `domains` row.\nThis backs the console \"Certificates\" surface. No certificate or private-key\nmaterial is returned — only audit metadata.","operationId":"list_on_demand_certs","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20}],"responses":{"200":{"description":"On-demand cert attempts retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListOnDemandCertsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain_id}/order":{"get":{"tags":["Domains"],"summary":"Get ACME order for a domain","operationId":"get_domain_order","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Order retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AcmeOrderResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Order not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Domains"],"summary":"Create or recreate ACME order for a domain","description":"Creates a new ACME order with Let's Encrypt for the specified domain.\nIf an order already exists, you should cancel it first using the cancel-order endpoint.\nReturns the challenge details that need to be fulfilled (DNS record or HTTP token).","operationId":"create_or_recreate_order","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Order created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainChallengeResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Domains"],"summary":"Cancel ACME order for a domain","description":"Cancels the current ACME order for a domain and clears all challenge data.\nThis allows you to start over with a new order if the previous one failed or got stuck.","operationId":"cancel_domain_order","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Order cancelled successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain_id}/order/finalize":{"post":{"tags":["Domains"],"summary":"Finalize ACME order for a domain","description":"Finalizes the ACME order by completing the challenge validation and requesting the certificate.\nThis should be called after the challenge has been set up (DNS record added or HTTP token served).","operationId":"finalize_order","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Order finalized successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain or order not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain_id}/setup-dns":{"post":{"tags":["Domains"],"summary":"Setup DNS challenge records automatically using a DNS provider","description":"This endpoint automatically creates the required DNS TXT records for ACME DNS-01 challenge\nvalidation using a configured DNS provider. The domain must have an active DNS challenge\npending (created via POST /domains/{id}/order with dns-01 challenge type).\n\nThis is similar to how email domain DNS records are auto-provisioned.","operationId":"setup_dns_challenge","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupDnsChallengeRequest"}}},"required":true},"responses":{"200":{"description":"DNS records created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupDnsChallengeResponse"}}}},"400":{"description":"Bad request - DNS provider not configured or no challenge pending"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain or DNS provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}":{"get":{"tags":["Domains"],"summary":"Get domain by ID","operationId":"get_domain_by_id","parameters":[{"name":"domain","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Domain retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Domains"],"summary":"Delete a domain","operationId":"delete_domain","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Domain deleted successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/challenge-token":{"get":{"tags":["Domains"],"summary":"Get challenge token for a domain (returns plain text token)","operationId":"get_challenge_token","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Challenge token retrieved successfully","content":{"text/plain":{"schema":{"type":"string"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Challenge not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/http-challenge-debug":{"get":{"tags":["Domains"],"summary":"Get HTTP challenge debug information","description":"Returns detailed debug information for HTTP-01 challenge including:\n- Whether a challenge exists for the domain\n- The challenge token and URL that Let's Encrypt will access\n- DNS resolution information showing where the domain currently points\n\nThis is useful for debugging why HTTP-01 challenges fail.","operationId":"get_http_challenge_debug","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Debug information retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpChallengeDebugResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/provision":{"post":{"tags":["Domains"],"summary":"Provision a domain certificate","operationId":"provision_domain","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Certificate provisioning initiated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProvisionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/renew":{"post":{"tags":["Domains"],"summary":"Renew domain certificate","description":"For HTTP-01 domains: Automatically renews the certificate\nFor DNS-01 domains (wildcards): Creates a new ACME order and returns challenge data","operationId":"renew_domain","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Certificate renewal initiated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProvisionResponse"}}}},"202":{"description":"DNS challenge created - manual action required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainChallengeResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/status":{"get":{"tags":["Domains"],"summary":"Check domain status","operationId":"check_domain_status","parameters":[{"name":"domain","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Domain status retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/drop/inspect":{"post":{"tags":["Projects"],"summary":"Inspect a source ZIP without creating a project or retaining the upload.","operationId":"inspect_drop_archive","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/DropArchiveUpload"}}},"required":true},"responses":{"200":{"description":"Detected deployable project roots","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DropInspectionResponse"}}}},"400":{"description":"Invalid or unsupported archive"}},"security":[{"bearer_auth":[]}]}},"/email-domains":{"get":{"tags":["Email Domains"],"summary":"List all email domains","operationId":"list_email_domains","parameters":[{"name":"provider_id","in":"query","description":"Only return domains belonging to this provider","required":false,"schema":{"type":["integer","null"],"format":"int32"}}],"responses":{"200":{"description":"List of email domains","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EmailDomainResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Email Domains"],"summary":"Create a new email domain","operationId":"create_email_domain","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEmailDomainRequest"}}},"required":true},"responses":{"201":{"description":"Domain created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailDomainWithDnsResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/by-domain/{domain}":{"get":{"tags":["Email Domains"],"summary":"Get an email domain by domain name with DNS records","operationId":"get_domain_by_name","parameters":[{"name":"domain","in":"path","description":"Domain name (e.g., 'mail.example.com')","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Email domain details with DNS records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailDomainWithDnsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/{id}":{"get":{"tags":["Email Domains"],"summary":"Get an email domain by ID with DNS records","operationId":"get_domain","parameters":[{"name":"id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Email domain details with DNS records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailDomainWithDnsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Email Domains"],"summary":"Delete an email domain","operationId":"delete_email_domain","parameters":[{"name":"id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Domain deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/{id}/dns-records":{"get":{"tags":["Email Domains"],"summary":"Get DNS records for an email domain","operationId":"get_domain_dns_records","parameters":[{"name":"id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"DNS records for the domain","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecordResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/{id}/setup-dns":{"post":{"tags":["Email Domains"],"summary":"Setup DNS records for an email domain using a configured DNS provider","operationId":"setup_dns","parameters":[{"name":"id","in":"path","description":"Email Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupDnsRequest"}}},"required":true},"responses":{"200":{"description":"DNS records setup result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupDnsResponse"}}}},"400":{"description":"Invalid request or DNS provider not configured"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/{id}/verify":{"post":{"tags":["Email Domains"],"summary":"Verify an email domain's DNS configuration","operationId":"verify_domain","parameters":[{"name":"id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Domain verification result with DNS records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailDomainWithDnsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-providers":{"get":{"tags":["Email Providers"],"summary":"List all email providers","operationId":"list_email_providers","responses":{"200":{"description":"List of email providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EmailProviderResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Email Providers"],"summary":"Create a new email provider","operationId":"create_email_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEmailProviderRequest"}}},"required":true},"responses":{"201":{"description":"Provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailProviderResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-providers/{id}":{"get":{"tags":["Email Providers"],"summary":"Get an email provider by ID","operationId":"get_email_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Email provider details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailProviderResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Email Providers"],"summary":"Delete an email provider","operationId":"delete_email_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Provider deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Email Providers"],"summary":"Update an email provider","description":"Partial update — any field left out keeps its current value. Most importantly,\nomitting the credential block (`ses_credentials`/`scaleway_credentials`/`smtp_credentials`)\npreserves the stored secret, so operators can rename a provider without re-typing\npasswords. `provider_type` is immutable; to switch providers, delete and recreate.","operationId":"update_email_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEmailProviderRequest"}}},"required":true},"responses":{"200":{"description":"Provider updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailProviderResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"409":{"description":"Provider type mismatch"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-providers/{id}/test":{"post":{"tags":["Email Providers"],"summary":"Test an email provider by sending a test email to the logged-in user","operationId":"test_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestEmailRequest"}}},"required":true},"responses":{"200":{"description":"Test email result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestEmailResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-providers/{id}/tracking/setup":{"post":{"tags":["Email Providers"],"summary":"One-click AWS-side setup of SES event tracking (SNS topic + webhook\nsubscription + SESv2 event destination), using the provider's stored\ncredentials.","operationId":"setup_email_tracking","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Setup completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailTrackingSetupResponse"}}}},"400":{"description":"Provider does not support event tracking"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"502":{"description":"An AWS call failed — the response detail names the failed step"}},"security":[{"bearer_auth":[]}]}},"/email-providers/{id}/tracking/status":{"get":{"tags":["Email Providers"],"summary":"Live status of SES event tracking for a provider","operationId":"get_email_tracking_status","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Event tracking status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailTrackingStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/emails":{"get":{"tags":["Emails"],"summary":"List emails with optional filtering","operationId":"list_emails","parameters":[{"name":"domain_id","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"project_id","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"status","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"from_address","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"page","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"page_size","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"List of emails","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedEmailsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Emails"],"summary":"Send an email","operationId":"send_email","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendEmailRequestBody"}}},"required":true},"responses":{"201":{"description":"Email sent successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendEmailResponseBody"}}}},"400":{"description":"Invalid request or domain not verified"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/emails/events":{"get":{"tags":["Email Tracking"],"summary":"GET /emails/events","operationId":"get_global_events","parameters":[{"name":"event_type","in":"query","description":"Filter by event type (open, click)","required":false,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Paginated tracking events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedEventsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/emails/events/stats":{"get":{"tags":["Email Tracking"],"summary":"GET /emails/events/stats","operationId":"get_global_event_stats","responses":{"200":{"description":"Global tracking statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlobalEventStatsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/emails/stats":{"get":{"tags":["Emails"],"summary":"Get email statistics","operationId":"get_email_stats","parameters":[{"name":"domain_id","in":"query","description":"Optional domain ID to filter stats","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Email statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailStatsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/emails/validate":{"post":{"tags":["Email Validation"],"summary":"Validate an email address","operationId":"validate_email","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateEmailRequest"}}},"required":true},"responses":{"200":{"description":"Email validation result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateEmailResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/emails/{email_id}/track/click/{link_index}":{"get":{"tags":["Email Tracking"],"summary":"Track email link click - redirects to original URL","description":"This endpoint replaces original links in tracked emails.\nNo authentication required - it's called when the recipient clicks a link.","operationId":"track_click","parameters":[{"name":"email_id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}},{"name":"link_index","in":"path","description":"Link index","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"302":{"description":"Redirect to original URL"},"404":{"description":"Link not found"}}}},"/emails/{email_id}/track/open":{"get":{"tags":["Email Tracking"],"summary":"Track email open - returns a 1x1 transparent GIF","description":"This endpoint is embedded as an tag in emails.\nNo authentication required - it's called by the email client.","operationId":"track_open","parameters":[{"name":"email_id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"1x1 transparent tracking pixel"},"404":{"description":"Email not found"}}}},"/emails/{id}":{"get":{"tags":["Emails"],"summary":"Get an email by ID","operationId":"get_email","parameters":[{"name":"id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Email details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Email not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/emails/{id}/tracking":{"get":{"tags":["Email Tracking"],"summary":"Get email tracking summary","operationId":"get_email_tracking","parameters":[{"name":"id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Tracking summary","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailTrackingResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Email not found"}},"security":[{"bearer_auth":[]}]}},"/emails/{id}/tracking/events":{"get":{"tags":["Email Tracking"],"summary":"Get email tracking events","operationId":"get_email_events","parameters":[{"name":"id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}},{"name":"event_type","in":"query","description":"Filter by event type (open, click)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Tracking events","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TrackingEventResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Email not found"}},"security":[{"bearer_auth":[]}]}},"/emails/{id}/tracking/links":{"get":{"tags":["Email Tracking"],"summary":"Get tracked links for an email","operationId":"get_email_links","parameters":[{"name":"id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Tracked links","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TrackedLinkResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Email not found"}},"security":[{"bearer_auth":[]}]}},"/external-services":{"get":{"tags":["External Services"],"summary":"Get all external services","operationId":"list_services","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of external services","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}}},"500":{"description":"Internal server error"}}},"post":{"tags":["External Services"],"summary":"Create new external service","operationId":"create_service","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateExternalServiceRequest"}}},"required":true},"responses":{"201":{"description":"Service created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}}}},"/external-services/available-containers":{"get":{"tags":["External Services"],"summary":"List available Docker containers that can be imported as services","operationId":"list_available_containers","responses":{"200":{"description":"List of available containers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AvailableContainerInfo"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/by-slug/{slug}":{"get":{"tags":["External Services"],"summary":"Get external service details by slug","operationId":"get_service_by_slug","parameters":[{"name":"slug","in":"path","description":"External service slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"External service details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceDetails"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/health-status-batch":{"get":{"tags":["External Services"],"summary":"Current health status for many services at once","description":"Powers the status dot on the Storage list page. Pass a comma-separated\nlist of service IDs via `?ids=1,2,3`. Omit to get every service.","operationId":"list_service_health_statuses","parameters":[{"name":"ids","in":"query","description":"Comma-separated service IDs. Omit for all services.","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Batch of current health statuses","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceHealthStatusBatchResponse"}}}},"500":{"description":"Internal server error"}}}},"/external-services/import":{"post":{"tags":["External Services"],"summary":"Import an existing Docker container as a managed external service","operationId":"import_external_service","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportExternalServiceRequest"}}},"required":true},"responses":{"201":{"description":"Service imported successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/projects/{project_id}":{"get":{"tags":["External Services"],"summary":"List services linked to a project","operationId":"list_project_services","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of services linked to project","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectServiceInfo"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/external-services/projects/{project_id}/environment":{"get":{"tags":["External Services"],"summary":"Get all environment variables for all services linked to a project","operationId":"get_project_service_environment_variables","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Map of service IDs to their environment variables","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"propertyNames":{"type":"integer","format":"int32"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/external-services/providers/metadata":{"get":{"tags":["External Services"],"summary":"Get provider metadata (display names, icons, descriptions)","operationId":"get_providers_metadata","responses":{"200":{"description":"List of provider metadata","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderMetadata"}}}}},"500":{"description":"Internal server error"}}}},"/external-services/providers/metadata/{service_type}":{"get":{"tags":["External Services"],"summary":"Get metadata for a specific provider","operationId":"get_provider_metadata","parameters":[{"name":"service_type","in":"path","description":"Service type (mongodb, postgres, redis, s3)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Provider metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderMetadata"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}}}},"/external-services/types":{"get":{"tags":["External Services"],"summary":"Get available service types","operationId":"get_service_types","responses":{"200":{"description":"List of available service types","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ServiceTypeRoute"}}}}},"500":{"description":"Internal server error"}}}},"/external-services/types/{service_type}/parameters":{"get":{"tags":["External Services"],"summary":"Get parameter schema for a specific service type","operationId":"get_service_type_parameters","parameters":[{"name":"service_type","in":"path","description":"Service type","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Service type parameter schema"},"404":{"description":"Service type not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}":{"get":{"tags":["External Services"],"summary":"Get external service details","operationId":"get_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"External service details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceDetails"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}},"put":{"tags":["External Services"],"summary":"Update external service","operationId":"update_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateExternalServiceRequest"}}},"required":true},"responses":{"200":{"description":"Service updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Invalid request"},"404":{"description":"Service not found"},"409":{"description":"A major upgrade is in progress for this service"},"500":{"description":"Internal server error"}}},"delete":{"tags":["External Services"],"summary":"Delete external service","operationId":"delete_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Service deleted successfully"},"400":{"description":"Cannot delete: service is still linked to projects"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/cluster-health":{"get":{"tags":["External Services"],"summary":"Per-member health for a Postgres HA cluster.","description":"Reads pg_auto_failover's `pgautofailover.node` table from the cluster's\nmonitor (TLS, autoctl_node) and joins each member with its\n`pg_stat_replication` row from the current primary. Returns one row per\ndata member with role/state, sync state, and replay lag.\n\nReturns `200` with `monitor_error` set when the monitor is briefly\nunreachable (UI surfaces it as a banner above the table); the table\nitself is empty in that case. Returns `400` for non-cluster services.","operationId":"get_cluster_health","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Per-member cluster health report","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClusterHealthReportResponse"}}}},"400":{"description":"Service is not a cluster"},"401":{"description":"Unauthorized"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/health-check":{"post":{"tags":["External Services"],"summary":"Run a health check for one service right now","description":"Triggers the same engine-specific probe as the background monitor, writes\na history row, updates the denormalized fields on `external_services`, and\nfires alerts on the Nth consecutive failure (so consecutive-failure state\nstays honest). Returns the fresh snapshot the UI can display immediately.","operationId":"trigger_service_health_check","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Fresh health snapshot after probing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceHealthResponse"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"},"503":{"description":"Health monitor not running on this node"}}}},"/external-services/{id}/health-status":{"get":{"tags":["External Services"],"summary":"Persisted health status for an external service","description":"Returns the latest health probe result recorded by\n`ExternalServiceHealthMonitor`, plus recent check history for sparklines\nand a 24-hour uptime percentage. Safe to poll from the UI every 30s.","operationId":"get_service_health_status","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Max number of recent checks (default 50, max 200)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Current health + recent history","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceHealthResponse"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/members":{"post":{"tags":["External Services"],"summary":"Begin adding a single new member to a running cluster.","description":"Currently only `replica` members can be added at runtime. The\nresponse is **202 Accepted** as soon as the validation passes and\nthe placeholder `service_members` row is inserted. The actual\ncontainer provisioning + DNS registration runs in the background;\npoll `GET /external-services/{id}/members/{member_id}` to watch\n`provisioning_step` advance through the phases.","operationId":"add_cluster_member","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddClusterMemberRequest"}}},"required":true},"responses":{"202":{"description":"Cluster member provisioning started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceMemberInfo"}}}},"400":{"description":"Validation failed (wrong topology, status, or role)"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/members/{member_id}":{"get":{"tags":["External Services"],"summary":"Get a single cluster member's current state.","description":"Used by the add-member page to poll the row every second while the\nbackground provisioning task walks through its phases. The\n`provisioning_step` field advances through `inserting_row` →\n`provisioning_container` → `registering_dns` → `done` (or `failed`\nwith `provisioning_error` set).","operationId":"get_cluster_member","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"member_id","in":"path","description":"Cluster member ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Cluster member details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceMemberInfo"}}}},"404":{"description":"Service or member not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["External Services"],"summary":"Remove a single member from a running cluster.","description":"Refuses to remove the monitor (singleton), the current primary\n(failover first), or any member if the cluster would drop below the\n2-data-member quorum required for HA. Stops + removes the container,\ndeletes the row, and drops the Tier-2 DNS record.","operationId":"remove_cluster_member","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"member_id","in":"path","description":"Cluster member ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Cluster member removed"},"400":{"description":"Validation failed (monitor, primary, or quorum violation)"},"404":{"description":"Service or member not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/members/{member_id}/promote":{"post":{"tags":["External Services"],"summary":"Promote a replica to primary by triggering a pg_auto_failover\nfailover. The monitor demotes the current primary and the chosen\nreplica transitions to primary; the role reconciler then refreshes\nthe role-aliased VIPs (≤30s).","operationId":"promote_cluster_member","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"member_id","in":"path","description":"Cluster member ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Promotion initiated"},"400":{"description":"Validation failed (monitor, already primary, not running, etc.)"},"404":{"description":"Service or member not found"},"500":{"description":"pg_autoctl perform promotion failed"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics":{"get":{"tags":["Metrics"],"summary":"Fetch a time-series range for a single metric on an external service.","description":"Pass `percentile` to compute a histogram quantile instead of a plain\ngauge/counter average.","operationId":"ExternalServiceMetricsGetRange","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric","in":"query","description":"Metric name, e.g. `\"pg.connections_active\"`.","required":true,"schema":{"type":"string"}},{"name":"range","in":"query","description":"Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`.","required":false,"schema":{"type":"string"}},{"name":"percentile","in":"query","description":"Optional histogram percentile (0–100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile.","required":false,"schema":{"type":["number","null"],"format":"double"}}],"responses":{"200":{"description":"Metric time series data points","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MetricDataPoint"}}}}},"400":{"description":"Invalid query parameters"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/alert-rules":{"get":{"tags":["Metrics"],"summary":"List all monitoring alert rules for an external service.","operationId":"ExternalServiceMetricsGetAlertRules","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of alert rules","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ServiceAlertRuleResponse"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Metrics"],"summary":"Create a monitoring alert rule for an external service.","description":"If metric collection is enabled and the service engine has default rules,\nseeding is idempotent (ON CONFLICT DO NOTHING).","operationId":"ExternalServiceMetricsCreateAlertRule","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceCreateAlertRuleRequest"}}},"required":true},"responses":{"201":{"description":"Alert rule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceAlertRuleResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/alert-rules/{rule_id}":{"put":{"tags":["Metrics"],"summary":"Update an existing monitoring alert rule for an external service.","operationId":"ExternalServiceMetricsUpdateAlertRule","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceUpdateAlertRuleRequest"}}},"required":true},"responses":{"200":{"description":"Updated alert rule","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceAlertRuleResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Metrics"],"summary":"Delete a monitoring alert rule for an external service.","operationId":"ExternalServiceMetricsDeleteAlertRule","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Alert rule deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/by-database":{"get":{"tags":["Metrics"],"summary":"Return the latest per-database metric values for a Postgres service.","description":"Groups `pg_stat_database` / size metrics by `datname` so the UI can show a\nbreakdown table (each database with its own size, cache-hit ratio, etc.)\nrather than collapsing every database into one value.","operationId":"ExternalServiceMetricsByDatabase","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Per-database metric breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatabaseMetricsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics not available"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/enable":{"patch":{"tags":["Metrics"],"summary":"Enable or disable metric collection for an external service.","description":"When `enabled=true`, seeds the default alert rules for the service's engine\nvia [`temps_monitoring::seed_default_rules`] (idempotent).","operationId":"ExternalServiceMetricsToggle","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToggleServiceMetricsRequest"}}},"required":true},"responses":{"200":{"description":"Metrics toggle applied"},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/latest":{"get":{"tags":["Metrics"],"summary":"Fetch the most-recent value for every tracked metric on an external service.","operationId":"ExternalServiceMetricsGetLatest","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Map of metric name to latest value","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"number","format":"double"},"propertyNames":{"type":"string"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/status":{"get":{"tags":["Metrics"],"summary":"Return the freshness status (last-received timestamp) for a service.","description":"Cheap O(1) lookup against `service_metrics_status` — used by the UI to show\n\"last received at …\" without scanning the metrics hypertable.","operationId":"ExternalServiceMetricsStatus","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Metrics freshness status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetricsStatusResponse"}}}},"503":{"description":"Metrics not available"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/parameters/{param_name}":{"get":{"tags":["External Services"],"summary":"Reveal one sensitive service parameter. Service detail responses never\ncontain plaintext values; every successful reveal is recorded separately.","operationId":"reveal_service_parameter","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"param_name","in":"path","description":"Sensitive parameter name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sensitive parameter value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensitiveValueResponse"}}}},"400":{"description":"Parameter is not sensitive"},"403":{"description":"Caller cannot access a project linked to this service"},"404":{"description":"Service or parameter not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/preview-environment-masked":{"get":{"tags":["External Services"],"summary":"Get environment variables preview with masked sensitive values","operationId":"get_service_preview_environment_variables_masked","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Preview of environment variables with sensitive values masked as ***","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/preview-environment-names":{"get":{"tags":["External Services"],"summary":"Get environment variable names preview (safe - no sensitive values)","operationId":"get_service_preview_environment_variable_names","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environment variable names that would be provided","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"}}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/projects":{"get":{"tags":["External Services"],"summary":"List projects linked to service","operationId":"list_service_projects","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of linked projects","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectServiceInfo"}}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["External Services"],"summary":"Link service to project","operationId":"link_service_to_project","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkServiceRequest"}}},"required":true},"responses":{"201":{"description":"Service linked to project successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectServiceInfo"}}}},"404":{"description":"Service or project not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/projects/{project_id}":{"delete":{"tags":["External Services"],"summary":"Unlink service from project","operationId":"unlink_service_from_project","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Service unlinked from project successfully"},"404":{"description":"Service link not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/projects/{project_id}/environment":{"get":{"tags":["External Services"],"summary":"Get all environment variables for a service-project pair","operationId":"get_service_environment_variables","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environment variables","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentVariableInfo"}}}}},"404":{"description":"Service or project not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/projects/{project_id}/environment/{var_name}":{"get":{"tags":["External Services"],"summary":"Get specific environment variable for a service-project pair","operationId":"get_service_environment_variable","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"var_name","in":"path","description":"Environment variable name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Environment variable value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableInfo"}}}},"403":{"description":"Plaintext secret access is not permitted"},"404":{"description":"Service, project, or variable not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/resources":{"patch":{"tags":["External Services"],"summary":"Update a service's resource limits (memory, CPU caps).","description":"Persists the new caps to the encrypted config AND live-applies them\nvia Docker's update API. Memory and CPU can be hot-changed without a\nrestart on running containers; stopped containers also accept the\nupdate and pick up the new caps on next start.\n\nPass `null` (or omit) any field to leave it unlimited. A request where\nevery field is `null` removes any existing limits.\n\nThe response includes a per-container `applied[]` list so the caller\ncan tell which members got the update and which were skipped (e.g.,\ncontainer not yet created, or `docker update` rejected because the\nnew memory cap is below current usage).","operationId":"update_service_resources","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceResourceLimits"}}},"required":true},"responses":{"200":{"description":"Updated resource limits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceLimitsUpdateResponse"}}}},"400":{"description":"Invalid resource limits"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/restore":{"post":{"tags":["Restore"],"operationId":"start_restore","parameters":[{"name":"id","in":"path","description":"External service id (source for the restore)","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartRestoreRequest"}}},"required":true},"responses":{"202":{"description":"Restore run started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestoreRunView"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup or service not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/restore-capabilities":{"get":{"tags":["Restore"],"operationId":"get_restore_capabilities","parameters":[{"name":"id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Capabilities declared by the service","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestoreCapabilitiesResponse"}}}},"404":{"description":"Service not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/restore-plan":{"post":{"tags":["Restore"],"operationId":"plan_restore","parameters":[{"name":"id","in":"path","description":"Target service id","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartRestoreRequest"}}},"required":true},"responses":{"200":{"description":"Preview of what the restore will do","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestorePlan"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup or service not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/restore-runs":{"get":{"tags":["Restore"],"operationId":"list_restore_runs_for_service","parameters":[{"name":"id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Recent restore runs for the service","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RestoreRunView"}}}}}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/retry":{"post":{"tags":["External Services"],"summary":"Retry a failed cluster service initialization.","description":"Cleans up any leftover containers from the previous attempt and\nre-runs cluster initialization with the provided member specifications.","operationId":"retry_cluster","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RetryClusterRequest"}}},"required":true},"responses":{"200":{"description":"Cluster retry initiated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Service is not a failed cluster"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/runtime":{"get":{"tags":["External Services"],"summary":"Inspect a service's container(s): status, restart count, OOM-killed flag,\nexit code, and the cgroup limits actually applied.","operationId":"get_service_runtime","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Container runtime snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceRuntimeReport"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/start":{"post":{"tags":["External Services"],"summary":"Start an external service","operationId":"start_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Service started successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"404":{"description":"Service not found"},"409":{"description":"A Postgres major upgrade is in progress for this service"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/stats":{"get":{"tags":["External Services"],"summary":"Sample current CPU/memory usage from each of a service's containers.\nOne-shot sample, no streaming. Cheap to call (single Docker round-trip\nper member) so the UI can poll on a 5–10s interval.","operationId":"get_service_stats","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Container stats snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceStatsReport"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/stop":{"post":{"tags":["External Services"],"summary":"Stop an external service","operationId":"stop_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Service stopped successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/upgrade":{"post":{"tags":["External Services"],"summary":"Upgrade external service to new Docker image with data migration\nThis endpoint uses service-specific upgrade procedures (e.g., pg_upgrade for PostgreSQL)","operationId":"upgrade_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpgradeExternalServiceRequest"}}},"required":true},"responses":{"200":{"description":"Service upgraded successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Invalid request or upgrade not supported"},"404":{"description":"Service not found"},"409":{"description":"A major upgrade is already in progress for this service"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/wal-health":{"get":{"tags":["External Services"],"summary":"Postgres WAL & archive health snapshot","description":"Returns the latest WAL/archive health snapshot recorded by the background\nhealth monitor for a Postgres external service. Powers the warning banner\non the service detail page when the disk is filling up due to stale\nreplication slots, archive backlog, or misconfigured `archive_command`.\n\nReturns 404 when no snapshot exists yet (probe hasn't run, or the service\nisn't Postgres).","operationId":"getPostgresWalHealth","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Latest WAL health snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostgresWalHealth"}}}},"404":{"description":"Service not found, or no WAL snapshot available"},"500":{"description":"Internal server error"}}}},"/external-services/{service_id}/pg-stat-statements/enable":{"post":{"tags":["External Services"],"summary":"Enable `pg_stat_statements` on a standalone Postgres service.","description":"Stops the container and restarts it so that the\n`shared_preload_libraries=pg_stat_statements` CMD flag (baked into every\nnew standalone Postgres container) takes effect. The named data volume is\nreused unchanged — no data is lost.\n\n**Clustered (HA) services are rejected** with 422 — a blind single-container\nrestart bypasses controlled failover. For clustered services the response\nbody describes the manual rolling-restart steps.\n\nConfirmation is the caller's responsibility (UI dialog / CLI `--yes` flag)\nbefore invoking this endpoint.","operationId":"ExternalServiceEnablePgStatStatements","parameters":[{"name":"service_id","in":"path","description":"ID of the provisioned standalone Postgres service","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Container restarted; pg_stat_statements now active","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnablePgStatStatementsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions (requires external_services:write)"},"404":{"description":"Service not found"},"422":{"description":"Service is not standalone Postgres (cluster or wrong type)"},"500":{"description":"Restart failed"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/pg-stat-statements/reset":{"post":{"tags":["External Services"],"summary":"Reset all statistics accumulated by `pg_stat_statements` for a Postgres\nservice. This affects every user, database, and normalized query tracked by\nthe target Postgres instance and cannot be undone.","operationId":"ExternalServiceResetPgStatStatements","parameters":[{"name":"service_id","in":"path","description":"ID of the provisioned Postgres service","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"Explicit confirmation of the global, irreversible reset","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPgStatStatementsRequest"}}},"required":true},"responses":{"200":{"description":"All accumulated pg_stat_statements statistics cleared","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPgStatStatementsResponse"}}}},"400":{"description":"Missing or invalid reset confirmation"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions (requires external_services:write)"},"404":{"description":"Service not found"},"422":{"description":"Service is not Postgres"},"502":{"description":"Target Postgres rejected or failed the reset operation"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/pg-stat-statements/slow-queries":{"get":{"tags":["External Services"],"operationId":"get_slow_queries","parameters":[{"name":"service_id","in":"path","description":"ID of the provisioned Postgres service","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based). Defaults to 1.","required":false,"schema":{"type":["integer","null"],"format":"int32","minimum":0}},{"name":"page_size","in":"query","description":"Number of rows per page (1–100). Defaults to 20.","required":false,"schema":{"type":["integer","null"],"format":"int32","minimum":0}},{"name":"sort_by","in":"query","description":"Column to sort by: one of `calls`, `total_exec_time_ms`,\n`mean_exec_time_ms`, `rows`, `cache_hit_ratio`. Defaults to\n`mean_exec_time_ms`. Applied server-side so ordering stays\nconsistent across pages.","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","description":"Sort direction: `asc` or `desc`. Defaults to `desc`.","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Paginated slow queries from pg_stat_statements","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SlowQueriesResponse"}}}},"400":{"description":"Invalid pagination or sort parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions (requires external_services:read)"},"404":{"description":"Service not found"},"422":{"description":"Service is not a Postgres service"},"503":{"description":"pg_stat_statements extension not available (container restart required)"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/ai-data-access":{"get":{"tags":["External Services - Query"],"summary":"Report whether the AI assistant may read row data from this service.","description":"Always answers (rather than 404-ing when disabled) so the console can render\nthe capability with an \"off — here's how to turn it on\" state instead of\nhiding it, and so the agent can tell \"not set up\" apart from \"not supported\".","operationId":"get_ai_data_access","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Current AI data access setting","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiDataAccessResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service not found"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["External Services - Query"],"summary":"Enable or disable AI assistant access to this service's row data.","description":"Off by default. Row contents can include password hashes, API tokens and\npersonal data, and enabling this sends them to the configured AI provider —\nso it is a deliberate, audited, per-service decision by the operator.","operationId":"set_ai_data_access","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToggleAiDataAccessRequest"}}},"required":true},"responses":{"200":{"description":"Setting applied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiDataAccessResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers":{"get":{"tags":["External Services - Query"],"summary":"List containers at the root level (databases, keyspaces, etc.)","operationId":"list_root_containers","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of root containers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ContainerResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}":{"get":{"tags":["External Services - Query"],"summary":"List containers at a specific path\nPath segments are separated by forward slashes\nExample: /external-services/1/query/containers/mydb lists schemas in database \"mydb\"","operationId":"list_containers_at_path","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of containers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ContainerResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/entities":{"get":{"tags":["External Services - Query"],"summary":"List entities (tables, collections, etc.) in a container\nExample: /external-services/1/query/containers/mydb/public/entities lists tables in the public schema","operationId":"list_entities","parameters":[{"name":"limit","in":"query","description":"Maximum number of entities to return (default: 100, max: 1000)","required":false,"schema":{"type":"integer","minimum":0}},{"name":"token","in":"query","description":"Continuation token for pagination","required":false,"schema":{"type":"string"}},{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated list of entities","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedEntitiesResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/entities/{entity}":{"get":{"tags":["External Services - Query"],"summary":"Get detailed information about an entity (table schema)","operationId":"get_entity_info","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}},{"name":"entity","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Entity details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntityInfoResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service, container, or entity not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/entities/{entity}/data":{"get":{"tags":["External Services - Query"],"summary":"Read rows from an entity (read-only `GET`; see [`query_data`] for the\n`POST` form used by the console).","description":"Gated for AI callers by the service's `ai_data_access` opt-in — see\n[`temps_core::ai_tool_call::AiToolCall`].","operationId":"read_entity_rows","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","description":"Container path, slash-separated (e.g. `mydb/public`)","required":true,"schema":{"type":"string"}},{"name":"entity","in":"path","description":"Table, collection, key or object name","required":true,"schema":{"type":"string"}},{"name":"filter","in":"query","description":"JSON-encoded backend-specific filter","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Maximum rows to return","required":false,"schema":{"type":"integer","minimum":0}},{"name":"offset","in":"query","description":"Rows to skip","required":false,"schema":{"type":"integer","minimum":0}},{"name":"sort_by","in":"query","description":"Field to sort by","required":false,"schema":{"type":"string"}},{"name":"sort_order","in":"query","description":"asc or desc","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Query results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryDataResponse"}}}},"400":{"description":"Invalid query or filter"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions, or AI data access not enabled for this service"},"404":{"description":"Service, container, or entity not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["External Services - Query"],"summary":"Query data from an entity with optional filters, pagination, and sorting","operationId":"query_data","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}},{"name":"entity","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryDataRequest"}}},"required":true},"responses":{"200":{"description":"Query results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryDataResponse"}}}},"400":{"description":"Invalid query"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service, container, or entity not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/entities/{entity}/download":{"get":{"tags":["External Services - Query"],"summary":"Download an object (S3 only) as a streaming response","operationId":"download_object","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}},{"name":"entity","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Object data stream","content":{"application/octet-stream":{}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Object not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/info":{"get":{"tags":["External Services - Query"],"summary":"Get information about a specific container","operationId":"get_query_container_info","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/explorer-support":{"get":{"tags":["External Services - Query"],"summary":"Check if a service supports query explorer functionality","operationId":"check_explorer_support","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Explorer support information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExplorerSupportResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades":{"get":{"tags":["Postgres Upgrades"],"summary":"List recent upgrades for a single service (newest first, page size 50).","operationId":"list_pg_upgrades","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Recent upgrades","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}}},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Postgres Upgrades"],"summary":"Start a new PostgreSQL major-version upgrade for a service.","operationId":"start_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartPgUpgradeRequest"}}},"required":true},"responses":{"201":{"description":"Upgrade started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"400":{"description":"Invalid request"},"409":{"description":"An upgrade is already running for this service"},"412":{"description":"No default S3 source configured"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}":{"get":{"tags":["Postgres Upgrades"],"summary":"Get a single upgrade by id, scoped to a service.","operationId":"get_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Upgrade","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"404":{"description":"Not found"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}/cancel":{"post":{"tags":["Postgres Upgrades"],"summary":"Cancel an in-flight upgrade. The orchestrator stops at its next phase\nboundary; already-terminal upgrades return 409.","operationId":"cancel_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Cancellation requested","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Upgrade already terminal"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}/logs":{"get":{"tags":["Postgres Upgrades"],"summary":"Get the accumulated JSONL log content for an upgrade (for dashboard display).","operationId":"get_pg_upgrade_logs","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Log content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeLogResponse"}}}},"404":{"description":"Not found"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}/retry":{"post":{"tags":["Postgres Upgrades"],"summary":"Retry a failed upgrade. The phase is preserved, so the state machine\nresumes from where it failed.","operationId":"retry_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Retry scheduled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"400":{"description":"Upgrade is not in a retriable state"},"404":{"description":"Not found"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}/rollback":{"post":{"tags":["Postgres Upgrades"],"summary":"Roll a completed upgrade back to its pre-upgrade PGDATA volume and old image.\nOnly valid while the rollback retention window is still open (see\n`ROLLBACK_RETENTION_DAYS`) and the rollback volume has not been swept.","operationId":"rollback_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Rollback complete","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Upgrade is not in a rollbackable state (not completed, volume swept, or retention expired)"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/files/{file_path}":{"get":{"tags":["Files"],"operationId":"get_file","parameters":[{"name":"file_path","in":"path","description":"Relative path to the file from static directory","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"File content retrieved successfully","content":{"application/octet-stream":{}}},"401":{"description":"Authentication required"},"403":{"description":"Access denied - path outside static directory or insufficient permissions"},"404":{"description":"File not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/flags/exposure":{"post":{"tags":["Feature Flags"],"summary":"Record which flags a running app actually evaluated.","description":"This is what makes `last_evaluated_at` mean something. The snapshot\nendpoint hands the SDK every flag in the environment and evaluation then\nhappens locally, so the control plane cannot otherwise tell a flag that is\nreferenced by live code from one nothing has called in a year. Stamping on\nsnapshot fetch would mark every flag as freshly used and defeat the point.\n\nScope comes from the deployment token, never the body. The endpoint writes\nonly `last_evaluated_at` — never a flag's value — so \"a deployment token\ncannot change what a flag serves\" still holds despite this being a write.","operationId":"record_flag_exposure","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecordExposureRequest"}}},"required":true},"responses":{"200":{"description":"Exposure recorded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecordExposureResponse"}}}},"400":{"description":"Deployment token required"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/flags/snapshot":{"get":{"tags":["Feature Flags"],"summary":"Every flag for the caller's environment, collapsed to what the evaluator\nneeds.","description":"Scope comes from the deployment token, never from the URL: a container's\nbaked-in `TEMPS_API_TOKEN` identifies exactly one project (and usually one\nenvironment), so a compromised app cannot read another tenant's flags by\nchanging a path parameter.\n\nSupports `If-None-Match`, so the SDK's background poll is a 304 in the\ncommon case.","operationId":"get_flag_snapshot","parameters":[{"name":"environment_id","in":"query","description":"Required only when the calling token is project-wide rather than scoped\nto a single environment.","required":false,"schema":{"type":["integer","null"],"format":"int32"}}],"responses":{"200":{"description":"Snapshot for the environment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagSnapshotResponse"}}}},"304":{"description":"Snapshot unchanged"},"400":{"description":"Environment could not be determined"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/geo/{ip}":{"get":{"tags":["geo"],"summary":"Get geolocation information for an IP address","operationId":"get_ip_geolocation","parameters":[{"name":"ip","in":"path","description":"IP address to geolocate (IPv4 or IPv6)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Geolocation information retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeoLocationResponse"}}}},"400":{"description":"Invalid IP address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"IP address not found in database","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/git-connections":{"get":{"tags":["Git Providers"],"summary":"List user's git provider connections","operationId":"list_connections","parameters":[{"name":"page","in":"query","description":"Page number for pagination (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Number of items per page (default: 30, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"sort","in":"query","description":"Sort field (created_at, updated_at, account_name)","required":false,"schema":{"type":"string"}},{"name":"direction","in":"query","description":"Sort direction (asc, desc), default: desc","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of connections","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionListResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}":{"delete":{"tags":["Git Providers"],"summary":"Permanently delete a git provider connection","operationId":"delete_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Connection deleted successfully"},"400":{"description":"Connection is in use by projects and cannot be deleted"},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/activate":{"post":{"tags":["Git Providers"],"summary":"Activate a git provider connection","operationId":"activate_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection activated successfully"},"400":{"description":"Provider is deactivated and connection cannot be activated"},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/deactivate":{"post":{"tags":["Git Providers"],"summary":"Deactivate a git provider connection","operationId":"deactivate_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection deactivated successfully"},"400":{"description":"Connection is in use by projects and cannot be deactivated"},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/health-check":{"post":{"tags":["Git Provider Connections"],"summary":"Run an on-demand health check for a git connection.","description":"Probes the upstream (GitHub App, PAT, or OAuth token), persists the result,\nand fires admin notifications on status transitions. Returns the updated\nconnection.","operationId":"run_connection_health_check","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Health check completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/repositories":{"get":{"tags":["Git Providers"],"summary":"List repositories for a specific connection","description":"Fetches repositories from the connected git provider with support for pagination, search, and filtering.\nThis endpoint calls the provider's API directly to get the most up-to-date repository list.","operationId":"list_repositories_by_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"sort","in":"query","description":"Sort field (name, created_at, updated_at, stars, etc.)","required":false,"schema":{"type":"string"}},{"name":"direction","in":"query","description":"Sort direction (asc, desc)","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Search term to filter repositories","required":false,"schema":{"type":"string"}},{"name":"owner","in":"query","description":"Filter by repository owner","required":false,"schema":{"type":"string"}},{"name":"language","in":"query","description":"Filter by programming language","required":false,"schema":{"type":"string"}},{"name":"private","in":"query","description":"Filter by private status (true/false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of repositories","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/sync":{"post":{"tags":["Git Providers"],"summary":"Start a repository sync for a connection","description":"Kicks off a background sync of the connection's repositories from the\nprovider. Returns `202 Accepted` immediately — the caller should poll\nthe connection endpoint for `syncing` / `synced_repository_count`\nupdates rather than waiting on this response. The sync is guarded by\na hard deadline and always releases the `syncing` flag on exit, so a\nclient that disconnects mid-sync will not leave the connection stuck.","operationId":"sync_repositories","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Repository sync started in background","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositorySyncStartedResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"409":{"description":"Sync already in progress"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/update-token":{"post":{"tags":["Git Provider Connections"],"summary":"Update access token for a connection (when tokens expire or are rotated)","operationId":"update_connection_token","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTokenRequest"}}},"required":true},"responses":{"200":{"description":"Token updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTokenResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/validate":{"get":{"tags":["Git Provider Connections"],"summary":"Validate a connection by testing the access token","operationId":"validate_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection validation result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers":{"get":{"tags":["Git Providers"],"summary":"List all git providers","operationId":"list_git_providers","responses":{"200":{"description":"List of providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderResponse"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Git Providers"],"summary":"Create a new git provider configuration","operationId":"create_git_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProviderRequest"}}},"required":true},"responses":{"201":{"description":"Provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/bitbucket":{"post":{"tags":["Git Providers"],"summary":"Create a Bitbucket Cloud provider with access token or app password authentication","operationId":"create_bitbucket_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBitbucketRequest"}}},"required":true},"responses":{"201":{"description":"Bitbucket provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request — missing or invalid auth fields"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/generic":{"post":{"tags":["Git Providers"],"summary":"Create a Generic git provider for self-hosted or arbitrary HTTPS git hosts.\nSupports public repositories (no token) and private repositories (token-based).","operationId":"create_generic_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGenericRequest"}}},"required":true},"responses":{"201":{"description":"Generic git provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request — invalid clone URL or missing fields"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/gitea/pat":{"post":{"tags":["Git Providers"],"summary":"Create a Gitea Personal Access Token provider","operationId":"create_gitea_pat_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGiteaPATRequest"}}},"required":true},"responses":{"201":{"description":"Gitea PAT provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request — invalid URL or missing fields"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/github/pat":{"post":{"tags":["Git Providers"],"summary":"Create a GitHub Personal Access Token provider","operationId":"create_github_pat_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGitHubPATRequest"}}},"required":true},"responses":{"201":{"description":"GitHub PAT provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/gitlab/oauth":{"post":{"tags":["Git Providers"],"summary":"Create a GitLab OAuth provider","operationId":"create_gitlab_oauth_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGitLabOAuthRequest"}}},"required":true},"responses":{"201":{"description":"GitLab OAuth provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/gitlab/pat":{"post":{"tags":["Git Providers"],"summary":"Create a GitLab PAT provider","operationId":"create_gitlab_pat_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGitLabPATRequest"}}},"required":true},"responses":{"201":{"description":"GitLab PAT provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}":{"get":{"tags":["Git Providers"],"summary":"Get a specific git provider","operationId":"get_git_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Provider details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Git Providers"],"summary":"Permanently delete a git provider","operationId":"delete_git_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Provider deleted successfully"},"400":{"description":"Provider has connections and cannot be deleted"},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/activate":{"post":{"tags":["Git Providers"],"summary":"Activate a git provider","operationId":"activate_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Provider activated successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/callback":{"get":{"tags":["Git Providers"],"summary":"Handle OAuth callback for a git provider","operationId":"handle_git_provider_oauth_callback","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"code","in":"query","description":"OAuth authorization code","required":true,"schema":{"type":"string"}},{"name":"state","in":"query","description":"CSRF state token","required":true,"schema":{"type":"string"}}],"responses":{"302":{"description":"Redirect to success page"},"400":{"description":"Bad request"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}}}},"/git-providers/{provider_id}/connections":{"get":{"tags":["Git Providers"],"summary":"Get connections for a specific git provider","operationId":"get_provider_connections","parameters":[{"name":"provider_id","in":"path","description":"Provider ID to get connections for","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of connections for the provider","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ConnectionResponse"}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/credentials":{"patch":{"tags":["Git Providers"],"summary":"Partially update credentials for an existing git provider. Only the fields\nyou send are replaced; omitted fields keep their stored values. Fields that\ndon't apply to the provider's auth method are ignored on the service side.","operationId":"update_git_provider_credentials","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProviderCredentialsRequest"}}},"required":true},"responses":{"200":{"description":"Credentials updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/deactivate":{"post":{"tags":["Git Providers"],"summary":"Deactivate a git provider","operationId":"deactivate_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Provider deactivated successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/deletion-check":{"get":{"tags":["Git Providers"],"summary":"Check if a git provider can be safely deleted","operationId":"check_provider_deletion_safety","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deletion check result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderDeletionCheckResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/oauth/authorize":{"get":{"tags":["Git Providers"],"summary":"Start OAuth flow for a git provider","operationId":"start_git_provider_oauth","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"302":{"description":"Redirect to OAuth provider"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/repositories":{"get":{"tags":["Git Providers"],"summary":"List all repositories for a specific provider","description":"Lists repositories synced to the database across every connection under\nthis provider, with the same pagination/filtering as `/repositories`.","operationId":"list_repositories_by_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"sort","in":"query","description":"Sort field (name, created_at, updated_at, stars, watchers, size, issues)","required":false,"schema":{"type":"string"}},{"name":"direction","in":"query","description":"Sort direction (asc, desc)","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Search term to filter repositories","required":false,"schema":{"type":"string"}},{"name":"owner","in":"query","description":"Filter by repository owner","required":false,"schema":{"type":"string"}},{"name":"language","in":"query","description":"Filter by programming language","required":false,"schema":{"type":"string"}},{"name":"private","in":"query","description":"Filter by private status (true/false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of repositories","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/safe-delete":{"delete":{"tags":["Git Providers"],"summary":"Safely delete a git provider (only if no projects are using it)","operationId":"delete_provider_safely","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Provider successfully deleted"},"400":{"description":"Cannot delete provider because it's in use"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git/public/{provider}/{owner}/{repo}":{"get":{"tags":["Public Repositories"],"summary":"Get information about a public repository (supports GitHub and GitLab)","operationId":"get_public_repository","parameters":[{"name":"provider","in":"path","description":"Git provider (github or gitlab)","required":true,"schema":{"type":"string"}},{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Repository information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicRepositoryInfo"}}}},"400":{"description":"Provider not supported"},"404":{"description":"Repository not found"},"429":{"description":"API rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/git/public/{provider}/{owner}/{repo}/branches":{"get":{"tags":["Public Repositories"],"summary":"Get branches for a public repository (supports GitHub and GitLab)","operationId":"get_public_branches","parameters":[{"name":"provider","in":"path","description":"Git provider (github or gitlab)","required":true,"schema":{"type":"string"}},{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of branches","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BranchListResponse"}}}},"400":{"description":"Provider not supported"},"404":{"description":"Repository not found"},"429":{"description":"API rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/git/public/{provider}/{owner}/{repo}/presets":{"get":{"tags":["Public Repositories"],"summary":"Detect presets for a public repository (supports GitHub and GitLab)","operationId":"detect_public_presets","parameters":[{"name":"provider","in":"path","description":"Git provider (github or gitlab)","required":true,"schema":{"type":"string"}},{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"branch","in":"query","description":"Branch name to detect presets for (default: repository's default branch)","required":false,"schema":{"type":["string","null"]}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Detected presets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicPresetResponse"}}}},"400":{"description":"Provider not supported"},"404":{"description":"Repository or branch not found"},"429":{"description":"API rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/imports/discover":{"post":{"tags":["Imports"],"summary":"Discover workloads from a source","operationId":"discover_workloads","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscoverRequest"}}},"required":true},"responses":{"200":{"description":"List of discovered workloads","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscoverResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/imports/execute":{"post":{"tags":["Imports"],"summary":"Execute an import","operationId":"execute_import","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteImportRequest"}}},"required":true},"responses":{"202":{"description":"Import execution started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteImportResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/imports/plan":{"post":{"tags":["Imports"],"summary":"Create an import plan","operationId":"create_plan","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePlanRequest"}}},"required":true},"responses":{"200":{"description":"Import plan created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePlanResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/imports/sources":{"get":{"tags":["Imports"],"summary":"List available import sources","operationId":"list_sources","responses":{"200":{"description":"List of available import sources","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ImportSourceInfo"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/imports/{session_id}":{"get":{"tags":["Imports"],"summary":"Get import status","operationId":"get_import_status","parameters":[{"name":"session_id","in":"path","description":"Import session ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Import status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Import session not found"}},"security":[{"bearer_auth":[]}]}},"/incidents/{incident_id}":{"get":{"tags":["Status Page"],"summary":"Get an incident by ID","operationId":"get_incident","parameters":[{"name":"incident_id","in":"path","description":"Incident ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved incident","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Incident not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/incidents/{incident_id}/status":{"patch":{"tags":["Status Page"],"summary":"Update incident status","operationId":"update_incident_status","parameters":[{"name":"incident_id","in":"path","description":"Incident ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateIncidentStatusRequest"}}},"required":true},"responses":{"200":{"description":"Incident status updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Incident not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/incidents/{incident_id}/updates":{"get":{"tags":["Status Page"],"summary":"Get incident updates","operationId":"get_incident_updates","parameters":[{"name":"incident_id","in":"path","description":"Incident ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved incident updates","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/IncidentUpdateResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Incident not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes":{"get":{"tags":["Nodes"],"summary":"List all registered nodes (admin — session auth via RequireAuth)","operationId":"admin_list_nodes","responses":{"200":{"description":"List of nodes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodeListResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes/register":{"post":{"tags":["Nodes"],"summary":"Register a new worker node or reconnect an existing one","operationId":"register_node","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterNodeApiRequest"}}},"required":true},"responses":{"200":{"description":"Node reconnected successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterNodeResponse"}}}},"201":{"description":"Node registered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterNodeResponse"}}}},"400":{"description":"Validation error"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}":{"get":{"tags":["Nodes"],"summary":"Get a specific node by ID (admin — session auth via RequireAuth)","operationId":"admin_get_node","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Node details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodeInfoResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Nodes"],"summary":"Remove a node from the cluster entirely. The node should be drained first\nto ensure containers have been rescheduled. If the node still has active\ncontainers, it will be drained automatically before removal.","operationId":"admin_remove_node","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Node removed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoveNodeResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"409":{"description":"Node still has active containers"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes/{node_id}/containers":{"get":{"tags":["Nodes"],"summary":"List all containers running on a specific node","operationId":"admin_list_node_containers","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Containers on this node","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodeContainerListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes/{node_id}/dns/ack":{"post":{"tags":["Internal DNS"],"summary":"`POST /internal/nodes/{node_id}/dns/ack`","operationId":"post_dns_ack","parameters":[{"name":"node_id","in":"path","description":"Node id, must match the bearer token's node","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsAckRequest"}}},"required":true},"responses":{"200":{"description":"ACK accepted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsAckResponse"}}}},"400":{"description":"ACK higher than server generation"},"401":{"description":"Missing or invalid bearer token"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}/dns/changes":{"get":{"tags":["Internal DNS"],"summary":"`GET /internal/nodes/{node_id}/dns/changes?since=N`","operationId":"get_dns_changes","parameters":[{"name":"node_id","in":"path","description":"Node id, must match the bearer token's node","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"since","in":"query","description":"Highest generation the agent has already applied. Pass `0` to\nrequest a full zone snapshot. Defaults to `0` if omitted.","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Diff or full snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsChangesResponse"}}}},"401":{"description":"Missing or invalid bearer token"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}/drain":{"get":{"tags":["Nodes"],"summary":"Get the drain status for a node, including migration progress.","description":"Returns container counts and whether the drain is complete.\nCan be polled to track drain progress.","operationId":"admin_drain_status","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Drain status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DrainStatusResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Nodes"],"summary":"Drain a node: mark it as \"draining\" so no new replicas are scheduled on it,\nand trigger redeployment of all affected environments so their containers\nare rescheduled to healthy nodes.","operationId":"admin_drain_node","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Node drain initiated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DrainNodeResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Nodes"],"summary":"Undrain (reactivate) a node so it can accept new deployments again.\nOnly works for nodes in \"draining\" or \"drained\" status.","operationId":"admin_undrain_node","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Node reactivated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UndrainNodeResponse"}}}},"400":{"description":"Node not in drainable state"},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes/{node_id}/heartbeat":{"post":{"tags":["Nodes"],"summary":"Receive a heartbeat from a worker node","operationId":"node_heartbeat","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HeartbeatApiRequest"}}},"required":true},"responses":{"200":{"description":"Heartbeat received","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HeartbeatResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}/network/peers":{"get":{"tags":["Nodes"],"summary":"`GET /internal/nodes/{node_id}/network/peers`","operationId":"list_peers","parameters":[{"name":"node_id","in":"path","description":"Node id, must match the bearer token's node","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Peer list and self-allocation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PeerListResponse"}}}},"401":{"description":"Missing or invalid bearer token"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}/s3-credentials/{s3_source_id}":{"get":{"tags":["Nodes"],"summary":"Get decrypted S3 credentials for a backup/restore operation.","description":"Agents call this endpoint to receive the S3 credentials they need to upload\nor download backups. The credentials are decrypted from the stored S3 source\nand returned over the authenticated TLS/WireGuard channel.","operationId":"get_s3_credentials","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"s3_source_id","in":"path","description":"S3 source ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"S3 credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3CredentialsResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"S3 source not found"},"500":{"description":"Internal server error"}}}},"/ip-access-control":{"get":{"tags":["IP Access Control"],"summary":"List all IP access control rules","operationId":"list_ip_access_control","parameters":[{"name":"action","in":"query","description":"Filter by action (\"block\" or \"allow\")","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of IP access control rules","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/IpAccessControlResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["IP Access Control"],"summary":"Create a new IP access control rule","operationId":"create_ip_access_control","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIpAccessControlRequest"}}},"required":true},"responses":{"201":{"description":"IP access control rule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IpAccessControlResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"409":{"description":"Duplicate IP address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ip-access-control/check/{ip}":{"get":{"tags":["IP Access Control"],"summary":"Check if an IP address is blocked","operationId":"check_ip_blocked","parameters":[{"name":"ip","in":"path","description":"IP address to check","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"IP block status"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ip-access-control/{id}":{"get":{"tags":["IP Access Control"],"summary":"Get a single IP access control rule by ID","operationId":"get_ip_access_control","parameters":[{"name":"id","in":"path","description":"IP access control rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"IP access control rule details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IpAccessControlResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"IP access control rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["IP Access Control"],"summary":"Delete an IP access control rule","operationId":"delete_ip_access_control","parameters":[{"name":"id","in":"path","description":"IP access control rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"IP access control rule deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"IP access control rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["IP Access Control"],"summary":"Update an IP access control rule","operationId":"update_ip_access_control","parameters":[{"name":"id","in":"path","description":"IP access control rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateIpAccessControlRequest"}}},"required":true},"responses":{"200":{"description":"IP access control rule updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IpAccessControlResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"IP access control rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/kv/del":{"post":{"tags":["KV Store"],"summary":"Delete one or more keys","operationId":"kv_del","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DelRequest"}}},"required":true},"responses":{"200":{"description":"Keys deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DelResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/disable":{"delete":{"tags":["KV Management"],"summary":"Disable KV service","operationId":"kv_disable","responses":{"200":{"description":"KV service disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DisableKvResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"KV service not enabled"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/enable":{"post":{"tags":["KV Management"],"summary":"Enable KV service","operationId":"kv_enable","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnableKvRequest"}}},"required":true},"responses":{"200":{"description":"KV service enabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnableKvResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/expire":{"post":{"tags":["KV Store"],"summary":"Set expiration on a key","operationId":"kv_expire","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExpireRequest"}}},"required":true},"responses":{"200":{"description":"Expiration set","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExpireResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/get":{"post":{"tags":["KV Store"],"summary":"Get a value by key","operationId":"kv_get","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetRequest"}}},"required":true},"responses":{"200":{"description":"Value retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/incr":{"post":{"tags":["KV Store"],"summary":"Increment a numeric value","operationId":"kv_incr","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncrRequest"}}},"required":true},"responses":{"200":{"description":"Value incremented","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncrResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/keys":{"post":{"tags":["KV Store"],"summary":"Get keys matching a pattern","operationId":"kv_keys","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeysRequest"}}},"required":true},"responses":{"200":{"description":"Keys retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeysResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/set":{"post":{"tags":["KV Store"],"summary":"Set a value with optional expiration","operationId":"kv_set","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetRequest"}}},"required":true},"responses":{"200":{"description":"Value set","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/status":{"get":{"tags":["KV Management"],"summary":"Get KV service status","operationId":"kv_status","responses":{"200":{"description":"KV service status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KvStatusResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/ttl":{"post":{"tags":["KV Store"],"summary":"Get time-to-live for a key","operationId":"kv_ttl","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TtlRequest"}}},"required":true},"responses":{"200":{"description":"TTL retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TtlResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/update":{"patch":{"tags":["KV Management"],"summary":"Update KV service configuration","operationId":"kv_update","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateKvRequest"}}},"required":true},"responses":{"200":{"description":"KV service updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateKvResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"KV service not enabled"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/lb/routes":{"get":{"tags":["Load Balancer"],"operationId":"list_routes","responses":{"200":{"description":"List of routes","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RouteResponse"}}}}},"500":{"description":"Internal server error"}}},"post":{"tags":["Load Balancer"],"operationId":"create_route","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRouteRequest"}}},"required":true},"responses":{"201":{"description":"Route created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteResponse"}}}},"400":{"description":"Invalid request"}}}},"/lb/routes/{domain}":{"get":{"tags":["Load Balancer"],"operationId":"get_route","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Route found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteResponse"}}}},"404":{"description":"Route not found"}}},"put":{"tags":["Load Balancer"],"operationId":"update_route","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRouteRequest"}}},"required":true},"responses":{"200":{"description":"Route updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteResponse"}}}},"404":{"description":"Route not found"}}},"delete":{"tags":["Load Balancer"],"operationId":"delete_route","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Route deleted successfully"},"404":{"description":"Route not found"}}}},"/logout":{"post":{"tags":["Authentication"],"operationId":"logout","responses":{"200":{"description":"Successfully logged out"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/logs/context":{"get":{"tags":["Logs"],"summary":"Get context lines surrounding a specific log line","operationId":"get_log_context","parameters":[{"name":"chunk_id","in":"query","description":"Chunk ID","required":true,"schema":{"type":"string"}},{"name":"line_offset","in":"query","description":"Line offset within the chunk","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"lines","in":"query","description":"Context lines before and after (default: 25)","required":false,"schema":{"type":"integer","format":"int32","minimum":0}}],"responses":{"200":{"description":"Context lines","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContextLogsResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Chunk not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/logs/search":{"post":{"tags":["Logs"],"summary":"Search logs with structured filters and full text search","operationId":"search_logs","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchLogsRequest"}}},"required":true},"responses":{"200":{"description":"Search results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchLogsResponse"}}}},"400":{"description":"Invalid search parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/logs/tail":{"get":{"tags":["Logs"],"summary":"Live tail logs via Server-Sent Events","operationId":"tail_logs","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"string"}},{"name":"service","in":"query","description":"Service name","required":true,"schema":{"type":"string"}},{"name":"env","in":"query","description":"Environment","required":true,"schema":{"type":"string"}},{"name":"levels","in":"query","description":"Optional level filters","required":true,"schema":{"type":"array","items":{"type":"string"}}},{"name":"text","in":"query","description":"Optional text filter","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"SSE stream of log lines"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/monitors-health/projects":{"get":{"tags":["Status Page"],"summary":"Get monitor-based health summaries for multiple projects in a single query","operationId":"get_projects_monitor_health","parameters":[{"name":"project_ids","in":"query","description":"Comma-separated list of project IDs","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Health summaries per project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectsMonitorHealthResponse"}}}},"400":{"description":"Invalid parameters"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/monitors/{monitor_id}":{"get":{"tags":["Status Page"],"summary":"Get a monitor by ID","operationId":"get_monitor","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved monitor","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Status Page"],"summary":"Delete a monitor","operationId":"delete_monitor","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Monitor deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/monitors/{monitor_id}/bucketed":{"get":{"tags":["Status Page"],"summary":"Get bucketed status data for a monitor using TimescaleDB","operationId":"get_bucketed_status","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"interval","in":"query","description":"Bucket interval: '5min', 'hourly', or 'daily' (default: hourly)","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601) (default: 24 hours ago)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (ISO 8601) (default: now)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved bucketed status data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusBucketedResponse"}}}},"400":{"description":"Invalid parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/monitors/{monitor_id}/current-status":{"get":{"tags":["Status Page"],"summary":"Get current status and uptime metrics for a monitor","operationId":"get_current_monitor_status","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","description":"Custom start time (ISO 8601) - overrides timeframe","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"Custom end time (ISO 8601)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved current status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CurrentStatusResponse"}}}},"400":{"description":"Invalid time parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/monitors/{monitor_id}/uptime":{"get":{"tags":["Status Page"],"summary":"Get uptime history for a monitor","operationId":"get_uptime_history","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"days","in":"query","description":"Number of days of history (default: 60) - ignored if start_time/end_time provided","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601) - overrides days parameter","required":true,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (ISO 8601) - defaults to now","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved uptime history","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UptimeHistoryResponse"}}}},"400":{"description":"Invalid time parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/nodes/{id}/metrics":{"get":{"tags":["Metrics"],"summary":"Fetch a time-series range for a single metric on a node.","operationId":"NodeMetricsGetRange","parameters":[{"name":"id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric","in":"query","description":"Metric name, e.g. `\"pg.connections_active\"`.","required":true,"schema":{"type":"string"}},{"name":"range","in":"query","description":"Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`.","required":false,"schema":{"type":"string"}},{"name":"percentile","in":"query","description":"Optional histogram percentile (0–100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile.","required":false,"schema":{"type":["number","null"],"format":"double"}}],"responses":{"200":{"description":"Metric time series data points","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MetricDataPoint"}}}}},"400":{"description":"Invalid query parameters"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/notification-preferences":{"get":{"tags":["Notification Preferences"],"summary":"Get notification preferences","operationId":"get_preferences","responses":{"200":{"description":"Successfully retrieved preferences","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationPreferencesResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Notification Preferences"],"summary":"Update notification preferences","operationId":"update_preferences","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePreferencesRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated preferences","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationPreferencesResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Notification Preferences"],"summary":"Delete notification preferences","operationId":"delete_preferences","responses":{"204":{"description":"Successfully deleted preferences"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers":{"get":{"tags":["Notification Providers"],"summary":"List all notification providers","operationId":"list_notification_providers","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Successfully retrieved providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}}},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Notification Providers"],"summary":"Create a new notification provider","operationId":"create_notification_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/cloudflare":{"post":{"tags":["Notification Providers"],"summary":"Create a new Cloudflare Email Sending notification provider","operationId":"create_cloudflare_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCloudflareProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created Cloudflare provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/cloudflare/{id}":{"put":{"tags":["Notification Providers"],"summary":"Update a Cloudflare Email Sending notification provider","operationId":"update_cloudflare_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCloudflareProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated Cloudflare provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/email":{"post":{"tags":["Notification Providers"],"summary":"Create a new Email notification provider","operationId":"create_notification_email_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateNotificationEmailProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created Email provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/email/{id}":{"put":{"tags":["Notification Providers"],"summary":"Update an Email notification provider","operationId":"update_notification_email_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateNotificationEmailProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated Email provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/slack":{"post":{"tags":["Notification Providers"],"summary":"Create a new Slack notification provider","operationId":"create_slack_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSlackProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created Slack provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/slack/{id}":{"put":{"tags":["Notification Providers"],"summary":"Update a Slack notification provider","operationId":"update_slack_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSlackProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated Slack provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/webhook":{"post":{"tags":["Notification Providers"],"summary":"Create a new Webhook notification provider","description":"Webhook providers send notifications as JSON payloads to any HTTP endpoint.\nYou can configure custom headers for authentication (Bearer tokens, API keys, etc.).\nThe webhook will receive a JSON payload with notification details including:\nid, title, message, type, priority, severity, timestamp, and metadata.","operationId":"create_webhook_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created Webhook provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/webhook/{id}":{"put":{"tags":["Notification Providers"],"summary":"Update a Webhook notification provider","operationId":"update_webhook_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWebhookProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated Webhook provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/{id}":{"get":{"tags":["Notification Providers"],"summary":"Get a single notification provider","operationId":"get_notification_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Notification Providers"],"summary":"Update a notification provider","operationId":"update_notification_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid masked provider configuration"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Notification Providers"],"summary":"Delete a notification provider","operationId":"delete_notification_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Successfully deleted provider"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/{id}/config/{field}":{"get":{"tags":["Notification Providers"],"operationId":"reveal_notification_provider_config","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"field","in":"path","description":"Sensitive field, such as password or headers.Authorization","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sensitive provider configuration value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensitiveConfigValueResponse"}}}},"400":{"description":"Field is not revealable"},"403":{"description":"Missing secrets:read permission"},"404":{"description":"Provider or field not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/{id}/test":{"post":{"tags":["Notification Providers"],"summary":"Test a notification provider","operationId":"test_notification_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/orders":{"get":{"tags":["Domains"],"summary":"List all ACME orders","operationId":"list_orders","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Orders retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListOrdersResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/otel/alerts":{"get":{"tags":["Alerts"],"summary":"List alert rules for a project (newest first, paginated).","operationId":"list_alerts","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Alert rules for the project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricAlertsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Alerts"],"summary":"Create a new alert rule for a project.","operationId":"create_alert","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMetricAlertRequest"}}},"required":true},"responses":{"201":{"description":"Alert rule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricAlertRuleResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/alerts/preview":{"post":{"tags":["Alerts"],"summary":"Backtest an anomaly detector over a time range without saving a rule.","description":"Replays the metric against the same band the evaluator would use, returning\nthe per-bucket band + which points would have fired. Powers the form's\n\"would this have fired?\" preview and the explorer band overlay. Read-only.","operationId":"preview_alert","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnomalyPreviewRequest"}}},"required":true},"responses":{"200":{"description":"Per-bucket band + breach points","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnomalyPreviewResponse"}}}},"400":{"description":"Not an anomaly detector / bad input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/alerts/{id}":{"get":{"tags":["Alerts"],"summary":"Fetch a single alert rule by id.","operationId":"get_alert","parameters":[{"name":"id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the lookup)","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alert rule","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricAlertRuleResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Alert rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Alerts"],"summary":"Delete an alert rule.","operationId":"delete_alert","parameters":[{"name":"id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the delete)","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Alert rule deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Alert rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Alerts"],"summary":"Update an alert rule's fields.","operationId":"update_alert","parameters":[{"name":"id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the update)","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMetricAlertRequest"}}},"required":true},"responses":{"200":{"description":"Alert rule updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricAlertRuleResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Alert rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/dashboards":{"get":{"tags":["Dashboards"],"summary":"List dashboards for a project (newest first, paginated).","operationId":"list_dashboards","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Dashboards for the project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelDashboardsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Dashboards"],"summary":"Create a new dashboard for a project.","operationId":"create_dashboard","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDashboardRequest"}}},"required":true},"responses":{"201":{"description":"Dashboard created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelDashboardResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/dashboards/{id}":{"get":{"tags":["Dashboards"],"summary":"Fetch a single dashboard by id.","operationId":"get_dashboard","parameters":[{"name":"id","in":"path","description":"Dashboard ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the lookup)","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Dashboard","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelDashboardResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Dashboard not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Dashboards"],"summary":"Delete a dashboard.","operationId":"delete_dashboard","parameters":[{"name":"id","in":"path","description":"Dashboard ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the delete)","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Dashboard deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Dashboard not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Dashboards"],"summary":"Update a dashboard's name and/or layout.","operationId":"update_dashboard","parameters":[{"name":"id","in":"path","description":"Dashboard ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the update)","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDashboardRequest"}}},"required":true},"responses":{"200":{"description":"Dashboard updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelDashboardResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Dashboard not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/genai/traces":{"get":{"tags":["GenAI"],"summary":"Query GenAI trace summaries — traces containing spans with `gen_ai.*` attributes.","description":"`duration_ms` is the only field guaranteed to be milliseconds. `gen_ai.*`\nspan attributes (e.g. time-to-first-token, token latency) often follow the\nOTel GenAI semantic conventions, which use **seconds** (a fractional\ndouble), not milliseconds — do not read them as ms without converting.","operationId":"query_genai_traces","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"gen_ai_system","in":"query","description":"Filter by AI system (openai, anthropic, etc.)","required":false,"schema":{"type":"string"}},{"name":"gen_ai_model","in":"query","description":"Filter by model (gpt-4, claude-sonnet-4-20250514, etc.)","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max traces to return (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"GenAI trace summaries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenAiTraceSummariesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/genai/traces/{project_id}/{trace_id}":{"get":{"tags":["GenAI"],"summary":"Get GenAI span details for a specific trace.","description":"`duration_ms` is the only field guaranteed to be milliseconds. `gen_ai.*`\nspan attributes (e.g. time-to-first-token, token latency) often follow the\nOTel GenAI semantic conventions, which use **seconds** (a fractional\ndouble), not milliseconds — do not read them as ms without converting.","operationId":"get_genai_trace","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trace_id","in":"path","description":"Trace ID (hex)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"GenAI trace span details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenAiTraceDetailResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/global/traces/{trace_id}":{"get":{"tags":["Traces"],"summary":"Assemble a unified cross-project span waterfall (Phase 2).","description":"Fans out to every project that holds spans for `trace_id` (up to 20\nprojects, 10,000 total spans). Spans are annotated with\n`project_id`/`project_name` and sorted by `start_time ASC`.\n`truncated: true` signals a hit on either cap; `truncated_projects`\nlists the dropped project IDs. See ADR-027 §4 for the full design.","operationId":"getUnifiedTrace","parameters":[{"name":"trace_id","in":"path","description":"Trace ID (32 lowercase hex characters)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Unified cross-project trace waterfall","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnifiedTrace"}}}},"400":{"description":"trace_id is not 32 lowercase hex characters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions or deployment token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/health/{project_id}":{"get":{"tags":["OTel"],"summary":"Get health summaries for a project.","operationId":"get_health","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Health summaries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/insights/{project_id}":{"get":{"tags":["Insights"],"summary":"List anomaly insights for a project.","operationId":"list_insights","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"status","in":"query","description":"Filter by status (active, resolved)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max insights to return (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Insights list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsightsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/logs":{"get":{"tags":["Telemetry Logs"],"summary":"Query log records with optional filters.","operationId":"query_logs","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"severity","in":"query","description":"Filter by severity (TRACE, DEBUG, INFO, WARN, ERROR, FATAL)","required":false,"schema":{"type":"string"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Full-text search in log body (ILIKE)","required":false,"schema":{"type":"string"}},{"name":"trace_id","in":"query","description":"Filter by correlated trace ID","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max logs to return (default: 100, max: 1000)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Log records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LogsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/metric-label-keys":{"get":{"tags":["Telemetry Metrics"],"summary":"List the attribute (label) keys observed on a metric — powers the\nlabel-filter key autocomplete.","operationId":"list_metric_label_keys","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric_name","in":"query","description":"Metric to inspect","required":true,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Window start (RFC 3339); defaults to 24h before end","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"Window end (RFC 3339); defaults to now","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Distinct label keys","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricLabelKeysResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/metric-label-values":{"get":{"tags":["Telemetry Metrics"],"summary":"List the distinct values seen for a label key on a metric — powers value\nautocomplete once a key is chosen.","operationId":"list_metric_label_values","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric_name","in":"query","description":"Metric to inspect","required":true,"schema":{"type":"string"}},{"name":"label_key","in":"query","description":"Label key whose values to list (must match [a-zA-Z0-9_.:-])","required":true,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Window start (RFC 3339); defaults to 24h before end","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"Window end (RFC 3339); defaults to now","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Distinct label values","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricLabelValuesResponse"}}}},"400":{"description":"Invalid label key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/metric-names/{project_id}":{"get":{"tags":["Telemetry Metrics"],"summary":"List distinct metric names for a project.","operationId":"list_metric_names","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of metric names","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricNamesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/metrics":{"get":{"tags":["Telemetry Metrics"],"summary":"Query metrics with time bucketing.","operationId":"query_metrics","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric_name","in":"query","description":"Filter by metric name","required":false,"schema":{"type":"string"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"environment","in":"query","description":"Filter by deployment environment","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"bucket_interval","in":"query","description":"Bucket interval (e.g. '1 hour', '5 minutes')","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max buckets to return (default: 1000)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"metric_type","in":"query","description":"Filter by metric type (gauge, sum, histogram, exponential_histogram, summary)","required":false,"schema":{"type":"string"}},{"name":"aggregation","in":"query","description":"Per-bucket aggregation: avg (default), sum, min, max, count, rate, p50/p95/p99, quantile:0.95","required":false,"schema":{"type":"string"}},{"name":"label_filters","in":"query","description":"Comma-separated key=value data-point label filters (keys must match [a-zA-Z0-9_.:-])","required":false,"schema":{"type":"string"}},{"name":"group_by","in":"query","description":"Comma-separated label keys to group series by","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Metrics data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricsResponse"}}}},"400":{"description":"Invalid label key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/pipeline-stats":{"get":{"tags":["OTel"],"summary":"Get OTel pipeline statistics (admin/system view).","operationId":"get_pipeline_stats","responses":{"200":{"description":"Pipeline statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PipelineStatsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/quota/{project_id}":{"get":{"tags":["OTel"],"summary":"Get storage quota for a project.","operationId":"get_quota","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Storage quota","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuotaResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/trace-summaries":{"get":{"tags":["Traces"],"summary":"Query trace summaries — one row per trace with span count, error count,\nroot span info, and proper trace-level pagination.","operationId":"query_trace_summaries","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trace_id","in":"query","description":"Filter by trace ID","required":false,"schema":{"type":"string"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Filter by status (OK, ERROR)","required":false,"schema":{"type":"string"}},{"name":"min_duration_ms","in":"query","description":"Minimum trace duration in ms","required":false,"schema":{"type":"number","format":"double"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"name_pattern","in":"query","description":"Filter by span name pattern (ILIKE)","required":false,"schema":{"type":"string"}},{"name":"sort_by","in":"query","description":"Sort field: 'start_time' (default) or 'duration'","required":false,"schema":{"type":"string"}},{"name":"sort_order","in":"query","description":"Sort direction: 'asc' or 'desc' (default)","required":false,"schema":{"type":"string"}},{"name":"include_total","in":"query","description":"Compute the `total` count (default: true). Set false to skip the second aggregation when only the page is needed","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Max traces to return (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Trace summaries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TraceSummariesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/traces":{"get":{"tags":["Traces"],"summary":"Query trace spans with optional filters.","description":"Each returned span has a `duration_ms` field (float, milliseconds) — this is\nthe ONLY field guaranteed to be in milliseconds. Spans also carry an\n`attributes` map of raw key/value pairs exactly as reported by the\ninstrumenting library: numeric attribute values may be seconds, milliseconds,\nmicroseconds, or nanoseconds depending on that library's convention, and\nnothing in this response labels the unit. Never assume an attribute's\nnumeric value shares `duration_ms`'s unit, and never state a duration in\nmilliseconds unless it came from a `duration_ms` field.","operationId":"query_traces","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trace_id","in":"query","description":"Filter by trace ID","required":false,"schema":{"type":"string"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Filter by status (OK, ERROR, UNSET)","required":false,"schema":{"type":"string"}},{"name":"min_duration_ms","in":"query","description":"Minimum span duration in ms","required":false,"schema":{"type":"number","format":"double"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Max spans to return (default: 100, max: 1000)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Trace spans","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TracesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/traces/cross-project/{trace_id}":{"get":{"tags":["Traces"],"summary":"Discover sibling projects that share the same `trace_id` (Phase 1 banner).","description":"Returns an empty `siblings` list when the trace is single-project — never\n404. Project names are included so the UI can render navigation links\nwithout a second round-trip. See ADR-027 §3 for the full auth model and\ntopology-disclosure trade-offs.","operationId":"getCrossProjectTraceSiblings","parameters":[{"name":"trace_id","in":"path","description":"Trace ID (32 lowercase hex characters)","required":true,"schema":{"type":"string"}},{"name":"exclude_project_id","in":"query","description":"Project ID to exclude (the caller's own project) so the UI does not render a self-link","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Sibling projects sharing this trace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrossProjectTraceResponse"}}}},"400":{"description":"trace_id is not 32 lowercase hex characters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions or deployment token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/traces/{project_id}/{trace_id}":{"get":{"tags":["Traces"],"summary":"Get all spans for a specific trace.","description":"Each span has a `duration_ms` field (float, milliseconds) — the ONLY field\nguaranteed to be in milliseconds — plus an `attributes` map of raw\nkey/value pairs exactly as the instrumenting library reported them.\nNumeric attribute values (e.g. connection-pool wait times, queue delays)\nmay be in seconds, milliseconds, microseconds, or nanoseconds depending on\nthat library's own convention; this response never labels the unit. When\nexplaining what a span spent time on, only quote milliseconds from\n`duration_ms` (or from `start_time`/`end_time` deltas) — never assume a raw\nattribute number is already in milliseconds.","operationId":"get_trace","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trace_id","in":"path","description":"Trace ID (hex)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Trace spans tree","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TracesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/v1/logs":{"post":{"tags":["OTel Ingest"],"summary":"Ingest log records via OTLP/HTTP protobuf.","description":"Authenticates via API key in header, decompresses, decodes protobuf,\nchecks rate limit and storage quota, routes high-severity logs\nto DB and all logs to S3.","operationId":"ingest_logs","requestBody":{"description":"OTLP ExportLogsServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Logs accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/metrics":{"post":{"tags":["OTel Ingest"],"summary":"Ingest metrics via OTLP/HTTP protobuf.","description":"Authenticates via API key in header, decompresses, decodes protobuf,\nchecks rate limit and storage quota, then stores.","operationId":"ingest_metrics","requestBody":{"description":"OTLP ExportMetricsServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Metrics accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/traces":{"post":{"tags":["OTel Ingest"],"summary":"Ingest trace spans via OTLP/HTTP protobuf.","description":"Authenticates via API key in header, decompresses, decodes protobuf,\nchecks rate limit and storage quota, then stores spans.","operationId":"ingest_traces","requestBody":{"description":"OTLP ExportTraceServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Traces accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/{project_id}/{environment_id}/{deployment_id}/logs":{"post":{"tags":["OTel Ingest"],"summary":"Ingest log records with project/environment/deployment in the URL path.","operationId":"ingest_logs_by_path","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"OTLP ExportLogsServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Logs accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/{project_id}/{environment_id}/{deployment_id}/metrics":{"post":{"tags":["OTel Ingest"],"summary":"Ingest metrics with project/environment/deployment in the URL path.","operationId":"ingest_metrics_by_path","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"OTLP ExportMetricsServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Metrics accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/{project_id}/{environment_id}/{deployment_id}/traces":{"post":{"tags":["OTel Ingest"],"summary":"Ingest trace spans with project/environment/deployment in the URL path.","operationId":"ingest_traces_by_path","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"OTLP ExportTraceServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Traces accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/performance/has-metrics":{"get":{"tags":["Performance"],"summary":"Check if performance metrics exist for a project","operationId":"has_performance_metrics","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully checked performance metrics availability","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HasMetricsResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/performance/metrics":{"get":{"tags":["Performance"],"summary":"Get performance metrics","operationId":"get_performance_metrics","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Deployment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"device_type","in":"query","description":"Device type filter: desktop or mobile (optional)","required":false,"schema":{"type":"string"}},{"name":"include_bots","in":"query","description":"Include crawler/datacenter bot samples (default false)","required":false,"schema":{"type":"boolean"}},{"name":"filter_path","in":"query","description":"Filter to one page pathname (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_country","in":"query","description":"Filter to one country (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Filter to one region (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Filter to one city (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_browser","in":"query","description":"Filter to one browser (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_operating_system","in":"query","description":"Filter to one operating system (optional)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved performance metrics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PerformanceMetricsResponse"}}}},"400":{"description":"Invalid date format or missing parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/performance/metrics-over-time":{"get":{"tags":["Performance"],"summary":"Get metrics over time","operationId":"get_metrics_over_time","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DDTHH:MM:SSZ","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DDTHH:MM:SSZ","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Deployment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"device_type","in":"query","description":"Device type filter: desktop or mobile (optional)","required":false,"schema":{"type":"string"}},{"name":"include_bots","in":"query","description":"Include crawler/datacenter bot samples (default false)","required":false,"schema":{"type":"boolean"}},{"name":"filter_path","in":"query","description":"Filter to one page pathname (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_country","in":"query","description":"Filter to one country (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Filter to one region (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Filter to one city (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_browser","in":"query","description":"Filter to one browser (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_operating_system","in":"query","description":"Filter to one operating system (optional)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved metrics over time","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetricsOverTimeResponse"}}}},"400":{"description":"Invalid date format or missing parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/performance/page-metrics":{"get":{"tags":["Performance"],"summary":"Get grouped page metrics","operationId":"get_grouped_page_metrics","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DDTHH:MM:SSZ","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DDTHH:MM:SSZ","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Deployment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"group_by","in":"query","description":"Group by: path, country, region, city, device_type, browser, operating_system","required":true,"schema":{"type":"string"}},{"name":"device_type","in":"query","description":"Device type filter: desktop or mobile (optional)","required":false,"schema":{"type":"string"}},{"name":"include_bots","in":"query","description":"Include crawler/datacenter bot samples (default false)","required":false,"schema":{"type":"boolean"}},{"name":"filter_path","in":"query","description":"Filter to one page pathname (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_country","in":"query","description":"Filter to one country (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Filter to one region (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Filter to one city (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_browser","in":"query","description":"Filter to one browser (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_operating_system","in":"query","description":"Filter to one operating system (optional)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved grouped page metrics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroupedPageMetricsResponse"}}}},"400":{"description":"Invalid date format, missing parameters, or invalid group_by value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/platform/access-info":{"get":{"tags":["Platform"],"summary":"Get information about how the service is being accessed","description":"Returns details about the server's access mode, public IP address, private IP address,\nand domain creation capabilities. Both IP addresses are always included when available.","operationId":"get_access_info","responses":{"200":{"description":"Service access information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceAccessInfo"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/platform/private-ip":{"get":{"tags":["Platform"],"summary":"Get private/local IP address of the server","operationId":"get_private_ip","responses":{"200":{"description":"Successfully retrieved private IP address"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/platform/public-ip":{"get":{"tags":["Platform"],"summary":"Get public IP address of the server","operationId":"get_public_ip","responses":{"200":{"description":"Successfully retrieved public IP address"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/presets":{"get":{"tags":["Presets"],"summary":"List all available presets","operationId":"list_presets","responses":{"200":{"description":"List of available presets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListPresetsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/presets/{slug}/dockerfile":{"post":{"tags":["Presets"],"summary":"Generate a Dockerfile from a preset","description":"Returns the Dockerfile content and build arguments for a given preset slug.\nThe CLI can use this to build Docker images locally without needing a Dockerfile\nin the project directory, enabling zero-config deployments.","operationId":"generate_preset_dockerfile","parameters":[{"name":"slug","in":"path","description":"Preset slug (e.g., nextjs, vite, python)","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateDockerfileRequest"}}},"required":true},"responses":{"200":{"description":"Generated Dockerfile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateDockerfileResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Preset not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/logs":{"get":{"tags":["Preview Gateway"],"operationId":"get_preview_gateway_logs","parameters":[{"name":"tail","in":"query","description":"Lines to tail (default 200, max 2000)","required":false,"schema":{"type":"integer","minimum":0}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LogsResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/restart":{"post":{"tags":["Preview Gateway"],"operationId":"restart_preview_gateway","responses":{"204":{"description":"Gateway restarted"}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/settings":{"get":{"tags":["Preview Gateway"],"operationId":"get_preview_gateway_settings","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewGatewaySettingsResponse"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Preview Gateway"],"operationId":"patch_preview_gateway_settings","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PatchSettingsRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewGatewaySettingsResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/status":{"get":{"tags":["Preview Gateway"],"operationId":"get_preview_gateway_status","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayStatus"}}}}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/upgrade":{"post":{"tags":["Preview Gateway"],"operationId":"upgrade_preview_gateway","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpgradeRequest"}}},"required":true},"responses":{"204":{"description":"Gateway upgraded"}},"security":[{"bearer_auth":[]}]}},"/projects":{"get":{"tags":["Projects"],"summary":"Get a list of all projects","operationId":"get_projects","parameters":[{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"per_page","in":"query","description":"Number of items per page","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"List of projects","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedProjectList"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Projects"],"summary":"Create a new project","operationId":"create_project","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectRequest"}}},"required":true},"responses":{"200":{"description":"Project created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"400":{"description":"Invalid input"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/by-slug/{slug}":{"get":{"tags":["Projects"],"summary":"Get details of a specific project by slug","operationId":"get_project_by_slug","parameters":[{"name":"slug","in":"path","description":"Project slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Project details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]}},"/projects/from-template":{"post":{"tags":["Projects"],"summary":"Create a new project from a template","description":"Creates a new repository from a template and sets up the project with the\nspecified configuration. The template is cloned to a new repository under\nthe authenticated user's account or specified organization.","operationId":"create_project_from_template","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectFromTemplateRequest"}}},"required":true},"responses":{"201":{"description":"Project created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectFromTemplateResponse"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Template not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/statistics":{"get":{"tags":["Projects"],"summary":"Get project statistics","operationId":"get_project_statistics","responses":{"200":{"description":"Project statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectStatisticsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{id}":{"get":{"tags":["Projects"],"summary":"Get details of a specific project","operationId":"get_project","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Project details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Projects"],"operationId":"update_project","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectRequest"}}},"required":true},"responses":{"200":{"description":"Project updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Projects"],"operationId":"delete_project","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Project deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{id}/deployments":{"get":{"tags":["Projects"],"operationId":"get_project_deployments","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"per_page","in":"query","description":"Items per page","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"environment_id","in":"query","description":"Environment ID filter","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of deployments","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentListResponse"}}}},"404":{"description":"Project not found"}}}},"/projects/{id}/last-deployment":{"get":{"tags":["Deployments"],"summary":"Get the last deployment for a specific project","operationId":"get_last_deployment","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Last deployment details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentResponse"}}}},"404":{"description":"Project not found or no deployments"},"500":{"description":"Internal server error"}}}},"/projects/{id}/source":{"patch":{"tags":["Projects"],"summary":"Change a project's source type to a Git-less type (docker_image /\nstatic_files / manual). Switching TO Git is done via the Git settings\nendpoint (`POST /projects/{id}/git`), which also supplies the repository and\nprovider connection.","operationId":"change_project_source","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeProjectSourceRequest"}}},"required":true},"responses":{"200":{"description":"Source type changed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"400":{"description":"Invalid source type change (e.g. switching to Git here)"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{id}/trigger-pipeline":{"post":{"tags":["Projects"],"summary":"Trigger pipeline for a specific project","operationId":"trigger_project_pipeline","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerPipelinePayload"}}},"required":true},"responses":{"200":{"description":"Pipeline triggered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerPipelineResponse"}}}},"400":{"description":"Invalid request"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/access":{"get":{"tags":["Teams"],"operationId":"list_project_access","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Access grants","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectAccessResponse"}}}}},"403":{"description":"Insufficient permissions or no access to this project"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Teams"],"operationId":"grant_project_access","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectAccessRequest"}}},"required":true},"responses":{"201":{"description":"Access granted (idempotent upsert)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectAccessResponse"}}}},"403":{"description":"Insufficient permissions or no access to this project"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/access/{team_id}":{"delete":{"tags":["Teams"],"operationId":"revoke_project_access","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Access revoked"},"403":{"description":"Insufficient permissions or no access to this project"},"404":{"description":"Grant not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/active-visitors":{"get":{"tags":["Events"],"summary":"Get active visitors count","operationId":"get_active_visitors","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved active visitors count","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActiveVisitorsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents":{"get":{"tags":["Agents"],"operationId":"list_agents","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of agents for project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListAgentsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertAgentRequest"}}},"required":true},"responses":{"201":{"description":"Agent created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentConfigResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/cli-status":{"get":{"tags":["Agents"],"operationId":"get_cli_status","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"provider","in":"query","description":"AI provider: claude_cli or codex_cli","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"CLI status"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs":{"get":{"tags":["Agents"],"operationId":"list_all_runs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of all agent runs for a project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListRunsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/latest-for-source":{"get":{"tags":["Agents"],"operationId":"latest_run_for_source","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trigger_source_type","in":"query","description":"Trigger source type, e.g. 'error_group'","required":true,"schema":{"type":"string"}},{"name":"trigger_source_id","in":"query","description":"Trigger source ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Latest matching run, or null if none","content":{"application/json":{"schema":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AgentRunResponse"}]}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/{run_id}":{"get":{"tags":["Agents"],"operationId":"get_run_with_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Run with logs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunWithLogsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/{run_id}/cancel":{"post":{"tags":["Agents"],"operationId":"cancel_run","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Agent run ID to cancel","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Run cancelled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunResponse"}}}},"400":{"description":"Run is already in a terminal state"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/{run_id}/retry":{"post":{"tags":["Agents"],"summary":"Retry a completed, failed, cancelled, or no_fix run with the same trigger context.\nCreates a new run record and spawns the executor.","operationId":"retry_run","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID to retry","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"New run created from retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunResponse"}}}},"400":{"description":"Run is still active"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/{run_id}/stream":{"get":{"tags":["Agents"],"summary":"SSE endpoint for real-time streaming of run events.\nPolls the agent_run_logs table every 500ms for new entries and streams them.\nCloses when the run reaches a terminal status.","operationId":"stream_run_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Agent run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Server-Sent Events stream of run log events and terminal status","content":{"text/event-stream":{}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/sandbox-status":{"get":{"tags":["Agents"],"operationId":"get_sandbox_status","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Project-scoped sandbox readiness (Docker + agent image)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/smoke-test":{"post":{"tags":["Agents"],"summary":"Run a smoke test to verify the selected AI CLI works in the environment\nwhere agents will actually execute (host or sandbox container). If no\n`provider_id` is supplied the globally active provider is tested.","operationId":"smoke_test_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"provider_id","in":"query","description":"Provider id to test; defaults to the globally active provider","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Smoke test result for the AI CLI in the agent's execution environment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SmokeTestResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/{slug}":{"get":{"tags":["Agents"],"operationId":"get_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Agent config","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentConfigResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertAgentRequest"}}},"required":true},"responses":{"200":{"description":"Agent updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentConfigResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Agent deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/{slug}/runs":{"get":{"tags":["Agents"],"operationId":"list_agent_runs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of runs for a specific agent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListRunsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/{slug}/trigger":{"post":{"tags":["Agents"],"operationId":"trigger_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerAgentRequest"}}},"required":true},"responses":{"202":{"description":"Agent run created and queued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"402":{"description":"Daily budget exceeded"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"},"422":{"description":"AI CLI not installed"},"429":{"description":"Cooldown active"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/aggregated-buckets":{"get":{"tags":["Events"],"summary":"Get aggregated metrics by time bucket","operationId":"get_aggregated_buckets","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for the query range","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for the query range","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Optional environment filter","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Optional deployment filter","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors (default: events)","required":false,"schema":{"type":"string"}},{"name":"bucket_size","in":"query","description":"Time bucket size: '1 hour', '1 day', '1 week', etc. (default: '1 hour')","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved aggregated buckets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AggregatedBucketsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations":{"get":{"tags":["AI Chat"],"summary":"Find the existing chat for a context (returns `null` if none yet). Requires\nthe per-project `ai_debug_chat_enabled` toggle to be on; returns 403 when the\nfeature is disabled so revoking it consistently hides existing chat content.","operationId":"find_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"context_type","in":"query","required":true,"schema":{"type":"string"}},{"name":"context_id","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ConversationResponse"}]}}}},"401":{"description":""},"403":{"description":""}},"security":[{"bearer_auth":[]}]},"post":{"tags":["AI Chat"],"summary":"Get-or-create the chat for a context (seeds it on first open).","operationId":"create_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateConversationRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/list":{"get":{"tags":["AI Chat"],"summary":"List all active conversations for a project, most-recently-active first.\nPowers the conversation switcher in the AI assistant sidebar.","operationId":"list_conversations","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ConversationResponse"}}}}},"401":{"description":""},"403":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/{public_id}":{"get":{"tags":["AI Chat"],"summary":"Full conversation history (excluding the internal system seed).","operationId":"get_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationDetailResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["AI Chat"],"summary":"Rename a conversation (set its human-facing title).","operationId":"rename_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenameConversationRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationResponse"}}}},"400":{"description":""},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/{public_id}/archive":{"post":{"tags":["AI Chat"],"summary":"Archive (soft-delete) a conversation.","operationId":"archive_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":""},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/{public_id}/messages":{"post":{"tags":["AI Chat"],"summary":"Send a user message; stream the assistant reply as Server-Sent Events.","operationId":"send_message","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendMessageRequest"}}},"required":true},"responses":{"200":{"description":"SSE stream of assistant text deltas","content":{"text/event-stream":{}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/{public_id}/pending-actions":{"get":{"tags":["AI Chat"],"summary":"List all pending actions for a conversation (most-recently-proposed first).","operationId":"list_pending_actions","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","description":"Conversation public id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PendingActionResponse"}}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/pending-actions/{action_public_id}":{"get":{"tags":["AI Chat"],"summary":"Get a single pending action by its public id (scoped to the project).","operationId":"get_pending_action","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"action_public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PendingActionResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/pending-actions/{action_public_id}/confirm":{"post":{"tags":["AI Chat"],"summary":"Confirm a proposed AI action: validate permission, atomically claim, execute,\npersist outcome. The execution uses the CONFIRMING user's auth — never the model's.","operationId":"confirm_pending_action","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"action_public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PendingActionResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""},"409":{"description":""},"503":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/pending-actions/{action_public_id}/reject":{"post":{"tags":["AI Chat"],"summary":"Reject a proposed AI action (no execution). Status transitions to \"rejected\".","operationId":"reject_pending_action","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"action_public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PendingActionResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""},"409":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/readiness":{"get":{"tags":["AI Chat"],"summary":"Report which AI prerequisites this project satisfies.","description":"Read-only and cheap, so the UI can decide up front whether to show a working\nentry point, an onboarding path, or nothing — instead of letting the user\nclick something that fails with a 409 they can't act on.","operationId":"get_chat_readiness","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Which AI prerequisites are met","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatReadinessResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/alarms":{"get":{"tags":["Alarms"],"summary":"List alarms for a project with optional filters.","operationId":"listProjectAlarms","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"alarm_type","in":"query","description":"Filter by alarm type (e.g. `container_restart`, `outage`).","required":false,"schema":{"type":["string","null"]}},{"name":"status","in":"query","description":"Filter by status: `firing`, `acknowledged`, or `resolved`.","required":false,"schema":{"type":["string","null"]}},{"name":"severity","in":"query","description":"Filter by severity: `info`, `warning`, or `critical`.","required":false,"schema":{"type":["string","null"]}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"service_id","in":"query","description":"Filter by external service ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based, default 1).","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default 20, max 100).","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"Paginated list of alarms","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlarmListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/alarms/summary":{"get":{"tags":["Alarms"],"summary":"Get alarm counts by status/severity/type for a project (dashboard summary widget).","operationId":"getProjectAlarmsSummary","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alarm summary counts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlarmSummaryResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/alarms/{alarm_id}/acknowledge":{"post":{"tags":["Alarms"],"summary":"Acknowledge a firing alarm (marks it as seen but not resolved).","operationId":"acknowledgeAlarm","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"alarm_id","in":"path","description":"Alarm ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alarm acknowledged"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Alarm not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/alarms/{alarm_id}/resolve":{"post":{"tags":["Alarms"],"summary":"Resolve an alarm.","operationId":"resolveAlarm","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"alarm_id","in":"path","description":"Alarm ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alarm resolved"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Alarm not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/analyze":{"post":{"tags":["Autofixer"],"summary":"Start an autofixer analysis run for the given error group.\nCreates the run record immediately and spawns analysis in the background.","operationId":"start_analysis","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartAnalysisRequest"}}},"required":true},"responses":{"202":{"description":"Analysis started; returns run_id for streaming","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutofixerRunResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}":{"get":{"tags":["Autofixer"],"summary":"Get a single autofixer run with its logs.","operationId":"get_run","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Run with logs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutofixerRunWithLogsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/add-context":{"post":{"tags":["Autofixer"],"summary":"Append a user message to the run's context field.","operationId":"add_context","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddContextRequest"}}},"required":true},"responses":{"200":{"description":"Context appended"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/cancel":{"post":{"tags":["Autofixer"],"summary":"Cancel an autofixer run and clean up the work directory.","operationId":"cancel","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Run cancelled"},"400":{"description":"Run is already in a terminal state"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/create-pr":{"post":{"tags":["Autofixer"],"summary":"Push the fix branch and create a pull request.\nRequires phase == \"fix_ready\".","operationId":"create_pr","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"201":{"description":"PR created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePrResponse"}}}},"400":{"description":"Run not in fix_ready phase"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/fix":{"post":{"tags":["Autofixer"],"summary":"Transition from analysis to fix phase.\nRequires phase == \"analyzed\".","operationId":"start_fix","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Fix generation started"},"400":{"description":"Run not in analyzed phase"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/re-analyze":{"post":{"tags":["Autofixer"],"summary":"Continue the conversation with user feedback.\nUses the same Claude session (--continue) in the existing work directory.\nRequires phase == \"analyzed\".","operationId":"re_analyze","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Conversation continued with feedback"},"400":{"description":"Run not in analyzed phase"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/stream":{"get":{"tags":["Agents"],"summary":"SSE endpoint: streams run log events in real-time.\nPolls every 500 ms. Keeps the connection open through \"analyzed\" and \"fix_ready\"\nwaiting states; closes only on terminal statuses.","operationId":"stream_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Autofixer run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Server-Sent Events stream of autofixer run logs and status updates","content":{"text/event-stream":{}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/automatic-deploy":{"post":{"tags":["Projects"],"summary":"Update automatic deployment setting for a project","operationId":"update_automatic_deploy","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAutomaticDeployRequest"}}},"required":true},"responses":{"200":{"description":"Automatic deployment setting updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/custom-domains":{"get":{"tags":["Custom Domains"],"summary":"List all custom domains for a project","operationId":"list_custom_domains_for_project","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Custom domains retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListCustomDomainsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Custom Domains"],"summary":"Create a custom domain for a project","operationId":"create_custom_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainRequest"}}},"required":true},"responses":{"201":{"description":"Custom domain created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainResponse"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"409":{"description":"Domain already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/custom-domains/{domain_id}":{"get":{"tags":["Custom Domains"],"summary":"Get a custom domain by ID","operationId":"get_custom_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Custom domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Custom domain retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Custom domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Custom Domains"],"summary":"Update a custom domain","operationId":"update_custom_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Custom domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCustomDomainRequest"}}},"required":true},"responses":{"200":{"description":"Custom domain updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainResponse"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"404":{"description":"Custom domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Custom Domains"],"summary":"Delete a custom domain","operationId":"delete_custom_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Custom domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Custom domain deleted successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Custom domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/custom-domains/{domain_id}/link-certificate/{certificate_id}":{"post":{"tags":["Custom Domains"],"summary":"Link a custom domain to a certificate","operationId":"link_custom_domain_to_certificate","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Custom domain ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"certificate_id","in":"path","description":"Certificate ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Custom domain linked to certificate successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Custom domain or certificate not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployment-config":{"patch":{"tags":["Projects"],"summary":"Update deployment configuration for a project","operationId":"update_project_deployment_config","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDeploymentConfigRequest"}}},"required":true},"responses":{"200":{"description":"Deployment configuration updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"400":{"description":"Invalid deployment configuration"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployment-tokens":{"get":{"tags":["Deployment Tokens"],"summary":"List all deployment tokens for a project","operationId":"list_deployment_tokens","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of deployment tokens","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentTokenListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Deployment Tokens"],"summary":"Create a new deployment token for a project","operationId":"create_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDeploymentTokenRequest"}}},"required":true},"responses":{"201":{"description":"Deployment token created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDeploymentTokenResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"409":{"description":"Token with this name already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployment-tokens/{token_id}":{"get":{"tags":["Deployment Tokens"],"summary":"Get a specific deployment token","operationId":"get_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"token_id","in":"path","description":"Deployment token ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment token details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment token not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Deployment Tokens"],"summary":"Delete a deployment token","operationId":"delete_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"token_id","in":"path","description":"Deployment token ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Deployment token deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment token not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Deployment Tokens"],"summary":"Update a deployment token","operationId":"update_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"token_id","in":"path","description":"Deployment token ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDeploymentTokenRequest"}}},"required":true},"responses":{"200":{"description":"Deployment token updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentTokenResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment token not found"},"409":{"description":"Token with this name already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployment-tokens/{token_id}/rotate":{"post":{"tags":["Deployment Tokens"],"summary":"Rotate a deployment token, invalidating its old secret and issuing a new one","operationId":"rotate_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"token_id","in":"path","description":"Deployment token ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment token rotated successfully; the response contains the new plaintext token, shown only once","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDeploymentTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment token not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployments/{deployment_id}":{"get":{"tags":["Deployments"],"summary":"Get a specific deployment by ID for a project (identified by ID or slug)","operationId":"get_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentResponse"}}}},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/cancel":{"post":{"tags":["Projects"],"summary":"Cancel a deployment","operationId":"cancel_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment cancelled successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentStateResponse"}}}},"400":{"description":"Deployment cannot be cancelled (already completed, failed, or cancelled)"},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/container-logs":{"get":{"tags":["Deployments"],"summary":"List the captured (historical) container-log dumps for a deployment.","description":"Container runtime logs are normally only available live from the running\ncontainer. When a deployment is superseded its containers are torn down and\nthose logs would be lost — so just before teardown we capture each\ncontainer's logs to durable storage. This endpoint lists what was captured\nfor a given (often older) deployment, so a user can read the logs of a\ncontainer that no longer exists.","operationId":"list_deployment_container_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Captured container logs for the deployment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentContainerLogsListResponse"}}}},"404":{"description":"Deployment not found in this project"},"500":{"description":"Internal server error"}},"security":[{"bearer_token":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/container-logs/{log_id}":{"get":{"tags":["Deployments"],"summary":"Get the captured text content of a single historical container-log dump.","operationId":"get_deployment_container_log_content","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"log_id","in":"path","description":"Captured log ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Captured container log content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentContainerLogContentResponse"}}}},"404":{"description":"Captured log not found in this project"},"500":{"description":"Internal server error"}},"security":[{"bearer_token":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/jobs":{"get":{"tags":["Deployments"],"summary":"Get jobs for a specific deployment","description":"Returns all jobs (workflow tasks) for a deployment, ordered by execution order.\nThis replaces the old deployment stages endpoint.","operationId":"get_deployment_jobs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Jobs retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentJobsResponse"}}}},"404":{"description":"Deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/jobs/{job_id}/logs":{"get":{"tags":["Deployments"],"summary":"Get logs for a specific deployment job","operationId":"get_deployment_job_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"job_id","in":"path","description":"Job ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Job logs retrieved successfully","content":{"text/plain":{"schema":{"type":"string"}}}},"404":{"description":"Job or logs not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_token":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/jobs/{job_id}/logs/tail":{"get":{"tags":["Deployments"],"summary":"Tail logs for a specific deployment job in real-time via WebSocket","description":"**WebSocket Streaming**: Logs are sent as raw text, one line per WebSocket message.\n\n**Authentication**: Requires authentication via session cookie (browser clients)\nor API key (API clients). For browser-based WebSocket connections, ensure the user\nis logged in - the browser automatically includes session cookies in the WebSocket\nupgrade request.\n\n**API Client Authentication**: Include API key in Authorization header:\n```text\nAuthorization: Bearer tk_your_api_key_here\n```","operationId":"tail_deployment_job_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"job_id","in":"path","description":"Job ID","required":true,"schema":{"type":"string"}}],"responses":{"101":{"description":"WebSocket connection established for streaming deployment job logs"},"404":{"description":"Job or logs not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_token":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/operations":{"get":{"tags":["Deployments"],"summary":"Get all operations for a deployment","operationId":"get_deployment_operations","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of operations","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperationResultsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Deployments"],"summary":"Execute a deployment operation (deploy, mark_complete, take_screenshot)","operationId":"execute_deployment_operation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteOperationRequest"}}},"required":true},"responses":{"202":{"description":"Operation executed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperationResultResponse"}}}},"400":{"description":"Invalid operation"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/operations/{operation_type}":{"get":{"tags":["Deployments"],"summary":"Get the status of a specific operation type","operationId":"get_deployment_operation_status","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","required":true,"schema":{"type":"string"}},{"name":"operation_type","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Operation status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperationResultResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Operation not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/pause":{"post":{"tags":["Projects"],"summary":"Pause a deployment","operationId":"pause_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment paused successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentStateResponse"}}}},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/promote":{"post":{"tags":["Deployments"],"summary":"Promote a deployment to another environment","description":"Creates a new deployment in the target environment using the source deployment's\nDocker image. Useful for promoting a validated preview/staging deployment to production.","operationId":"promote_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Source deployment ID to promote","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromoteDeploymentRequest"}}},"required":true},"responses":{"200":{"description":"Promotion initiated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentResponse"}}}},"400":{"description":"Invalid deployment state for promotion"},"404":{"description":"Project, deployment, or target environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/resume":{"post":{"tags":["Projects"],"summary":"Resume a deployment","operationId":"resume_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment resumed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentStateResponse"}}}},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/rollback":{"post":{"tags":["Projects"],"operationId":"rollback_to_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID to rollback to","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Rollback initiated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentResponse"}}}},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/teardown":{"delete":{"tags":["Projects"],"summary":"Teardown a specific deployment","operationId":"teardown_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Deployment torn down successfully"},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/dsns":{"get":{"tags":[],"summary":"List all DSNs for a project","operationId":"list_dsns","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of DSNs","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectDSNResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":[],"summary":"Create a new DSN for a project","operationId":"create_dsn","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDSNRequest"}}},"required":true},"responses":{"201":{"description":"DSN created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDSNResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/dsns/get-or-create":{"post":{"tags":[],"summary":"Get or create DSN for a project/environment/deployment combination","operationId":"get_or_create_dsn","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetOrCreateDSNRequest"}}},"required":true},"responses":{"200":{"description":"DSN retrieved or created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDSNResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/dsns/{dsn_id}/regenerate":{"post":{"tags":[],"summary":"Regenerate DSN keys (rotate keys)","operationId":"regenerate_dsn","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"dsn_id","in":"path","description":"DSN ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegenerateDSNRequest"}}},"required":true},"responses":{"200":{"description":"DSN keys regenerated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDSNResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"DSN not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/dsns/{dsn_id}/revoke":{"post":{"tags":[],"summary":"Revoke (deactivate) a DSN","operationId":"revoke_dsn","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"dsn_id","in":"path","description":"DSN ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"DSN revoked"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"DSN not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/env-vars":{"get":{"tags":["Projects"],"summary":"Get environment variables for a project, optionally filtered by environment","operationId":"get_environment_variables","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Optional environment ID to filter by","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environment variables","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentVariableResponse"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["Projects"],"summary":"Create a new environment variable","operationId":"create_environment_variable","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEnvironmentVariableRequest"}}},"required":true},"responses":{"201":{"description":"Environment variables created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableResponse"}}}},"400":{"description":"Invalid input"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/env-vars/resolved":{"get":{"tags":["Projects"],"summary":"Resolved env vars for a project (manual + integration-sourced, merged).","description":"Returns the effective set of environment variables a deployment would see,\ncombining manually-defined vars with those contributed by linked external\nservices (Postgres, Redis, S3, etc.). Each entry is tagged with its source\nso the UI can render an integration icon, and manual entries that shadow an\nintegration key carry a reference to the integration they override.\n\nValues are always returned as a masked preview. Use the per-key reveal\nendpoint for plaintext (audit-logged).","operationId":"get_resolved_environment_variables","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Optional environment ID to filter manual vars by","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Resolved environment variables","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ResolvedEnvVarResponse"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/env-vars/resolved/{key}/value":{"get":{"tags":["Projects"],"summary":"Reveal the plaintext value of a resolved environment variable.","description":"Mirrors `GET /projects/{id}/env-vars/{key}/value` but handles keys sourced\nfrom linked integrations (which are not stored in the `env_vars` table).\nResolution order mirrors the merged view:\n\n1. Manual env var with this key — this endpoint reads the manual store when\n the key exists there, then writes its own reveal audit event so callers\n can safely use one endpoint regardless of source.\n2. Integration env var supplied by a linked external service.\n\nReturns 404 when neither a manual var nor an integration produces the key.","operationId":"get_resolved_environment_variable_value","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Environment variable key","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Optional environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"var_id","in":"query","description":"Exact manual environment-variable row ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"service_id","in":"query","description":"Integration service ID shown by the resolved list","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Resolved environment variable value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableValueResponse"}}}},"403":{"description":"Plaintext secret access is not permitted"},"404":{"description":"Project, key, or integration not found"},"409":{"description":"Environment variable key is ambiguous"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/env-vars/{key}/value":{"get":{"tags":["Projects"],"summary":"Get environment variable value by key","operationId":"get_environment_variable_value","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Environment variable key","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Optional environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"var_id","in":"query","description":"Exact environment-variable row ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Environment variable value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableValueResponse"}}}},"403":{"description":"Plaintext secret access is not permitted"},"404":{"description":"Project or variable not found"},"409":{"description":"Environment variable key is ambiguous"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/env-vars/{var_id}":{"put":{"tags":["Projects"],"summary":"Update an environment variable","operationId":"update_environment_variable","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"var_id","in":"path","description":"Environment variable ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEnvironmentVariableRequest"}}},"required":true},"responses":{"200":{"description":"Environment variables updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableResponse"}}}},"400":{"description":"Invalid input"},"404":{"description":"Project or variable not found"},"500":{"description":"Internal server error"}}},"delete":{"tags":["Projects"],"summary":"Delete an environment variable","operationId":"delete_environment_variable","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"var_id","in":"path","description":"Environment variable ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Environment variable deleted successfully"},"404":{"description":"Project or variable not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments":{"get":{"tags":["Projects"],"summary":"Get all environments for a project","operationId":"get_environments","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environments","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentResponse"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["Projects"],"summary":"Create a new environment for a project","operationId":"create_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEnvironmentRequest"}}},"required":true},"responses":{"201":{"description":"Environment created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"400":{"description":"Invalid input"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}":{"get":{"tags":["Projects"],"summary":"Get a specific environment by ID or slug","operationId":"get_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Environment details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}},"delete":{"tags":["Projects"],"summary":"Delete an environment permanently","description":"Permanently deletes an environment and all related data. Cannot delete:\n- Production environments (name = \"Production\")\n\nWarning: This action is permanent and cannot be undone.\nActive deployments are automatically cancelled before deletion.","operationId":"delete_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Environment permanently deleted"},"400":{"description":"Cannot delete production environment"},"404":{"description":"Project or environment not found"},"428":{"description":"Recent MFA verification required"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/crons":{"get":{"tags":["Crons"],"operationId":"get_environment_crons","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of cron jobs","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CronInfo"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/crons/{cron_id}":{"get":{"tags":["Crons"],"operationId":"get_cron_by_id","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"cron_id","in":"path","description":"Cron Job ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Cron job details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CronInfo"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Cron job not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/crons/{cron_id}/executions":{"get":{"tags":["Crons"],"operationId":"get_cron_executions","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"cron_id","in":"path","description":"Cron Job ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"per_page","in":"query","description":"Items per page (default: 20)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"List of cron job executions","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CronExecutionInfo"}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Cron job not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/domains":{"get":{"tags":["Projects"],"summary":"Get all environment domains for a specific environment","operationId":"get_environment_domains","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environment domains","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentDomainResponse"}}}}},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["Projects"],"summary":"Add a new environment domain","operationId":"add_environment_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddEnvironmentDomainRequest"}}},"required":true},"responses":{"201":{"description":"Domain added successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentDomainResponse"}}}},"400":{"description":"Invalid input"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/domains/{domain_id}":{"delete":{"tags":["Projects"],"summary":"Delete an environment domain","operationId":"delete_environment_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Domain deleted successfully"},"404":{"description":"Project, environment, or domain not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/settings":{"put":{"tags":["Projects"],"summary":"Update environment settings","operationId":"update_environment_settings","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEnvironmentSettingsRequest"}}},"required":true},"responses":{"200":{"description":"Environment settings updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/sleep":{"post":{"tags":["Environments"],"summary":"Sleep an on-demand environment","description":"Manually put an on-demand environment to sleep. Stops containers and sets\n`sleeping = true`. If no OnDemandWaker is available, falls back to DB flag only.","operationId":"sleep_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Environment put to sleep","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"400":{"description":"On-demand not enabled for this environment"},"404":{"description":"Environment not found"},"429":{"description":"Too many state transitions, retry after cooldown"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/subdomain":{"patch":{"tags":["Projects"],"summary":"Rename the auto-managed subdomain for an environment.","description":"Replaces the environment's previous subdomain entirely — the old\nhostname stops resolving once the proxy reloads its route table.\nCustom domains attached to the environment are unaffected.","operationId":"update_environment_subdomain","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEnvironmentSubdomainRequest"}}},"required":true},"responses":{"200":{"description":"Subdomain updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"400":{"description":"Invalid subdomain or conflict with another environment"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/teardown":{"delete":{"tags":["Projects"],"summary":"Teardown an environment and all its active deployments","operationId":"teardown_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Environment torn down successfully"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/wake":{"post":{"tags":["Environments"],"summary":"Wake a sleeping on-demand environment","description":"Manually wake an environment that has been put to sleep by the on-demand\nidle timeout. Starts containers, waits for health checks, then sets\n`sleeping = false`. If no OnDemandWaker is available (proxy not running\nin same process), falls back to setting the DB flag only.","operationId":"wake_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Environment woken up","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"400":{"description":"On-demand not enabled for this environment"},"404":{"description":"Environment not found"},"429":{"description":"Too many state transitions, retry after cooldown"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/container-logs":{"get":{"tags":["Deployments"],"summary":"Get logs for a container in an environment via WebSocket","operationId":"get_container_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for logs","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"end_date","in":"query","description":"End date for logs","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tail","in":"query","description":"Number of lines to tail (or 'all')","required":false,"schema":{"type":"string"}},{"name":"container_name","in":"query","description":"Optional container name (defaults to first/primary container)","required":false,"schema":{"type":"string"}},{"name":"timestamps","in":"query","description":"Include timestamps in log output (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"follow","in":"query","description":"Follow log output in real-time (default: true)","required":false,"schema":{"type":"boolean"}}],"responses":{"101":{"description":"WebSocket connection established for streaming container logs"},"400":{"description":"Not a server-type project"},"404":{"description":"Project, deployment, or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers":{"get":{"tags":["Deployments"],"summary":"List all containers for an environment","operationId":"list_containers","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of containers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerListResponse"}}}},"400":{"description":"Not a server-type project"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}":{"get":{"tags":["Containers"],"summary":"Get detailed information about a specific container","operationId":"get_container_detail","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerDetailResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/environment/{variable_name}":{"get":{"tags":["Containers"],"operationId":"get_container_environment_variable","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}},{"name":"variable_name","in":"path","description":"Environment variable name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Environment variable value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerEnvironmentVariableValueResponse"}}}},"403":{"description":"Plaintext secret access is not permitted"},"404":{"description":"Container or environment variable not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/logs":{"get":{"tags":["Deployments"],"summary":"Get logs for a specific container by container ID via WebSocket","operationId":"get_container_logs_by_id","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}},{"name":"start_date","in":"query","description":"Start date for logs","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"end_date","in":"query","description":"End date for logs","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tail","in":"query","description":"Number of lines to tail (or 'all')","required":false,"schema":{"type":"string"}},{"name":"timestamps","in":"query","description":"Include timestamps in log output (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"follow","in":"query","description":"Follow log output in real-time (default: true)","required":false,"schema":{"type":"boolean"}}],"responses":{"101":{"description":"WebSocket connection established for streaming container logs"},"400":{"description":"Not a server-type project"},"404":{"description":"Project, environment, or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/metrics":{"get":{"tags":["Containers"],"summary":"Get metrics/stats for a specific container","operationId":"get_container_metrics","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container metrics retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerMetricsResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/metrics/history":{"get":{"tags":["Containers"],"summary":"Fetch a time-series range for a single container resource metric\n(recorded by the container health monitor every ~30s).","description":"Useful metric names: `container.cpu_percent`,\n`container.cpu_utilization_percent`, `container.memory_used_bytes`,\n`container.memory_percent`, `container.network_rx_bytes_delta`,\n`container.network_tx_bytes_delta`.","operationId":"ContainerMetricsGetHistory","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}},{"name":"metric","in":"query","description":"Dotted metric name, e.g. `container.cpu_percent` or\n`container.memory_used_bytes`.","required":true,"schema":{"type":"string"}},{"name":"range","in":"query","description":"Time window: `1h`, `6h`, `24h`, or `7d` (defaults to `1h`).","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Metric time series data points","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ContainerMetricHistoryPoint"}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Container not found"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/metrics/stream":{"get":{"tags":["Containers"],"summary":"Stream container metrics via Server-Sent Events (SSE)","operationId":"stream_container_metrics","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}},{"name":"interval","in":"query","description":"Update interval in milliseconds (default: 1000)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Metrics stream established (Server-Sent Events)"},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/restart":{"post":{"tags":["Containers"],"summary":"Restart a container","operationId":"restart_container","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container restarted successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerActionResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/start":{"post":{"tags":["Containers"],"summary":"Start a container","operationId":"start_container","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container started successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerActionResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/stop":{"post":{"tags":["Containers"],"summary":"Stop a specific container","operationId":"stop_container","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container stopped successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerActionResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/deploy/image":{"post":{"tags":["Deployments"],"summary":"Deploy from an external Docker image","description":"Triggers a deployment using a pre-built Docker image from an external registry.\nThe image will be pulled and deployed to the specified environment.","operationId":"deploy_from_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeployFromImageRequest"}}},"required":true},"responses":{"202":{"description":"Deployment started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoteDeploymentResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/deploy/image-upload":{"post":{"tags":["Deployments"],"summary":"Deploy from an uploaded Docker image tarball","description":"Uploads a Docker image tarball (from `docker save`) and deploys it directly.\nThe image is imported using `docker load` and then deployed to the specified environment.\nThis is useful when you want to deploy an image without pushing to a registry first.\n\nThe uploaded file should be a tarball created by `docker save myimage:tag > image.tar`\nor `docker save myimage:tag | gzip > image.tar.gz` (gzip compressed tarballs are also supported).","operationId":"deploy_from_image_upload","parameters":[{"name":"tag","in":"query","description":"Tag to apply to the imported image (e.g., \"myapp:v1.0\")\nIf not provided, a unique tag will be generated","required":false,"schema":{"type":["string","null"]}},{"name":"health_check_path","in":"query","description":"Optional HTTP health-check path override (e.g. \"/api/healthz\").\nMust start with '/'. When omitted, defaults to \"/\".","required":false,"schema":{"type":["string","null"]}},{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Image imported and deployment started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoteDeploymentResponse"}}}},"400":{"description":"Invalid request or unsupported format"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project or environment not found"},"413":{"description":"Image tarball too large"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/deploy/source":{"post":{"tags":["Deployments"],"summary":"Upload source code and immediately start a preset-based deployment.","operationId":"deploy_from_uploaded_source","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/SourceArchiveUpload"}}},"required":true},"responses":{"202":{"description":"Source deployment started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoteDeploymentResponse"}}}},"400":{"description":"Invalid source archive"},"404":{"description":"Project or environment not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/deploy/static":{"post":{"tags":["Deployments"],"summary":"Deploy from an uploaded static bundle","description":"Triggers a deployment using a previously uploaded static file bundle.","operationId":"deploy_from_static","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeployFromStaticRequest"}}},"required":true},"responses":{"202":{"description":"Deployment started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoteDeploymentResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project, environment, or bundle not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/error-alert-rules":{"get":{"tags":["error-alert-rules"],"summary":"List all alert rules for a project","operationId":"list_alert_rules","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of alert rules","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AlertRuleResponse"}}}}},"500":{"description":"Internal server error"}}},"post":{"tags":["error-alert-rules"],"summary":"Create a new alert rule","operationId":"create_alert_rule","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAlertRuleRequest"}}},"required":true},"responses":{"201":{"description":"Alert rule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertRuleResponse"}}}},"400":{"description":"Validation error"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-alert-rules/{rule_id}":{"get":{"tags":["error-alert-rules"],"summary":"Get a specific alert rule","operationId":"get_alert_rule","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alert rule details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertRuleResponse"}}}},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}}},"put":{"tags":["error-alert-rules"],"summary":"Update an existing alert rule","operationId":"update_alert_rule","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAlertRuleRequest"}}},"required":true},"responses":{"200":{"description":"Alert rule updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertRuleResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}}},"delete":{"tags":["error-alert-rules"],"summary":"Delete an alert rule","operationId":"delete_alert_rule","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Alert rule deleted"},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-dashboard-stats":{"get":{"tags":["error-tracking"],"summary":"Get error dashboard statistics","operationId":"get_error_dashboard_stats","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"end_time","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"environment_id","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"compare_to_previous","in":"query","required":false,"schema":{"type":["boolean","null"]}}],"responses":{"200":{"description":"Error dashboard statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDashboardStatsResponse"}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-groups":{"get":{"tags":["error-tracking"],"summary":"List error groups for a project","operationId":"list_error_groups","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"status","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"environment_id","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_date","in":"query","required":false,"schema":{"type":["string","null"],"format":"date-time"}},{"name":"end_date","in":"query","required":false,"schema":{"type":["string","null"],"format":"date-time"}},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated list of error groups","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedErrorGroupsResponse"}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-groups/{group_id}":{"get":{"tags":["error-tracking"],"summary":"Get a specific error group","operationId":"get_error_group","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"group_id","in":"path","description":"Error group ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Error group details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorGroupResponse"}}}},"404":{"description":"Error group not found"},"500":{"description":"Internal server error"}}},"put":{"tags":["error-tracking"],"summary":"Update error group status","operationId":"update_error_group","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"group_id","in":"path","description":"Error group ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateErrorGroupRequest"}}},"required":true},"responses":{"200":{"description":"Error group updated successfully"},"404":{"description":"Error group not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-groups/{group_id}/events":{"get":{"tags":["error-tracking"],"summary":"List error events for a specific group","operationId":"list_error_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"group_id","in":"path","description":"Error group ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Paginated list of error events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedErrorEventsResponse"}}}},"404":{"description":"Error group not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-groups/{group_id}/events/{event_id}":{"get":{"tags":["error-tracking"],"summary":"Get a specific error event","operationId":"get_error_event","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"group_id","in":"path","description":"Error group ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"event_id","in":"path","description":"Error event ID","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Error event details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEventResponse"}}}},"404":{"description":"Event not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-stats":{"get":{"tags":["error-tracking"],"summary":"Get error statistics for a project","operationId":"get_error_stats","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Error statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorGroupStatsResponse"}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-time-series":{"get":{"tags":["error-tracking"],"summary":"Get error time series data for charts","operationId":"get_error_time_series","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"end_time","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"bucket","in":"query","description":"Time bucket size (e.g., \"1h\", \"15m\", \"1d\", \"1 hour\", \"30 minutes\")","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Error time series data","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ErrorTimeSeriesDataResponse"}}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/events":{"get":{"tags":["Events"],"summary":"Get event counts with filtering","operationId":"get_events_count","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering events","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering events","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Maximum number of events to return (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"custom_events_only","in":"query","description":"Only return custom events, excluding system events like page_view, page_leave, heartbeat (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors (default: events)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved event counts","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventCount"}}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/breakdown":{"get":{"tags":["Events"],"summary":"Get event type breakdown","operationId":"get_event_type_breakdown","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering events","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering events","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors (default: events)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved event type breakdown","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventTypeBreakdown"}}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/ingest":{"post":{"tags":["Events"],"summary":"Record an analytics event via the console API with explicit project ID.","description":"The app backend forwards the user's encrypted Temps cookies, so visitor/session\nidentity is resolved automatically by middleware. No geolocation or user-agent\nenrichment is performed — this is a lightweight server-side ingestion path.","operationId":"record_console_event","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsoleEventPayload"}}},"required":true},"responses":{"200":{"description":"Event recorded successfully"},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/properties/breakdown":{"get":{"tags":["Events"],"summary":"Get property breakdown by grouping events by a column","operationId":"get_property_breakdown","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"group_by","in":"query","description":"Column to group by (channel, device_type, browser, etc.)","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"event_name","in":"query","description":"Filter by event name","required":false,"schema":{"type":"string"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors - default: events","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Maximum number of results (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"include_crawlers","in":"query","description":"Include crawler/bot traffic (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"filter_country","in":"query","description":"Filter by country (for region/city drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Filter by region (for city drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_browser","in":"query","description":"Filter by browser name (for version drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_os","in":"query","description":"Filter by OS name (for version drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_channel","in":"query","description":"Filter by channel name (for channel drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_referrer","in":"query","description":"Filter by referrer hostname (for referrer drill-downs)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved property breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PropertyBreakdownResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/properties/timeline":{"get":{"tags":["Events"],"summary":"Get property timeline by grouping events by a column over time","operationId":"get_property_timeline","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"group_by","in":"query","description":"Column to group by (channel, device_type, browser, etc.)","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"event_name","in":"query","description":"Filter by event name","required":false,"schema":{"type":"string"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors - default: events","required":false,"schema":{"type":"string"}},{"name":"bucket_size","in":"query","description":"Time bucket: hour, day, week, month (default: auto-detect)","required":false,"schema":{"type":"string"}},{"name":"include_crawlers","in":"query","description":"Include crawler/bot traffic (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Successfully retrieved property timeline","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PropertyTimelineResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/timeline":{"get":{"tags":["Events"],"summary":"Get events timeline","operationId":"get_events_timeline","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering events","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering events","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"event_name","in":"query","description":"Filter by specific event name","required":false,"schema":{"type":"string"}},{"name":"bucket_size","in":"query","description":"Bucket size: hour, day, or week (auto-detected if not specified)","required":false,"schema":{"type":"string"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors (default: events)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved events timeline","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventTimeline"}}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/unique":{"get":{"tags":["Funnels"],"summary":"Get all unique/distinct event types for a project (paginated)","operationId":"get_unique_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Unique event types retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventTypesResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/external-images":{"get":{"tags":["External Images"],"summary":"List external images for a project","operationId":"list_remote_external_images","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default: 20)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of external images","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedExternalImagesResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["External Images"],"summary":"Register an external Docker image","description":"Registers an external Docker image reference without triggering a deployment.\nThe image can be deployed later using the deploy/image endpoint.","operationId":"register_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterImageRequest"}}},"required":true},"responses":{"201":{"description":"Image registered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalImageResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/external-images/{image_id}":{"get":{"tags":["External Images"],"summary":"Get details of a specific external image","operationId":"get_remote_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"image_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Image details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalImageResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Image not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["External Images"],"summary":"Delete an external image","operationId":"delete_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"image_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Image deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Image not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/flags":{"get":{"tags":["Feature Flags"],"operationId":"list_flags","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"include_archived","in":"query","description":"Include archived flags. Defaults to false.","required":false,"schema":{"type":"boolean"}},{"name":"page","in":"query","description":"1-indexed page number. Defaults to 1.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page. Defaults to 20, capped at 100.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"Flags listed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Feature Flags"],"operationId":"create_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFlagRequest"}}},"required":true},"responses":{"201":{"description":"Flag created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"409":{"description":"Flag key already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/flags/{key}":{"get":{"tags":["Feature Flags"],"operationId":"get_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Flag retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Feature Flags"],"operationId":"archive_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Flag archived","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArchiveFlagResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Feature Flags"],"operationId":"update_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateFlagRequest"}}},"required":true},"responses":{"200":{"description":"Flag updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/flags/{key}/environments/{environment_id}":{"put":{"tags":["Feature Flags"],"summary":"Set a flag's value in one environment, and/or flip its kill switch.","operationId":"set_flag_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetFlagEnvironmentRequest"}}},"required":true},"responses":{"200":{"description":"Environment value set","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagEnvironmentResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag or environment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/flags/{key}/restore":{"post":{"tags":["Feature Flags"],"summary":"Bring an archived flag back.","description":"Archiving is otherwise one-way: the key stays reserved so the flag cannot\neven be re-created under the same name, which makes an accidental archive\nunrecoverable through the API.","operationId":"restore_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Flag restored","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/funnels":{"get":{"tags":["Funnels"],"summary":"List all funnels for a project","operationId":"list_funnels","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Funnels retrieved successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/FunnelResponse"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Funnels"],"summary":"Create a new funnel","operationId":"create_funnel","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFunnelRequest"}}},"required":true},"responses":{"201":{"description":"Funnel created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFunnelResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/funnels/preview":{"post":{"tags":["Funnels"],"summary":"Preview funnel metrics without creating the funnel","operationId":"preview_funnel_metrics","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFunnelRequest"}}},"required":true},"responses":{"200":{"description":"Funnel metrics preview","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FunnelMetricsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/funnels/{funnel_id}":{"put":{"tags":["Funnels"],"summary":"Update a funnel","operationId":"update_funnel","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"funnel_id","in":"path","description":"Funnel ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFunnelRequest"}}},"required":true},"responses":{"200":{"description":"Funnel updated successfully"},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"404":{"description":"Funnel not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Funnels"],"summary":"Delete a funnel","operationId":"delete_funnel","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"funnel_id","in":"path","description":"Funnel ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Funnel deleted successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Funnel not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/funnels/{funnel_id}/metrics":{"get":{"tags":["Funnels"],"summary":"Get funnel metrics","operationId":"get_funnel_metrics","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"funnel_id","in":"path","description":"Funnel ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID filter","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"country_code","in":"query","description":"Country code filter","required":false,"schema":{"type":"string"}},{"name":"start_date","in":"query","description":"Start date filter (ISO 8601)","required":false,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date filter (ISO 8601)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Funnel metrics retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FunnelMetricsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"404":{"description":"Funnel not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/git":{"post":{"tags":["Projects"],"summary":"Update git settings for a project","operationId":"update_git_settings","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateGitSettingsRequest"}}},"required":true},"responses":{"200":{"description":"Git settings updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"400":{"description":"Invalid git configuration or branch does not exist"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/gitlab/reinstall-webhook":{"post":{"tags":["Projects"],"summary":"Reinstall the GitLab webhook for a project","description":"Removes the existing webhook (if any) and installs a fresh one.\nUse this when a webhook has been manually deleted on the GitLab side\nand automatic deployments have stopped working.","operationId":"reinstall_gitlab_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Webhook reinstalled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReinstallWebhookResponse"}}}},"400":{"description":"Project is not connected to a GitLab repository"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/has-error-groups":{"get":{"tags":["error-tracking"],"summary":"Check if project has any error groups","operationId":"has_error_groups","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Error groups existence check","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HasErrorGroupsResponse"}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/has-events":{"get":{"tags":["Events"],"summary":"Check if project has any analytics events","operationId":"has_analytics_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully checked for events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HasEventsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/hourly-visits":{"get":{"tags":["Events"],"summary":"Get hourly visits","operationId":"get_hourly_visits","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering visits","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering visits","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events (page views), sessions (unique sessions), or visitors (unique visitors) - default: events","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved hourly visits","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventTimeline"}}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/images":{"get":{"tags":["External Images"],"summary":"List all external images for a project","operationId":"list_external_images","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of external images","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PushedExternalImageResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/images/push":{"post":{"tags":["External Images"],"summary":"Push an external Docker image","operationId":"push_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushImageRequest"}}},"required":true},"responses":{"201":{"description":"Image pushed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushedExternalImageResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/images/{image_id}":{"get":{"tags":["External Images"],"summary":"Get details of a specific external image","operationId":"get_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"image_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Image details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushedExternalImageResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Image not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/incidents":{"get":{"tags":["Status Page"],"summary":"List incidents for a project","operationId":"list_incidents","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"status","in":"query","description":"Filter by status","required":false,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Successfully retrieved incidents"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Status Page"],"summary":"Create a new incident","operationId":"create_incident","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIncidentRequest"}}},"required":true},"responses":{"201":{"description":"Incident created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/incidents/bucketed":{"get":{"tags":["Status Page"],"summary":"Get bucketed incident data for a project","operationId":"get_bucketed_incidents","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"interval","in":"query","description":"Bucket interval: '5min', 'hourly', or 'daily' (default: hourly)","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601) (default: 7 days ago)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (ISO 8601) (default: now)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved bucketed incident data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentBucketedResponse"}}}},"400":{"description":"Invalid parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/logs":{"delete":{"tags":["Logs"],"summary":"Purge all logs for a project before a given timestamp","operationId":"purge_project_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurgeLogsRequest"}}},"required":true},"responses":{"200":{"description":"Purge completed"},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/mcp-servers":{"get":{"tags":["Agents"],"operationId":"list_mcps","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListMcpsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_mcp","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMcpRequest"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/mcp-servers/{slug}":{"get":{"tags":["Agents"],"operationId":"get_mcp","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_mcp","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMcpRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_mcp","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"MCP server deleted"},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/mcp-servers/{slug}/config/{field}":{"get":{"tags":["Agents"],"operationId":"reveal_mcp_config","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}},{"name":"field","in":"path","description":"Sensitive field path, such as url or env.API_TOKEN","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensitiveMcpConfigValueResponse"}}}},"400":{"description":"Field is not revealable"},"401":{"description":"Unauthorized"},"403":{"description":"Missing secrets:read permission"},"404":{"description":"MCP server or field not found"},"500":{"description":"Configuration read or audit failed"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/monitors":{"get":{"tags":["Status Page"],"summary":"List monitors for a project","operationId":"list_monitors","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved monitors","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MonitorResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Status Page"],"summary":"Create a new monitor","operationId":"create_monitor","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMonitorRequest"}}},"required":true},"responses":{"201":{"description":"Monitor created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/observe/events":{"get":{"tags":["Observability"],"summary":"List a merged page of observability events for a project.","description":"Each row carries everything the side panel needs to render — no\nfollow-up fetch is required for the common case. Heavy fields\n(stacktraces, headers, span attributes) are truncated server-side and\nexpose a `*_truncated` flag; clients fetch the full row from the\n`/full` endpoint only when the user explicitly clicks \"Show full\".","operationId":"observability_list_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"kinds","in":"query","description":"Comma-separated kinds: `log,request,span,error,revenue`. Empty or\nmissing returns every kind.","required":false,"schema":{"type":"string"}},{"name":"from","in":"query","description":"Inclusive lower bound on event timestamp (ISO 8601, `Z` suffix).","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","description":"Inclusive upper bound on event timestamp.","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"deployment_id","in":"query","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"search","in":"query","description":"Free-text substring matched against per-kind summary fields\n(request path / error class / revenue event_type).","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Page size (default 50, max 200).","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"hide_bots","in":"query","description":"When `true`, exclude bot/crawler request rows. When `false`, only\ninclude bot rows. Omitted means \"include everything\" (default).\nOnly affects the `Request` kind.","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Merged event page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventsResponse"}}}},"400":{"description":"Invalid filter (kinds, time range, …)","content":{"text/plain":{"schema":{"type":"string"}}}},"401":{"description":"Unauthorized","content":{"text/plain":{"schema":{"type":"string"}}}},"403":{"description":"Insufficient permissions","content":{"text/plain":{"schema":{"type":"string"}}}},"500":{"description":"Internal server error","content":{"text/plain":{"schema":{"type":"string"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/observe/events/{kind}/{event_id}/full":{"get":{"tags":["Observability"],"summary":"Fetch the un-truncated form of one event by `(kind, id)`. Side panel\n\"Show full\" action calls this — the list response carries truncated\npreviews + a `*_truncated` flag to let the UI decide whether to fetch.","operationId":"observability_full_event","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"kind","in":"path","description":"Event kind discriminator","required":true,"schema":{"$ref":"#/components/schemas/EventKind"}},{"name":"event_id","in":"path","description":"Per-kind identity: request_id for requests, `{trace_id}:{span_id}` for spans, serial id for errors/revenue","required":true,"schema":{"type":"string"}},{"name":"ts","in":"query","description":"The row's event timestamp as returned by the list endpoint. Optional,\nbut strongly recommended: it bounds the lookup to the storage\npartitions/chunks around that instant instead of scanning the whole\nretention window.","required":false,"schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"Full row","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FullEvent"}}}},"401":{"description":"Unauthorized","content":{"text/plain":{"schema":{"type":"string"}}}},"403":{"description":"Insufficient permissions","content":{"text/plain":{"schema":{"type":"string"}}}},"404":{"description":"Event not found in project","content":{"text/plain":{"schema":{"type":"string"}}}},"500":{"description":"Internal server error","content":{"text/plain":{"schema":{"type":"string"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/releases/{release}/source-files":{"get":{"tags":["source-maps"],"summary":"List uploaded source files for a release (metadata only).","operationId":"list_source_files","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of source files","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceFileListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["source-maps"],"summary":"Upload a raw source file for a release (native symbolication).","description":"Accepts a multipart form with:\n- `file`: the source file bytes (required)\n- `file_path`: the path of the file as it appears in stack frames (required;\n derived from the uploaded filename if omitted). Normalized with the `~`\n prefix convention, matching source-map storage.\n\nRequires the project's `error_source_context_enabled` toggle to be on.\nUpserts on (project, release, file_path).","operationId":"upload_source_file","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"Source file uploaded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceFileResponse"}}}},"400":{"description":"Missing fields"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"409":{"description":"Source context disabled for project"},"413":{"description":"Source file too large"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["source-maps"],"summary":"Delete all uploaded source files for a release.","operationId":"delete_release_source_files","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Source files deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/releases/{release}/source-maps":{"get":{"tags":["source-maps"],"summary":"List all source maps for a specific release","operationId":"list_source_maps","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of source maps","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceMapListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["source-maps"],"summary":"Upload a source map for a release.","description":"Accepts a multipart form with:\n- `file`: The .map file (required)\n- `file_path`: The URL path of the minified file as it appears in stack traces (required).\n Uses the ~ prefix convention (e.g., \"~/assets/main.js\").\n If a full URL is provided, it will be normalized automatically.\n- `dist`: Optional distribution identifier\n\nIf a source map already exists for the same (project, release, file_path), it is replaced.","operationId":"upload_source_map","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"Source map uploaded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceMapResponse"}}}},"400":{"description":"Invalid source map or missing fields"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"413":{"description":"Source map too large"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["source-maps"],"summary":"Delete all source maps for a specific release","operationId":"delete_release_source_maps","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Source maps deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/events":{"get":{"tags":["Revenue"],"summary":"Recent ingested events for the activity feed.","operationId":"revenue_recent_events","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RecentEventResponse"}}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations":{"get":{"tags":["Revenue"],"summary":"List revenue integrations for a project.","operationId":"revenue_list_integrations","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/IntegrationResponse"}}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Revenue"],"summary":"Create a new revenue integration. Response contains the generated\nwebhook path that the user must paste into their provider's dashboard.","operationId":"revenue_create_integration","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIntegrationBody"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationResponse"}}}},"400":{"description":"Validation error"},"409":{"description":"Already connected"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}":{"delete":{"tags":["Revenue"],"summary":"Delete a revenue integration (permanent — use rotate_token to refresh\ncredentials without breaking history).","operationId":"revenue_delete_integration","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/config":{"post":{"tags":["Revenue"],"summary":"Replace the typed provider config on an integration. Passing `null`\nclears the config back to the accept-everything default. The config's\nprovider tag must match the integration's provider.","operationId":"revenue_update_config","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateConfigBody"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Integration not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/import/invoices":{"post":{"tags":["Revenue"],"summary":"Import a Stripe invoices CSV export. Each paid invoice becomes an\n`invoice.paid` event so historical MRR/charge totals populate the\ntimeseries. Ingestion is idempotent: re-uploading the same file is a\nno-op.","operationId":"revenue_import_invoices_csv","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportOutcomeResponse"}}}},"400":{"description":"Malformed CSV or wrong provider"},"404":{"description":"Integration not found"},"413":{"description":"CSV too large"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/import/subscriptions":{"post":{"tags":["Revenue"],"summary":"Import a Stripe subscriptions CSV export. Use this to backfill MRR /\nactive subscriptions when migrating from Stripe without providing\nAPI keys. Webhooks remain the source of truth for live updates —\nCSV rows never overwrite newer webhook state.","operationId":"revenue_import_subscriptions_csv","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportOutcomeResponse"}}}},"400":{"description":"Malformed CSV or wrong provider"},"404":{"description":"Integration not found"},"413":{"description":"CSV too large"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/rotate-token":{"post":{"tags":["Revenue"],"summary":"Rotate the webhook path token. Returns the new integration state —\nthe user must paste the new URL into their provider's dashboard.","operationId":"revenue_rotate_token","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/update-secret":{"post":{"tags":["Revenue"],"summary":"Replace the stored signing secret without rotating the webhook URL.\nUse this after rotating the secret in the provider's dashboard.","operationId":"revenue_update_secret","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSecretBody"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Integration not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/metrics/customers":{"get":{"tags":["Revenue"],"summary":"New + churned customers per bucket.","operationId":"revenue_metrics_customers","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CustomerMovementResponse"}}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/metrics/mrr":{"get":{"tags":["Revenue"],"summary":"Bucketed MRR timeseries for the revenue chart.","operationId":"revenue_metrics_mrr","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MrrBucketResponse"}}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/metrics/summary":{"get":{"tags":["Revenue"],"summary":"Current MRR / ARR / churn / ARPU for a project, in one currency.","operationId":"revenue_metrics_summary","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetricsSummaryResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/secrets":{"get":{"tags":["Secrets"],"summary":"List project secrets (metadata only — values never returned).","operationId":"listProjectSecrets","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Optional environment filter","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of secrets (metadata only, no values)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectSecretResponse"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["Secrets"],"summary":"Create a new secret. The value is encrypted before storage and will be\nmounted as a file at `/run/secrets/` on the next deployment.\nThe plaintext value is NOT returned — the response carries only metadata.","operationId":"createProjectSecret","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectSecretRequest"}}},"required":true},"responses":{"201":{"description":"Secret created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectSecretResponse"}}}},"400":{"description":"Invalid key or value too large"},"409":{"description":"Key already exists in project"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/secrets/{secret_id}":{"put":{"tags":["Secrets"],"summary":"Update a project secret. Value rotation requires a redeploy to take effect —\nrunning containers keep their currently-mounted values until the next\ndeployment.","operationId":"updateProjectSecret","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"secret_id","in":"path","description":"Secret ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProjectSecretRequest"}}},"required":true},"responses":{"200":{"description":"Secret updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectSecretResponse"}}}},"400":{"description":"Value too large"},"404":{"description":"Secret not found"},"500":{"description":"Internal server error"}}},"delete":{"tags":["Secrets"],"summary":"Delete a project secret. Running containers keep their mounted secret files\nuntil they are redeployed.","operationId":"deleteProjectSecret","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"secret_id","in":"path","description":"Secret ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Secret deleted"},"404":{"description":"Secret not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/settings":{"post":{"tags":["Projects"],"summary":"Update project settings","operationId":"update_project_settings","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProjectSettingsRequest"}}},"required":true},"responses":{"200":{"description":"Project settings updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/skills":{"get":{"tags":["Agents"],"operationId":"list_skills","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSkillsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSkillRequest"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/skills/upload":{"post":{"tags":["Agents"],"summary":"Upload a skill with an archive (tar.gz) — project-scoped.","operationId":"upload_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"string"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/skills/{slug}":{"get":{"tags":["Agents"],"operationId":"get_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSkillRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Skill deleted"},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/skills/{slug}/archive":{"get":{"tags":["Agents"],"summary":"Download a skill's archive (tar.gz) — project-scoped.","operationId":"download_skill_archive","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Skill archive tar.gz","content":{"application/gzip":{}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found or has no archive"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/source-map-releases":{"get":{"tags":["source-maps"],"summary":"List all releases that have source maps for a project","operationId":"list_releases","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of releases","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReleaseListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/source-maps/{source_map_id}":{"delete":{"tags":["source-maps"],"summary":"Delete a specific source map by ID","operationId":"delete_source_map","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"source_map_id","in":"path","description":"Source map ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Source map deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Source map not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/static-bundles":{"get":{"tags":["Static Bundles"],"summary":"List static bundles for a project","operationId":"list_static_bundles","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default: 20)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of static bundles","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedStaticBundlesResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/static-bundles/{bundle_id}":{"get":{"tags":["Static Bundles"],"summary":"Get details of a specific static bundle","operationId":"get_static_bundle","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"bundle_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Bundle details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaticBundleResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Bundle not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Static Bundles"],"summary":"Delete a static bundle","operationId":"delete_static_bundle","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"bundle_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Bundle deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Bundle not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/status":{"get":{"tags":["Status Page"],"summary":"Get status page overview","operationId":"get_status_overview","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved status overview","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusPageOverview"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/unique-counts":{"get":{"tags":["Events"],"summary":"Get unique counts over time frame","operationId":"get_unique_counts","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"metric","in":"query","description":"Metric to count: 'sessions' (unique sessions), 'visitors' (unique visitors), 'returning_visitors' (visitors seen before the range), or 'page_views' (total page views) (default: 'sessions')","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved count","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UniqueCountsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/upload/static":{"post":{"tags":["Static Bundles"],"summary":"Upload a static bundle for later deployment","description":"Uploads a tar.gz or zip file containing static assets. The bundle can be\ndeployed later using the deploy/static endpoint.","operationId":"upload_static_bundle","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/SourceArchiveUpload"}}},"required":true},"responses":{"201":{"description":"Bundle uploaded successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaticBundleResponse"}}}},"400":{"description":"Invalid request or unsupported format"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"},"413":{"description":"Bundle too large"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/vulnerability-scans":{"get":{"tags":["Vulnerability Scans"],"operationId":"list_project_scans","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of vulnerability scans","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ScanResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Vulnerability Scans"],"operationId":"trigger_scan","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerScanRequest"}}},"required":true},"responses":{"202":{"description":"Scan triggered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerScanResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/vulnerability-scans/environments":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_latest_scans_per_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Latest scans per environment for current deployments","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ScanResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/vulnerability-scans/latest":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_latest_scan","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Latest scan for project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"No scans found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks":{"get":{"tags":["Webhooks"],"summary":"List all webhooks for a project","operationId":"list_webhooks","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of webhooks","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/WebhookResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Webhooks"],"summary":"Create a new webhook","operationId":"create_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookRequestBody"}}},"required":true},"responses":{"201":{"description":"Webhook created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks/{webhook_id}":{"get":{"tags":["Webhooks"],"summary":"Get a specific webhook","operationId":"get_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Webhook details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Webhook not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Webhooks"],"summary":"Update a webhook","operationId":"update_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWebhookRequestBody"}}},"required":true},"responses":{"200":{"description":"Webhook updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Webhook not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Webhooks"],"summary":"Delete a webhook","operationId":"delete_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Webhook deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Webhook not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks/{webhook_id}/deliveries":{"get":{"tags":["Webhook Deliveries"],"summary":"List webhook deliveries","operationId":"list_deliveries","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Number of deliveries to return (default: 50)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of deliveries","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/WebhookDeliveryResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks/{webhook_id}/deliveries/{delivery_id}":{"get":{"tags":["Webhook Deliveries"],"summary":"Get a specific webhook delivery by ID","operationId":"get_delivery","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"delivery_id","in":"path","description":"Delivery ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Delivery details including full payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeliveryResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Delivery not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks/{webhook_id}/deliveries/{delivery_id}/retry":{"post":{"tags":["Webhook Deliveries"],"summary":"Retry a failed delivery","operationId":"retry_delivery","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"delivery_id","in":"path","description":"Delivery ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Delivery retried","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeliveryResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Delivery not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/workflows/dry-run":{"post":{"tags":["Workflows"],"operationId":"workflow_dry_run","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkflowDryRunRequest"}}},"required":true},"responses":{"202":{"description":"Ephemeral run created and queued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunResponse"}}}},"400":{"description":"Validation error (bad YAML, oversized payload, capped limits exceeded)"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/proxy-logs":{"get":{"tags":["Proxy Logs"],"summary":"Get proxy logs with optional filters and pagination","operationId":"get_proxy_logs","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"session_id","in":"query","description":"Filter by session ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"visitor_id","in":"query","description":"Filter by visitor ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering (ISO 8601 format).\n\n**Defaults to 1 hour before `end_date` (or before now) when omitted.**\nThe listing is always time-bounded: an unbounded query would have to\nconsider the entire retention window — 100M+ rows on a busy deployment —\nto return a single page. Pass an explicit `start_date` to widen the\nwindow, up to the configured retention horizon.\n\nThe maximum span between `start_date` and `end_date` is 7 days when\n`project_id` is omitted, or 30 days when a single `project_id` is set —\na project-scoped query is bounded by that project's own row count\nrather than the whole deployment's. A wider request is rejected with a\n400 naming the applicable cap.","required":false,"schema":{"type":["string","null"],"format":"date-time"}},{"name":"end_date","in":"query","description":"End date for filtering (ISO 8601 format). Defaults to now.","required":false,"schema":{"type":["string","null"],"format":"date-time"}},{"name":"method","in":"query","description":"Filter by HTTP method (GET, POST, etc.)","required":false,"schema":{"type":["string","null"]}},{"name":"host","in":"query","description":"Filter by host header","required":false,"schema":{"type":["string","null"]}},{"name":"path","in":"query","description":"Filter by path (supports partial match)","required":false,"schema":{"type":["string","null"]}},{"name":"client_ip","in":"query","description":"Filter by client IP address","required":false,"schema":{"type":["string","null"]}},{"name":"status_code","in":"query","description":"Filter by HTTP status code","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"response_time_min","in":"query","description":"Filter by minimum response time in ms","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"response_time_max","in":"query","description":"Filter by maximum response time in ms","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"routing_status","in":"query","description":"Filter by routing status (routed, no_project, error, pending)","required":false,"schema":{"type":["string","null"]}},{"name":"request_source","in":"query","description":"Filter by request source (proxy, api, console, cli)","required":false,"schema":{"type":["string","null"]}},{"name":"is_system_request","in":"query","description":"Filter by system request flag","required":false,"schema":{"type":["boolean","null"]}},{"name":"user_agent","in":"query","description":"Filter by user agent string (partial match)","required":false,"schema":{"type":["string","null"]}},{"name":"browser","in":"query","description":"Filter by browser name","required":false,"schema":{"type":["string","null"]}},{"name":"operating_system","in":"query","description":"Filter by operating system","required":false,"schema":{"type":["string","null"]}},{"name":"device_type","in":"query","description":"Filter by device type (mobile, desktop, tablet)","required":false,"schema":{"type":["string","null"]}},{"name":"is_bot","in":"query","description":"Filter by bot detection","required":false,"schema":{"type":["boolean","null"]}},{"name":"exclude_bots","in":"query","description":"When `true`, exclude rows flagged as bots while KEEPING rows whose\n`is_bot` is NULL (older rows without detection metadata). This is the\ntri-state complement of `is_bot=false`, which matches only rows\nexplicitly detected as non-bots. `false`/omitted is a no-op.","required":false,"schema":{"type":["boolean","null"]}},{"name":"bot_name","in":"query","description":"Filter by bot name","required":false,"schema":{"type":["string","null"]}},{"name":"ai_provider","in":"query","description":"Filter by AI provider (e.g. `OpenAI`, `Anthropic`, `Perplexity`). Matches\nthe canonical provider returned by the AI agent detector.","required":false,"schema":{"type":["string","null"]}},{"name":"ai_agent","in":"query","description":"Filter by AI agent name (e.g. `GPTBot`, `ChatGPT-User`). Equivalent to\nfiltering `bot_name` against a known AI taxonomy.","required":false,"schema":{"type":["string","null"]}},{"name":"is_ai_agent","in":"query","description":"When `true`, only return requests classified as known AI agents\n(regardless of provider/agent). Mutually compatible with the above.","required":false,"schema":{"type":["boolean","null"]}},{"name":"request_size_min","in":"query","description":"Filter by minimum request size in bytes","required":false,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"request_size_max","in":"query","description":"Filter by maximum request size in bytes","required":false,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"response_size_min","in":"query","description":"Filter by minimum response size in bytes","required":false,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"response_size_max","in":"query","description":"Filter by maximum response size in bytes","required":false,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"cache_status","in":"query","description":"Filter by cache status","required":false,"schema":{"type":["string","null"]}},{"name":"container_id","in":"query","description":"Filter by container ID","required":false,"schema":{"type":["string","null"]}},{"name":"upstream_host","in":"query","description":"Filter by upstream host","required":false,"schema":{"type":["string","null"]}},{"name":"has_error","in":"query","description":"Filter by presence of error message","required":false,"schema":{"type":["boolean","null"]}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"sort_by","in":"query","description":"Sort by field (default: timestamp)","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","description":"Sort order (asc or desc, default: desc)","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of proxy logs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProxyLogsPaginatedResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/ai-agents/known":{"get":{"tags":["Proxy Logs"],"summary":"List every AI agent the detector knows how to classify.","description":"Returned in the same order as the internal taxonomy so the UI can use it as\na stable dropdown.","operationId":"list_known_ai_agents","responses":{"200":{"description":"Known AI agents","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KnownAiAgentsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/request/{request_id}":{"get":{"tags":["Proxy Logs"],"summary":"Get a proxy log by request ID (for tracing)","operationId":"get_proxy_log_by_request_id","parameters":[{"name":"request_id","in":"path","description":"Request ID from pingora","required":true,"schema":{"type":"string"}},{"name":"timestamp","in":"query","description":"Event time of the log row (ISO 8601). When provided, the lookup is\nbounded to the hypertable chunks around this instant instead of\nscanning (and decompressing) the whole retention window. The list\nendpoint already returns this value per row — always pass it when\nnavigating from a list.","required":false,"schema":{"type":["string","null"],"format":"date-time"}}],"responses":{"200":{"description":"Proxy log found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProxyLogResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Proxy log not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-agent-pages":{"get":{"tags":["Proxy Logs"],"summary":"Get the top pages accessed by a specific AI agent over a time window.","description":"Returns page paths ranked by request count, scoped to a single canonical\nagent name (e.g. `ChatGPT-User`). Use `GET /proxy-logs/ai-agents/known` to\nlist all valid agent names. Unknown agent names return an empty items array.","operationId":"get_ai_agent_pages","parameters":[{"name":"agent","in":"query","description":"Canonical agent name to filter by (e.g. `ChatGPT-User`, `ClaudeBot`).\nMust be a name returned by `GET /proxy-logs/ai-agents/known`.","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Filter by project ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"limit","in":"query","description":"Maximum rows to return. Capped at 100 server-side.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"Pages breakdown for the requested agent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiAgentPagesResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-agents":{"get":{"tags":["Proxy Logs"],"summary":"Get the per-AI-agent breakdown for a project over a time window.","operationId":"get_ai_agent_breakdown","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID (recommended for per-project analytics).","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"limit","in":"query","description":"Maximum rows to return. Capped at 100 server-side.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"path","in":"query","description":"Optional exact path filter. Only used by the AI pages breakdown — when\nset, returns the single matching page so callers can ask \"how many AI\nagents hit this page?\".","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"AI agent breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiAgentBreakdownResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-agents/timeline":{"get":{"tags":["Proxy Logs"],"summary":"Time-bucketed AI-agent request volume, split by provider or agent.","description":"Powers the \"AI agents over time\" stacked chart. Same data source as the AI\nagent breakdown (request logs), just bucketed.","operationId":"get_ai_agent_timeline","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"group_by","in":"query","description":"Grouping dimension: `provider` (default) or `agent`.","required":false,"schema":{"type":["string","null"]},"example":"provider"},{"name":"bucket","in":"query","description":"Bucket interval override (e.g. `1 hour`, `1 day`). Auto-selected from the\nwindow width when omitted.","required":false,"schema":{"type":["string","null"]},"example":"1 hour"}],"responses":{"200":{"description":"AI agent timeline","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiAgentTimelineResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-pages":{"get":{"tags":["Proxy Logs"],"summary":"Get the top pages crawled by AI agents over a time window.","operationId":"get_ai_page_breakdown","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID (recommended for per-project analytics).","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"limit","in":"query","description":"Maximum rows to return. Capped at 100 server-side.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"path","in":"query","description":"Optional exact path filter. Only used by the AI pages breakdown — when\nset, returns the single matching page so callers can ask \"how many AI\nagents hit this page?\".","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"AI page breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiPageBreakdownResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-status":{"get":{"tags":["Proxy Logs"],"summary":"HTTP status-class breakdown for AI-agent traffic — are bots being served\n(2xx) or hitting broken/blocked pages (4xx/5xx)?","operationId":"get_ai_status_breakdown","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID (recommended for per-project analytics).","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"limit","in":"query","description":"Maximum rows to return. Capped at 100 server-side.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"path","in":"query","description":"Optional exact path filter. Only used by the AI pages breakdown — when\nset, returns the single matching page so callers can ask \"how many AI\nagents hit this page?\".","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"AI status breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiStatusBreakdownResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/projects-health":{"get":{"tags":["Proxy Logs"],"summary":"Get health summaries for multiple projects (last 1 hour)","operationId":"get_projects_health","parameters":[{"name":"project_ids","in":"query","description":"Comma-separated list of project IDs","required":true,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Optional start time (ISO 8601). Defaults to `end_time - 1h`.","required":false,"schema":{"type":["string","null"]},"example":"2025-10-23T00:00:00Z"},{"name":"end_time","in":"query","description":"Optional end time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2025-10-23T23:59:59Z"},{"name":"is_bot","in":"query","description":"Filter by bot detection. Pass `false` to exclude bots, `true` for bots only.","required":false,"schema":{"type":["boolean","null"]}}],"responses":{"200":{"description":"Health summaries per project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectsHealthResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/time-buckets":{"get":{"tags":["Proxy Logs"],"summary":"Get time-bucketed statistics with optional filters","operationId":"get_time_bucket_stats","parameters":[{"name":"start_time","in":"query","description":"Start time (ISO 8601 format)","required":true,"schema":{"type":"string"},"example":"2025-10-23T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601 format)","required":true,"schema":{"type":"string"},"example":"2025-10-23T23:59:59Z"},{"name":"bucket_interval","in":"query","description":"Bucket interval (e.g., \"1 hour\", \"1 day\", \"5 minutes\")","required":false,"schema":{"type":"string"}},{"name":"method","in":"query","description":"Filter by HTTP method","required":false,"schema":{"type":"string"}},{"name":"client_ip","in":"query","description":"Filter by client IP","required":false,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Filter by project ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"host","in":"query","description":"Filter by host","required":false,"schema":{"type":"string"}},{"name":"status_code","in":"query","description":"Filter by status code","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"status_code_class","in":"query","description":"Filter by status code class (e.g. \"2xx\", \"3xx\", \"4xx\", \"5xx\")","required":false,"schema":{"type":"string"}},{"name":"routing_status","in":"query","description":"Filter by routing status","required":false,"schema":{"type":"string"}},{"name":"request_source","in":"query","description":"Filter by request source","required":false,"schema":{"type":"string"}},{"name":"is_bot","in":"query","description":"Filter by bot detection","required":false,"schema":{"type":"boolean"}},{"name":"device_type","in":"query","description":"Filter by device type","required":false,"schema":{"type":"string"}},{"name":"has_project","in":"query","description":"When true, only count requests that matched a project\n(project_id IS NOT NULL). Makes chart totals line up with the\nper-project health cards.","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Time-bucketed statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimeBucketStatsResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/today":{"get":{"tags":["Proxy Logs"],"summary":"Get today's request count with optional filters","operationId":"get_today_stats","parameters":[{"name":"method","in":"query","description":"Filter by HTTP method","required":false,"schema":{"type":["string","null"]}},{"name":"client_ip","in":"query","description":"Filter by client IP","required":false,"schema":{"type":["string","null"]}},{"name":"project_id","in":"query","description":"Filter by project ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"host","in":"query","description":"Filter by host","required":false,"schema":{"type":["string","null"]}},{"name":"status_code","in":"query","description":"Filter by status code","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"status_code_class","in":"query","description":"Filter by status code class (e.g. \"2xx\", \"3xx\", \"4xx\", \"5xx\")","required":false,"schema":{"type":["string","null"]}},{"name":"routing_status","in":"query","description":"Filter by routing status","required":false,"schema":{"type":["string","null"]}},{"name":"request_source","in":"query","description":"Filter by request source","required":false,"schema":{"type":["string","null"]}},{"name":"is_bot","in":"query","description":"Filter by bot detection","required":false,"schema":{"type":["boolean","null"]}},{"name":"device_type","in":"query","description":"Filter by device type","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Today's request count","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TodayStatsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/{id}":{"get":{"tags":["Proxy Logs"],"summary":"Get a single proxy log by ID","operationId":"get_proxy_log_by_id","parameters":[{"name":"id","in":"path","description":"Proxy log ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"timestamp","in":"query","description":"Event time of the log row (ISO 8601). When provided, the lookup is\nbounded to the hypertable chunks around this instant instead of\nscanning (and decompressing) the whole retention window. The list\nendpoint already returns this value per row — always pass it when\nnavigating from a list.","required":false,"schema":{"type":["string","null"],"format":"date-time"}}],"responses":{"200":{"description":"Proxy log found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProxyLogResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Proxy log not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/repositories":{"get":{"tags":["Git Providers"],"summary":"List synced repositories with advanced filtering","description":"Lists repositories that have been synced to the database with filtering options.\nThis provides fast access to repository metadata with filtering by connection, search, and other criteria.","operationId":"list_synced_repositories","parameters":[{"name":"page","in":"query","description":"Page number for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"sort","in":"query","description":"Sort field (name, created_at, updated_at, stars, watchers, size, issues)","required":false,"schema":{"type":"string"}},{"name":"direction","in":"query","description":"Sort direction (asc, desc)","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Search term to filter repositories","required":false,"schema":{"type":"string"}},{"name":"owner","in":"query","description":"Filter by repository owner","required":false,"schema":{"type":"string"}},{"name":"language","in":"query","description":"Filter by programming language","required":false,"schema":{"type":"string"}},{"name":"private","in":"query","description":"Filter by private status (true/false)","required":false,"schema":{"type":"boolean"}},{"name":"git_provider_connection_id","in":"query","description":"Filter by git provider connection ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of synced repositories","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryListResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{name}":{"get":{"tags":["Git Providers"],"summary":"Get repository by owner and name from any connection","operationId":"get_repository_by_name","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"connection_id","in":"query","description":"Optional specific connection ID to search","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Repository found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryResponse"}}}},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{name}/all":{"get":{"tags":["Git Providers"],"summary":"Get all repositories with same owner/name from all git providers","operationId":"get_all_repositories_by_name","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Repositories found from all providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RepositoryResponse"}}}}},"404":{"description":"No repositories found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{name}/preset":{"get":{"tags":["Git Providers"],"summary":"Get repository preset by owner and name","operationId":"get_repository_preset_by_name","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"branch","in":"query","description":"Git branch to check (defaults to repository's default branch)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Repository preset calculated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryPresetResponse"}}}},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{repo}/branches":{"get":{"tags":["Repositories"],"summary":"Get repository branches","operationId":"get_repository_branches","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"connection_id","in":"query","description":"Git provider connection ID (required when multiple connections have the same repo)","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of branches","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BranchListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{repo}/tags":{"get":{"tags":["Repositories"],"summary":"Get repository tags","operationId":"get_repository_tags","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"connection_id","in":"query","description":"Git provider connection ID (required when multiple connections have the same repo)","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of tags","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"429":{"description":"Fresh tag lookup rate limit exceeded"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{repository_id}/preset/live":{"get":{"tags":["Git Providers"],"operationId":"get_repository_preset_live","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"branch","in":"query","description":"Git branch to check (defaults to repository's default branch)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Repository presets calculated successfully - includes root preset and projects in subdirectories","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryPresetResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"The git provider rejected the stored credential - the connection must be re-authorized"},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}":{"get":{"tags":["Git Providers"],"summary":"Get repository by ID","operationId":"get_repository_by_id","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Repository found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryResponse"}}}},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}/branches":{"get":{"tags":["Repositories"],"summary":"Get repository branches by repository ID","operationId":"get_branches_by_repository_id","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of branches","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BranchListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}/commits":{"get":{"tags":["Repositories"],"summary":"List recent commits for a repository branch","operationId":"list_commits_by_repository_id","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"branch","in":"query","description":"Branch name to list commits for","required":true,"schema":{"type":"string"}},{"name":"per_page","in":"query","description":"Number of commits to return (default: 20, max: 100)","required":false,"schema":{"type":["integer","null"],"format":"int32","minimum":0}}],"responses":{"200":{"description":"List of commits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommitListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}/commits/{commit_sha}":{"get":{"tags":["Repositories"],"summary":"Check if a commit exists in a repository","operationId":"check_commit_exists","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"commit_sha","in":"path","description":"Commit SHA to check","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Commit existence check result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommitExistsResponse"}}}},"400":{"description":"Invalid commit SHA"},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"429":{"description":"Commit lookup rate limit exceeded"},"500":{"description":"Internal server error"},"502":{"description":"Git provider request failed"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}/tags":{"get":{"tags":["Repositories"],"summary":"Get repository tags by repository ID","operationId":"get_tags_by_repository_id","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of tags","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"429":{"description":"Fresh tag lookup rate limit exceeded"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/restore-runs/{id}":{"get":{"tags":["Restore"],"operationId":"get_restore_run","parameters":[{"name":"id","in":"path","description":"Restore run id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Restore run progress","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestoreRunView"}}}},"404":{"description":"Restore run not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/revenue/events":{"get":{"tags":["Revenue"],"summary":"Org-wide revenue events across every project. Powers the revenue\ntransactions page. Supports filtering by project, date range, and\nevent type.","operationId":"revenue_global_events","parameters":[{"name":"project_id","in":"query","description":"Filter to a single project","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"from","in":"query","description":"Lower bound (inclusive), ISO-8601","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"Upper bound (inclusive), ISO-8601","required":false,"schema":{"type":"string"}},{"name":"event_types","in":"query","description":"Comma-separated event types (e.g. `invoice.paid,charge.succeeded`)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max rows, default 100, max 500","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GlobalRecentEventResponse"}}}}}},"security":[{"bearer_auth":[]}]}},"/revenue/metrics/global-mrr":{"get":{"tags":["Revenue"],"summary":"Org-wide MRR total, summed across every project in the install.\nPowers the single-number MRR card on the main dashboard.","operationId":"revenue_metrics_global_mrr","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlobalMrrResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/revenue/metrics/global-summary":{"get":{"tags":["Revenue"],"summary":"Org-wide revenue summary: MRR, paid cash (30d + all-time), refunds,\nactive subscriptions/customers, and transaction count. Powers the\nheader on the Revenue transactions page.","operationId":"revenue_metrics_global_summary","parameters":[{"name":"currency","in":"query","description":"ISO-4217 currency code, default USD","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlobalRevenueSummaryResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/revenue/providers":{"get":{"tags":["Revenue"],"summary":"List registered providers (what the UI needs to render the \"Connect\"\ndropdown + its wizard instructions).","operationId":"revenue_list_providers","responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderDescriptor"}}}}}},"security":[{"bearer_auth":[]}]}},"/session-replays":{"get":{"tags":["Analytics"],"summary":"Get session replays for a project","operationId":"get_project_session_replays","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Session replays retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetProjectSessionReplaysResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/sessions/{session_id}/events":{"get":{"tags":["Events"],"summary":"Get events for a specific session","operationId":"get_session_events","parameters":[{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved session events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsSessionEventsResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Session not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings":{"get":{"tags":["Settings"],"summary":"Get application settings","operationId":"get_settings","responses":{"200":{"description":"Application settings with masked sensitive fields","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppSettingsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Settings"],"summary":"Update application settings","operationId":"update_settings","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppSettings"}}},"required":true},"responses":{"200":{"description":"Settings updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsUpdateResponse"}}}},"400":{"description":"Bad request - invalid settings"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/agent-token":{"post":{"tags":["Agents"],"summary":"Save an encrypted AI provider token for use in sandbox containers.","operationId":"save_agent_token","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveAgentTokenRequest"}}},"required":true},"responses":{"200":{"description":"Token encrypted and persisted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveAgentTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Encryption or database error"}},"security":[{"bearer_auth":[]}]}},"/settings/ai-providers":{"get":{"tags":["Agents"],"summary":"List the AI provider catalog. Includes per-provider \"is a credential\nconfigured?\" so the settings UI can render configured/not-configured\nbadges without leaking the encrypted credential.","operationId":"list_ai_providers","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderCatalogResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/ai-providers/{provider_id}":{"patch":{"tags":["Agents"],"summary":"Update provider-scoped settings without touching the saved credential.\nToday that means just `default_model`; future per-provider settings\n(base URL overrides, request headers, etc.) can land here too without\nchanging the shape of `save_credential`.","operationId":"update_ai_provider","parameters":[{"name":"provider_id","in":"path","description":"AI provider ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAiProviderRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAiProviderResponse"}}}},"400":{"description":"Unknown provider"},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/ai-providers/{provider_id}/activate":{"post":{"tags":["Agents"],"summary":"Activate a provider as the platform-wide default. Refuses to activate a\nprovider that doesn't have a credential saved yet — the UI enforces the\nsame rule on the button, but we re-check server-side so a stale tab\ncan't bypass it.","operationId":"activate_ai_provider","parameters":[{"name":"provider_id","in":"path","description":"AI provider ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivateProviderResponse"}}}},"400":{"description":"Provider not configured"},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/ai-providers/{provider_id}/credential":{"post":{"tags":["Agents"],"summary":"Save (or replace) a provider's credential. The credential is encrypted\nwith `EncryptionService` and stored inside\n`agent_sandbox.providers[provider_id].credentials_encrypted`.","description":"The plaintext shape depends on the flavor's `credential_format`:\n - `ApiKey` / `OauthToken`: the key/token string.\n - `ConfigFile`: the full file body (e.g. OpenCode's `auth.json`).","operationId":"save_ai_provider_credential","parameters":[{"name":"provider_id","in":"path","description":"AI provider ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveCredentialRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveCredentialResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/disk-status":{"get":{"tags":["Settings"],"summary":"Get current disk usage for the control-plane server","description":"Returns live disk usage for the monitored path along with any disks that\nmeet or exceed the configured alert threshold. Read-only — does not send\nnotifications. Used by the dashboard to surface a low-disk-space warning.","operationId":"get_disk_status","responses":{"200":{"description":"Current disk usage and threshold alerts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiskSpaceCheckResult"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/enrollment-tokens":{"get":{"tags":["Settings"],"summary":"List currently-valid node enrollment tokens (hashes elided).","operationId":"list_enrollment_tokens","responses":{"200":{"description":"Active enrollment tokens","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnrollmentTokenListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Settings"],"summary":"Mint a short-lived, single-use node enrollment token.","operationId":"mint_enrollment_token","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MintEnrollmentTokenRequest"}}},"required":true},"responses":{"200":{"description":"Enrollment token minted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MintEnrollmentTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/enrollment-tokens/{id}":{"delete":{"tags":["Settings"],"summary":"Revoke a node enrollment token by id.","operationId":"revoke_enrollment_token","parameters":[{"name":"id","in":"path","description":"Enrollment token id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Enrollment token revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsUpdateResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Enrollment token not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/join-token":{"delete":{"tags":["Settings"],"summary":"Revoke the current join token","description":"Removes the stored join token hash, allowing any node to register\n(if no other authentication is in place).","operationId":"revoke_join_token","responses":{"200":{"description":"Join token revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsUpdateResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/join-token/generate":{"post":{"tags":["Settings"],"summary":"Generate a new join token for multi-node cluster registration","description":"Creates a random 32-byte hex token, stores the SHA-256 hash in settings,\nand returns the plaintext exactly once. If a token already exists, it is replaced.","operationId":"generate_join_token","responses":{"200":{"description":"Join token generated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateJoinTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/join-token/status":{"get":{"tags":["Settings"],"summary":"Check whether a join token is currently configured","operationId":"get_join_token_status","responses":{"200":{"description":"Join token status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JoinTokenStatusResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/mcp-servers":{"get":{"tags":["Agents"],"operationId":"list_global_mcps","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListMcpsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_global_mcp","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMcpRequest"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/mcp-servers/{slug}":{"get":{"tags":["Agents"],"operationId":"get_global_mcp","parameters":[{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_global_mcp","parameters":[{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMcpRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_global_mcp","parameters":[{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"MCP server deleted"},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]}},"/settings/mcp-servers/{slug}/config/{field}":{"get":{"tags":["Agents"],"operationId":"reveal_global_mcp_config","parameters":[{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}},{"name":"field","in":"path","description":"Sensitive field path, such as url or env.API_TOKEN","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensitiveMcpConfigValueResponse"}}}},"400":{"description":"Field is not revealable"},"401":{"description":"Unauthorized"},"403":{"description":"Missing secrets:read permission"},"404":{"description":"MCP server or field not found"},"500":{"description":"Configuration read or audit failed"}},"security":[{"bearer_auth":[]}]}},"/settings/routes/refresh":{"post":{"tags":["Settings"],"summary":"Manually refresh the proxy route table","description":"Reloads all routes from the database into the in-memory proxy cache.\nUseful as a workaround when routes are out of sync.","operationId":"refresh_route_table","responses":{"200":{"description":"Route table refreshed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteRefreshResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/sandbox-rebuild":{"post":{"tags":["Agents"],"operationId":"rebuild_sandbox_image","responses":{"200":{"description":"Server-Sent Events stream of rebuild progress; final event `{\"type\":\"done\",\"success\":bool,...}`","content":{"text/event-stream":{}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/settings/sandbox-status":{"get":{"tags":["Agents"],"operationId":"get_global_sandbox_status","responses":{"200":{"description":"Global sandbox readiness for the settings page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/settings/secrets":{"get":{"tags":["Secrets"],"operationId":"list_secrets","responses":{"200":{"description":"List of global agent secrets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSecretsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Secrets"],"operationId":"upsert_secret","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertSecretRequest"}}},"required":true},"responses":{"201":{"description":"Secret created/updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecretResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/settings/secrets/{name}":{"delete":{"tags":["Secrets"],"operationId":"delete_secret","parameters":[{"name":"name","in":"path","description":"Secret name","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Secret deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Secret not found"}},"security":[{"bearer_auth":[]}]}},"/settings/skills":{"get":{"tags":["Agents"],"operationId":"list_global_skills","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSkillsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_global_skill","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSkillRequest"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/skills/upload":{"post":{"tags":["Agents"],"summary":"Upload a skill with an archive (tar.gz) — global.","operationId":"upload_global_skill","requestBody":{"content":{"multipart/form-data":{"schema":{"type":"string"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/skills/{slug}":{"get":{"tags":["Agents"],"operationId":"get_global_skill","parameters":[{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_global_skill","parameters":[{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSkillRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_global_skill","parameters":[{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Skill deleted"},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]}},"/settings/skills/{slug}/archive":{"get":{"tags":["Agents"],"summary":"Download a skill's archive (tar.gz) — global.","operationId":"download_global_skill_archive","parameters":[{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Skill archive tar.gz","content":{"application/gzip":{}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found or has no archive"}},"security":[{"bearer_auth":[]}]}},"/settings/update-status":{"get":{"tags":["Settings"],"summary":"Report whether a newer temps release is available for this install.","operationId":"get_update_status","responses":{"200":{"description":"Release update status for this install","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/teams":{"get":{"tags":["Teams"],"operationId":"list_teams","parameters":[{"name":"page","in":"query","description":"1-indexed page","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"default 20, max 100","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Paginated teams","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Teams"],"operationId":"create_team","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTeamRequest"}}},"required":true},"responses":{"201":{"description":"Team created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamResponse"}}}},"400":{"description":"Validation error"},"403":{"description":"Insufficient permissions"},"409":{"description":"Slug already taken"}},"security":[{"bearer_auth":[]}]}},"/teams/{team_id}":{"get":{"tags":["Teams"],"operationId":"get_team","parameters":[{"name":"team_id","in":"path","description":"Team id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Team","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamResponse"}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Teams"],"operationId":"delete_team","parameters":[{"name":"team_id","in":"path","description":"Team id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Team deleted"},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Teams"],"operationId":"update_team","parameters":[{"name":"team_id","in":"path","description":"Team id","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTeamRequest"}}},"required":true},"responses":{"200":{"description":"Updated team","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamResponse"}}}},"400":{"description":"Validation error"},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]}},"/teams/{team_id}/members":{"get":{"tags":["Teams"],"operationId":"list_team_members","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Members","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TeamMemberResponse"}}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Teams"],"operationId":"add_team_member","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTeamMemberRequest"}}},"required":true},"responses":{"201":{"description":"Member added","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamMemberResponse"}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"},"409":{"description":"User already a member"}},"security":[{"bearer_auth":[]}]}},"/teams/{team_id}/members/{user_id}":{"delete":{"tags":["Teams"],"operationId":"remove_team_member","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Member removed"},"403":{"description":"Insufficient permissions"},"404":{"description":"Member not found"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Teams"],"operationId":"update_team_member_role","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMemberRoleRequest"}}},"required":true},"responses":{"200":{"description":"Updated membership","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamMemberResponse"}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Member not found"}},"security":[{"bearer_auth":[]}]}},"/teams/{team_id}/projects":{"get":{"tags":["Teams"],"operationId":"list_team_projects","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Projects this team has access to","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectAccessResponse"}}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]}},"/templates":{"get":{"tags":["Templates"],"summary":"List all available templates","description":"Returns a list of all public templates, optionally filtered by tag or featured status.","operationId":"list_project_templates","parameters":[{"name":"tag","in":"query","description":"Filter templates by tag","required":false,"schema":{"type":"string"}},{"name":"featured","in":"query","description":"Only return featured templates","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of templates","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListTemplatesResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/templates/tags":{"get":{"tags":["Templates"],"summary":"List all available template tags","description":"Returns a list of all unique tags used by public templates.","operationId":"list_project_template_tags","responses":{"200":{"description":"List of tags","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListTagsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/templates/{slug}":{"get":{"tags":["Templates"],"summary":"Get a specific template by slug","description":"Returns detailed information about a single template.","operationId":"get_project_template","parameters":[{"name":"slug","in":"path","description":"Template slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Template details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Template not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/user/me":{"get":{"tags":["Authentication"],"operationId":"get_current_user","responses":{"200":{"description":"Successfully retrieved user information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/users":{"get":{"tags":["Users"],"operationId":"list_users","parameters":[{"name":"include_deleted","in":"query","description":"Include deleted users in the response","required":true,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List all users with their roles","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}}},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Users"],"summary":"Create a new user with roles","operationId":"create_user","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserRequest"}}},"required":true},"responses":{"201":{"description":"User created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}},"400":{"description":"Invalid input"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me":{"patch":{"tags":["Users"],"summary":"Update current user's information","operationId":"update_self","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSelfRequest"}}},"required":true},"responses":{"200":{"description":"User updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me/mfa":{"delete":{"tags":["Users"],"operationId":"disable_mfa","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DisableMfaRequest"}}},"required":true},"responses":{"204":{"description":"MFA disabled"},"400":{"description":"Invalid verification code"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me/mfa/setup":{"post":{"tags":["Users"],"operationId":"setup_mfa","responses":{"200":{"description":"MFA setup data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaSetupResponse"}}}},"401":{"description":"Unauthorized"},"409":{"description":"MFA is already enabled; verify and disable it before re-enrollment"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me/mfa/verify":{"post":{"tags":["Users"],"operationId":"verify_and_enable_mfa","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyMfaRequest"}}},"required":true},"responses":{"204":{"description":"MFA verified and enabled"},"400":{"description":"Invalid code"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me/password":{"post":{"tags":["Users"],"operationId":"change_password_self","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangePasswordRequest"}}},"required":true},"responses":{"204":{"description":"Password updated"},"400":{"description":"Validation error (weak password, same as current, MFA missing)"},"401":{"description":"Current password incorrect or MFA code invalid"},"403":{"description":"Account has no password set (SSO only)"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/{user_id}":{"delete":{"tags":["Users"],"summary":"Delete a user","operationId":"delete_user","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"User deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Cannot delete yourself or non-admin attempt"},"404":{"description":"User not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Users"],"summary":"Update user information (admin only)","operationId":"update_user","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserRequest"}}},"required":true},"responses":{"200":{"description":"User updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Non-admin attempt"},"404":{"description":"User not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/{user_id}/restore":{"post":{"tags":["Users"],"operationId":"restore_user","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"User restored successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}},"400":{"description":"User is not deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Non-admin attempt"},"404":{"description":"User not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/{user_id}/roles":{"post":{"tags":["Users"],"operationId":"assign_role","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignRoleRequest"}}},"required":true},"responses":{"200":{"description":"Role assigned successfully"},"400":{"description":"Invalid role type"},"401":{"description":"Unauthorized"},"403":{"description":"Admin role required or self-modification forbidden"},"404":{"description":"User or role not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/{user_id}/roles/{role_type}":{"delete":{"tags":["Users"],"operationId":"remove_role","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"role_type","in":"path","description":"Role type to remove","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Role removed successfully"},"400":{"description":"Invalid role type"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Cannot modify own roles or non-admin attempt"},"404":{"description":"User or role not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes":{"get":{"tags":["Sandboxes"],"operationId":"list_sandboxes","parameters":[{"name":"page","in":"query","description":"Page (1-indexed)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default 20, max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List sandboxes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSandboxesResponse"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Sandboxes"],"operationId":"create_sandbox","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSandboxBody"}}},"required":true},"responses":{"201":{"description":"Sandbox created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/rootfs":{"get":{"tags":["Sandboxes"],"summary":"Inspect rootfs storage: the Firecracker digest-keyed cache (with which\nsandboxes reference each entry) and per-VM disks. Empty on Docker-only\nhosts. Admin/read scope — this exposes host storage layout.","operationId":"rootfs_report","responses":{"200":{"description":"Rootfs storage report"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/rootfs/gc":{"post":{"tags":["Sandboxes"],"summary":"Reclaim rootfs cache entries not backing any live sandbox. Idempotent;\nsafe to call any time (live VMs hold their own per-VM disks).","operationId":"rootfs_gc","responses":{"200":{"description":"Reclaimed cache entries"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}":{"get":{"tags":["Sandboxes"],"operationId":"get_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sandbox details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"404":{"description":"Not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/cmd":{"post":{"tags":["Sandboxes"],"summary":"Run a command inside the sandbox (`@vercel/sandbox`-compatible).","description":"`wait=false` (default) returns `{ command: {..., exitCode: null} }`\nimmediately once the background task is spawned.\n\n`wait=true` streams `application/x-ndjson`: the first line is the\nrunning envelope, the second is the finished envelope with `exitCode`.","operationId":"cmd","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdBody"}}},"required":true},"responses":{"200":{"description":"Command started (wait=false) or finished (wait=true)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdResponse"}}}},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/cmd/{cmd_id}":{"get":{"tags":["Sandboxes"],"operationId":"get_cmd","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"cmd_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Command snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdResponse"}}}},"404":{"description":"Sandbox or command not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/cmd/{cmd_id}/logs":{"get":{"tags":["Sandboxes"],"summary":"Stream a command's stdout/stderr as `application/x-ndjson`\n(`@vercel/sandbox`-compatible). Each line is either\n`{stream:\"stdout\"|\"stderr\", data:\"...\"}` or\n`{stream:\"error\", data:{code, message}}`.","operationId":"cmd_logs","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"cmd_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"NDJSON stream of log events"},"404":{"description":"Sandbox or command not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/destroy":{"post":{"tags":["Sandboxes"],"operationId":"destroy_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Sandbox destroyed (alias for `/stop` with an explicit verb)"},"404":{"description":"Not found"},"409":{"description":"Sandbox belongs to an active agent run — stop the run instead"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/domain":{"get":{"tags":["Sandboxes"],"operationId":"domain","parameters":[{"name":"port","in":"query","description":"Port inside the sandbox (1..=65535)","required":true,"schema":{"type":"integer","format":"int32","minimum":0}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Preview URL for the port","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxDomainResponse"}}}},"400":{"description":"Invalid port"},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/events":{"get":{"tags":["Sandboxes"],"summary":"The operations timeline for a sandbox (lifecycle events only — never\nshell/exec activity), newest first.","operationId":"list_events","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Operations timeline","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxEventsResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/exec":{"post":{"tags":["Sandboxes"],"operationId":"exec","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecBody"}}},"required":true},"responses":{"200":{"description":"Command finished (non-zero exit is NOT an error)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecResponse"}}}},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/exec-detached":{"post":{"tags":["Sandboxes"],"operationId":"exec_detached","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecBody"}}},"required":true},"responses":{"202":{"description":"Command accepted; poll /jobs/{job_id}","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecDetachedResponse"}}}},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/extend-timeout":{"post":{"tags":["Sandboxes"],"operationId":"extend_timeout","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExtendTimeoutBody"}}},"required":true},"responses":{"200":{"description":"Timeout extended","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/mkdir":{"post":{"tags":["Sandboxes"],"operationId":"mkdir","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MkdirBody"}}},"required":true},"responses":{"204":{"description":"Directory created (or already existed)"},"400":{"description":"Validation error"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/read":{"get":{"tags":["Sandboxes"],"operationId":"read_file","parameters":[{"name":"path","in":"query","description":"Absolute file path inside the sandbox","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"File contents (base64)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReadFileResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Sandbox or file not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/stat":{"get":{"tags":["Sandboxes"],"operationId":"stat_path","parameters":[{"name":"path","in":"query","description":"Absolute path inside the sandbox","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Stat info (exists=false when missing — not an error)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatResponse"}}}},"400":{"description":"Validation error"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/write":{"post":{"tags":["Sandboxes"],"summary":"Write a file into the sandbox. Accepts two body shapes — the SDK\npicks one based on `Content-Type`:","description":"- **`application/json`** (temps-native): `{path, contents_b64, mode}`\n — one file, base64-encoded.\n- **`application/gzip`** (`@vercel/sandbox`): a gzipped tarball of\n one-or-more entries, with the target extract dir carried in the\n `x-cwd` header. The SDK's `writeFile` and `writeFiles` both post\n here; they differ only in how many entries the tarball contains.\n\nWhy merge them on one route: the SDK is hardcoded to\n`POST /fs/write`, so splitting tar uploads onto a separate path would\nforce us to break SDK compat. Instead we dispatch on Content-Type,\npreserve JSON for native callers, and add tar for SDK callers.","operationId":"write_file","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WriteFileBody"}}},"required":true},"responses":{"204":{"description":"File(s) written"},"400":{"description":"Validation error or invalid base64"},"404":{"description":"Sandbox not found"},"415":{"description":"Unsupported Content-Type (expected application/json or application/gzip)"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/write-batch":{"post":{"tags":["Sandboxes"],"summary":"Batch-write multiple files in a single request. Mirrors\n`@vercel/sandbox` `writeFiles()`. Semantics are fail-fast: if any\nfile errors, previously-written entries are left in place and the\nerror describes which file broke.","operationId":"write_files","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WriteFilesBody"}}},"required":true},"responses":{"200":{"description":"All files written","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WriteFilesResponse"}}}},"400":{"description":"Validation error or invalid base64"},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/jobs":{"get":{"tags":["Sandboxes"],"operationId":"list_jobs","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Detached jobs for this sandbox","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListJobsResponse"}}}},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/jobs/{job_id}":{"get":{"tags":["Sandboxes"],"operationId":"job_status","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"job_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Job status snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobStatusResponse"}}}},"404":{"description":"Sandbox or job not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/jobs/{job_id}/kill":{"post":{"tags":["Sandboxes"],"summary":"Terminate a detached job. Aborts the server-side tracking task and\nsends SIGTERM (or SIGKILL if `force=true`) to any matching processes\ninside the sandbox container. Returns 204 on success; 404 if the\nsandbox or job is unknown.","operationId":"kill_job","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"job_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KillJobBody"}}},"required":true},"responses":{"204":{"description":"Job killed"},"404":{"description":"Sandbox or job not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/jobs/{job_id}/logs":{"get":{"tags":["Sandboxes"],"summary":"SSE endpoint streaming each stdout/stderr line from a detached job\nas it's produced. Mirrors the `Command.logs()` async iterator shape\non `@vercel/sandbox` — events carry `{ stream, data }`.","description":"Late subscribers only see events produced after they connect. The\nJobState snapshot (`GET /jobs/{job_id}`) covers the history.\n\nA \"done\" sentinel event fires when the broadcast channel closes\n(the exec task has exited and dropped the sender), signalling\ncallers they can stop reading.","operationId":"job_logs","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"job_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"SSE stream of log events"},"404":{"description":"Sandbox or job not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/pause":{"post":{"tags":["Sandboxes"],"operationId":"pause_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sandbox paused (container stopped, state preserved)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Sandbox is in an incompatible state (e.g. already destroyed)"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/preview-link":{"post":{"tags":["Sandboxes"],"summary":"Mint a shareable link to a sandbox preview.","description":"`GET /domain` returns the bare preview URL, which is useless to anyone who\ndoes not already hold the sandbox's preview password — so sharing a\nprotected preview meant sharing that password, which is the same secret for\nevery recipient and can only be withdrawn by rotating it for all of them.\n\nThis returns the same URL carrying a short-lived, sandbox-scoped grant. The\nrecipient's browser exchanges it for the ordinary preview cookie and lands\non `path`. The grant never reaches the sandbox, so preview application code\ncannot read it and re-share it.\n\nAnyone holding the returned URL can view the preview until it expires;\nthere is no per-link revocation short of rotating the preview password.","operationId":"sandbox_create_preview_link","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewShareLinkBody"}}},"required":true},"responses":{"200":{"description":"Shareable preview link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewShareLinkResponse"}}}},"400":{"description":"Invalid port"},"404":{"description":"Sandbox not found"},"409":{"description":"Sandbox has no preview password"},"500":{"description":"Preview grant minting failed"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/preview-password":{"put":{"tags":["Sandboxes"],"operationId":"set_preview_password","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPreviewPasswordBody"}}},"required":true},"responses":{"200":{"description":"Preview password set or rotated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPreviewPasswordResponse"}}}},"400":{"description":"Password too short or too long"},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Sandboxes"],"operationId":"clear_preview_password","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Preview password removed (sandbox is now URL-only protected)"},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/resize":{"post":{"tags":["Sandboxes"],"summary":"Grow a Firecracker sandbox's root disk. Offline resize — the VM reboots\n(filesystem/data persist) rather than resizing fully live.","operationId":"resize_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResizeSandboxBody"}}},"required":true},"responses":{"200":{"description":"Resized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"400":{"description":"Invalid size or unsupported backend"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/restart":{"post":{"tags":["Sandboxes"],"operationId":"restart_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sandbox container restarted in place","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Sandbox is stopped (use /resume) or already destroyed"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/resume":{"post":{"tags":["Sandboxes"],"operationId":"resume_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sandbox resumed; expires_at refreshed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Sandbox is not in a resumable state"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/source":{"post":{"tags":["Sandboxes"],"operationId":"source_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceBody"}}},"required":true},"responses":{"200":{"description":"Source content seeded into the sandbox work dir","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"400":{"description":"Validation error (embedded creds, conflicting fields, etc.)"},"404":{"description":"Sandbox not found"},"409":{"description":"Sandbox is not running"},"500":{"description":"Source seed failed inside sandbox"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/stop":{"post":{"tags":["Sandboxes"],"operationId":"stop_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Sandbox stopped and destroyed"},"404":{"description":"Not found"},"409":{"description":"Sandbox belongs to an active agent run — stop the run instead"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/{cmd_id}/kill":{"post":{"tags":["Sandboxes"],"summary":"Kill a running command (`@vercel/sandbox`-compatible). The SDK\ncalls `POST /v1/sandboxes/{id}/{cmdId}/kill` — note the path has the\ncommand ID directly under the sandbox, NOT under `/jobs/` or `/cmd/`.","operationId":"cmd_kill","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"cmd_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdKillBody"}}}},"responses":{"200":{"description":"Command killed; returns final snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdResponse"}}}},"404":{"description":"Sandbox or command not found"}},"security":[{"bearer_auth":[]}]}},"/visitors/{visitor_id}/session-replays":{"get":{"tags":["Analytics"],"summary":"Get session replays for a visitor","operationId":"get_visitor_sessions","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Session replays retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetVisitorSessionsResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/visitors/{visitor_id}/session-replays/{session_id}":{"get":{"tags":["Analytics"],"summary":"Get session replay data with visitor info (without events)","operationId":"get_session_replay","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Session replay retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetSessionReplayResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Analytics"],"summary":"Delete a session replay","operationId":"delete_session_replay","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Session replay deleted successfully"},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/visitors/{visitor_id}/session-replays/{session_id}/duration":{"put":{"tags":["Analytics"],"summary":"Update session duration","operationId":"update_session_duration","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSessionDurationRequest"}}},"required":true},"responses":{"200":{"description":"Session duration updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSessionDurationResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/visitors/{visitor_id}/session-replays/{session_id}/events":{"get":{"tags":["Analytics"],"summary":"Get session replay events (with session and visitor metadata)","operationId":"get_session_replay_events","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Session replay with events retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionReplayWithEventsDto"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Analytics"],"summary":"Add events to an existing session","operationId":"add_events","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddEventsRequest"}}},"required":true},"responses":{"200":{"description":"Events added successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddEventsResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/vulnerability-scans/{scan_id}":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_scan","parameters":[{"name":"scan_id","in":"path","description":"Scan ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Scan details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Scan not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Vulnerability Scans"],"operationId":"delete_scan","parameters":[{"name":"scan_id","in":"path","description":"Scan ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Scan deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Scan not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/vulnerability-scans/{scan_id}/vulnerabilities":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_scan_vulnerabilities","parameters":[{"name":"scan_id","in":"path","description":"Scan ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"severity","in":"query","description":"Filter by severity (CRITICAL, HIGH, MEDIUM, LOW)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of vulnerabilities","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/VulnerabilityResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Scan not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/webhook-event-types":{"get":{"tags":["Webhooks"],"summary":"List available event types","operationId":"list_event_types","responses":{"200":{"description":"List of available event types","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventTypeResponse"}}}}}}}},"/weekly-digest/trigger":{"post":{"tags":["Notification Preferences"],"summary":"Trigger weekly digest generation manually","operationId":"trigger_weekly_digest","responses":{"200":{"description":"Weekly digest triggered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerDigestResponse"}}}},"500":{"description":"Failed to generate digest"}},"security":[{"bearer_auth":[]}]}},"/x/plugins":{"get":{"tags":["External Plugins"],"summary":"List all running external plugins and their manifests.","description":"Requires only a valid session/token (no specific permission) since the\nmanifest drives sidebar navigation rendering for every authenticated\nuser, not just admins.","operationId":"list_external_plugins","responses":{"200":{"description":"List of all running external plugins","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PluginManifest"}}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/x/plugins/reload":{"post":{"tags":["External Plugins"],"summary":"Reload all external plugins.","description":"Stops all running plugin processes, re-scans the plugins directory,\nstarts any discovered binaries, and hot-swaps the proxy router so new\nand removed plugins take effect immediately without a server restart.\n\nRequires `SystemAdmin` permission.","operationId":"reload_plugins","responses":{"200":{"description":"Plugins reloaded successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReloadResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/{project_id}/envelope/":{"post":{"tags":["sentry-ingestor"],"summary":"Ingest a Sentry envelope (binary payload)","operationId":"ingest_sentry_envelope","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"Sentry envelope as binary data","content":{"application/octet-stream":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Envelope ingested"},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"413":{"description":"Request body too large (exceeds 2 MiB)"}}}},"/{project_id}/store/":{"post":{"tags":["sentry-ingestor"],"summary":"Ingest a Sentry event (JSON payload)","operationId":"ingest_sentry_event","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryEventRequest"}}},"required":true},"responses":{"200":{"description":"Event ingested","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryEventResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"413":{"description":"Request body too large (exceeds 2 MiB)"}}}},"audit/logs":{"get":{"tags":["Audit Logs"],"summary":"List audit logs with optional filtering","operationId":"list_audit_logs","parameters":[{"name":"operation_type","in":"query","description":"Filter logs by operation type (omit for all)","required":false,"schema":{"type":"string"},"example":"user.login"},{"name":"user_id","in":"query","description":"Filter logs by user ID (omit for all users)","required":false,"schema":{"type":"integer","format":"int32"},"example":1},{"name":"from","in":"query","description":"Start timestamp (milliseconds since epoch)","required":false,"schema":{"type":"string","format":"date-time"},"example":1},{"name":"to","in":"query","description":"End timestamp (milliseconds since epoch)","required":false,"schema":{"type":"string","format":"date-time"},"example":1},{"name":"limit","in":"query","description":"Maximum number of logs to return","required":false,"schema":{"type":"integer","format":"int32"},"example":100},{"name":"offset","in":"query","description":"Number of logs to skip","required":false,"schema":{"type":"integer","format":"int32"},"example":0}],"responses":{"200":{"description":"List of audit logs","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AuditLogResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"api_key":[]}]}},"audit/logs/{id}":{"get":{"tags":["Audit Logs"],"summary":"Get a specific audit log entry by ID","operationId":"get_audit_log","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Audit log details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuditLogResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Audit log not found"},"500":{"description":"Internal server error"}},"security":[{"api_key":[]}]}}},"components":{"schemas":{"AcmeOrderResponse":{"type":"object","required":["id","order_url","domain_id","email","status","identifiers","created_at","updated_at"],"properties":{"authorizations":{},"certificate_url":{"type":["string","null"]},"challenge_validation":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ChallengeValidationStatus","description":"Live challenge validation status fetched from Let's Encrypt"}]},"created_at":{"type":"integer","format":"int64"},"domain_id":{"type":"integer","format":"int32"},"email":{"type":"string"},"error":{"type":["string","null"]},"error_type":{"type":["string","null"]},"expires_at":{"type":["integer","null"],"format":"int64"},"finalize_url":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"identifiers":{},"order_url":{"type":"string"},"status":{"type":"string"},"updated_at":{"type":"integer","format":"int64"}}},"ActivateProviderResponse":{"type":"object","required":["default_provider"],"properties":{"default_provider":{"type":"string"}}},"ActiveVisitor":{"type":"object","required":["session_id","session_start","last_activity","page_count","event_count","duration_seconds","is_active"],"properties":{"current_page":{"type":["string","null"]},"duration_seconds":{"type":"integer","format":"int64"},"event_count":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"last_activity":{"type":"string"},"page_count":{"type":"integer","format":"int32"},"session_id":{"type":"string"},"session_start":{"type":"string"},"visitor_id":{"type":["string","null"]}}},"ActiveVisitorsQuery":{"type":"object","properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"}}},"ActiveVisitorsResponse":{"type":"object","required":["active_visitors","window_minutes"],"properties":{"active_visitors":{"type":"integer","format":"int64"},"window_minutes":{"type":"integer","format":"int32"}}},"ActivityDay":{"type":"object","description":"Daily activity count for a single day","required":["date","count","level"],"properties":{"count":{"type":"integer","format":"int64","description":"Number of deployments on this day"},"date":{"type":"string","description":"Date in YYYY-MM-DD format","example":"2024-06-15"},"level":{"type":"integer","format":"int32","description":"Intensity level (0-4) for visualization\n0: No activity, 1: Low (1-2), 2: Medium (3-5), 3: High (6-10), 4: Very High (11+)","example":2}}},"ActivityEvent":{"type":"object","description":"A single activity event for the real-time activity feed","required":["id","timestamp","event_type","page_path","is_crawler"],"properties":{"browser":{"type":["string","null"],"description":"Browser"},"city":{"type":["string","null"],"description":"Visitor's city (from ip_geolocations)"},"country":{"type":["string","null"],"description":"Visitor's country (from ip_geolocations)"},"country_code":{"type":["string","null"],"description":"Visitor's country code (from ip_geolocations)"},"device_type":{"type":["string","null"],"description":"Device type"},"event_name":{"type":["string","null"],"description":"Event name (for custom events)"},"event_type":{"type":"string","description":"Event type: \"page_view\", \"custom\", etc."},"id":{"type":"integer","format":"int64","description":"Event ID"},"is_crawler":{"type":"boolean","description":"Whether this event was from a crawler"},"latitude":{"type":["number","null"],"format":"double","description":"Latitude"},"longitude":{"type":["number","null"],"format":"double","description":"Longitude"},"operating_system":{"type":["string","null"],"description":"Operating system"},"page_path":{"type":"string","description":"Page path where the event happened"},"page_title":{"type":["string","null"],"description":"Page title"},"referrer":{"type":["string","null"],"description":"Referrer"},"timestamp":{"type":"string","format":"date-time","description":"When the event occurred"},"visitor_id":{"type":["integer","null"],"format":"int32","description":"Visitor numeric ID"}}},"ActivityGraphQuery":{"type":"object","description":"Query parameters for activity graph endpoint","properties":{"days":{"type":"integer","format":"int32","description":"Number of days to include (default: 365 for last year)"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment ID to filter activity"},"project_id":{"type":["integer","null"],"format":"int32","description":"Optional project ID to filter activity"}}},"ActivityGraphResponse":{"type":"object","description":"Response for activity graph showing daily deployment activity","required":["days","total_count","start_date","end_date"],"properties":{"days":{"type":"array","items":{"$ref":"#/components/schemas/ActivityDay"},"description":"Array of daily activity counts"},"end_date":{"type":"string","description":"Date range end (YYYY-MM-DD)","example":"2024-12-31"},"start_date":{"type":"string","description":"Date range start (YYYY-MM-DD)","example":"2024-01-01"},"total_count":{"type":"integer","format":"int64","description":"Total count of activities across all days"}}},"AddClusterMemberRequest":{"type":"object","description":"Request body for adding a single member to a running cluster.","required":["role"],"properties":{"node_id":{"type":["integer","null"],"format":"int32","description":"Target worker node ID. Omit or null to run on the control plane."},"role":{"type":"string","description":"Member role. Currently only `replica` is accepted at runtime —\nmonitor is a singleton, primary is elected by pg_auto_failover.","example":"replica"}}},"AddContextRequest":{"type":"object","required":["message"],"properties":{"message":{"type":"string"}}},"AddEnvironmentDomainRequest":{"type":"object","required":["domain","is_primary"],"properties":{"domain":{"type":"string"},"is_primary":{"type":"boolean"}}},"AddEventsRequest":{"type":"object","required":["events"],"properties":{"events":{"type":"string"}}},"AddEventsResponse":{"type":"object","required":["event_count","message"],"properties":{"event_count":{"type":"integer","minimum":0},"message":{"type":"string"}}},"AddManagedDomainApiRequest":{"type":"object","description":"Request to add a managed domain","required":["domain"],"properties":{"auto_manage":{"type":"boolean"},"domain":{"type":"string","example":"example.com"},"generated_hostname_mode":{"type":["string","null"],"description":"Generated hostname layout: `\"standard\"` (default) or `\"flat\"`."},"sync_generated_records":{"type":"boolean","description":"Opt in to reconciling generated hostnames into this domain's DNS zone."}}},"AdminGateResponse":{"type":"object","required":["allowed_ips","allowed_hosts","trust_forwarded_for","source","editable"],"properties":{"allowed_hosts":{"type":"array","items":{"type":"string"},"description":"`Host` header values allowed. Empty = any host."},"allowed_ips":{"type":"array","items":{"type":"string"},"description":"IPs / CIDRs allowed to reach the admin listener. Empty = any source."},"editable":{"type":"boolean","description":"True when the config is writable through this API. False when env\nvars are dictating the active config."},"source":{"$ref":"#/components/schemas/AdminGateSource","description":"Where the active config came from."},"trust_forwarded_for":{"type":"boolean","description":"When true, the gate trusts `X-Forwarded-For` from loopback peers."}}},"AdminGateSource":{"type":"string","description":"Where the active gate configuration came from. Env-supplied configs are\nfrozen at the process level — the UI shows them read-only and refuses to\npersist DB writes. DB-supplied configs are editable at runtime.","enum":["default","db","env"]},"AgentConfigResponse":{"type":"object","description":"Response DTO for a single agent — masks the encrypted API key.","required":["id","project_id","slug","name","source","enabled","trigger_config","ai_provider","api_key_set","max_turns","timeout_seconds","daily_budget_cents","cooldown_minutes","branch_prefix","deliverable","created_at","updated_at"],"properties":{"ai_model":{"type":["string","null"],"description":"Preferred model for the CLI (e.g. \"sonnet\", \"gpt-5-codex\"). `None` means default."},"ai_provider":{"type":"string"},"ai_provider_key_id":{"type":["integer","null"],"format":"int32"},"api_key_set":{"type":"boolean","description":"`true` if an API key is set; `false` otherwise."},"branch_prefix":{"type":"string"},"config_repo_branch":{"type":["string","null"],"description":"Branch of the config repo to use."},"config_repo_url":{"type":["string","null"],"description":"Private config repo containing .claude/ directory (skills, MCP, plugins)."},"cooldown_minutes":{"type":"integer","format":"int32"},"created_at":{"type":"string"},"daily_budget_cents":{"type":"integer","format":"int32"},"deliverable":{"type":"string"},"description":{"type":["string","null"]},"enabled":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"max_turns":{"type":"integer","format":"int32"},"mcp_servers_config":{"description":"MCP servers config (Claude Code settings.json mcpServers format).\nCredential-bearing legacy inline values are write-only and appear as\n`***`. Omit this field on update to preserve their stored values."},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"prompt":{"type":["string","null"]},"sandbox_enabled":{"type":["boolean","null"],"description":"None = use global sandbox setting, true = force on, false = force off"},"skills_config":{"description":"Skills config as JSON array."},"slug":{"type":"string"},"source":{"type":"string"},"timeout_seconds":{"type":"integer","format":"int32"},"tools_config":{"description":"Tools config as JSON array. Legacy custom-tool webhook URLs and headers\nare write-only and appear as `***`. Omit this field on update to\npreserve their stored values."},"trigger_config":{},"updated_at":{"type":"string"},"webhook_token":{"type":["string","null"],"description":"Secret token for the `X-Webhook-Token` header. Shown once when created,\nmasked with `***` prefix in subsequent reads."},"webhook_url":{"type":["string","null"],"description":"Public webhook URL for triggering this agent externally.\nOnly set when `on: { webhook: true }` is configured.\nUsage: `POST {webhook_url}` with header `X-Webhook-Token: {webhook_token}`"}}},"AgentRunLogResponse":{"type":"object","required":["id","run_id","level","message","created_at"],"properties":{"created_at":{"type":"string"},"id":{"type":"integer","format":"int64"},"level":{"type":"string"},"message":{"type":"string"},"metadata":{},"run_id":{"type":"integer","format":"int32"}}},"AgentRunResponse":{"type":"object","required":["id","project_id","source","trigger_type","status","tokens_input","tokens_output","estimated_cost_cents","files_changed","created_at","sandbox_enabled"],"properties":{"agent_name":{"type":["string","null"],"description":"Name of the agent that created this run, if available."},"agent_slug":{"type":["string","null"],"description":"Slug of the agent that created this run, if available."},"ai_model":{"type":["string","null"]},"ai_output":{"type":["string","null"]},"ai_provider":{"type":["string","null"],"description":"AI provider slug that executed this run (e.g. claude_cli, codex_cli, opencode)."},"ai_reasoning":{"type":["string","null"]},"ai_session_id":{"type":["string","null"],"description":"Claude CLI session UUID for resuming conversations via `--resume`."},"analysis":{"type":["string","null"],"description":"Report / analysis text produced by the agent (used for report/notification deliverables)."},"branch_name":{"type":["string","null"]},"commit_sha":{"type":["string","null"]},"completed_at":{"type":["string","null"]},"config_id":{"type":["integer","null"],"format":"int32","description":"Optional. NULL for ephemeral CLI runs (`source = \"cli_ephemeral\"`) and\nhistorical autofixer runs that pre-date the agent_id column."},"created_at":{"type":"string"},"ephemeral_yaml":{"type":["string","null"],"description":"Full WorkflowYamlConfig as YAML text. Populated only when\n`source = \"cli_ephemeral\"`. Used by the web UI to show a \"View YAML\"\nmodal so the user can see exactly what the executor ran."},"error_message":{"type":["string","null"]},"estimated_cost_cents":{"type":"integer","format":"int32"},"files_changed":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"phase":{"type":["string","null"],"description":"Autofixer phase: \"analyzing\", \"analyzed\", \"fixing\", \"fix_ready\", \"no_fix\",\n\"pr_created\", or NULL for non-autofixer runs."},"pr_number":{"type":["integer","null"],"format":"int32"},"pr_url":{"type":["string","null"]},"preview_url":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"prompt_text":{"type":["string","null"],"description":"Final assembled prompt the AI CLI actually saw (trigger context block +\nYAML prompt, with error-group fields interpolated). Captured once per\nrun. `None` for pre-migration rows."},"run_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AutofixRunConfig","description":"Per-run AI options the user chose when starting an autofixer run\n(provider, model, max_turns, branch). NULL for generic agent runs\nand historical rows. Used to prefill the retry dialog."}]},"sandbox_enabled":{"type":"boolean","description":"Legacy field — all runs now execute in a sandbox. Kept for\nbackwards-compatible JSON shape; always `true`."},"source":{"type":"string","description":"`committed` (the run's config lives in `project_agents`) or\n`cli_ephemeral` (the config was uploaded via the CLI for a one-off\ndry run; see `ephemeral_yaml`)."},"started_at":{"type":["string","null"]},"status":{"type":"string"},"tokens_input":{"type":"integer","format":"int32"},"tokens_output":{"type":"integer","format":"int32"},"trigger_source_id":{"type":["integer","null"],"format":"int32"},"trigger_source_type":{"type":["string","null"]},"trigger_type":{"type":"string"},"user_context":{"type":["string","null"],"description":"User-provided context for this run (e.g. webhook payload, manual instructions)."}}},"AgentRunWithLogsResponse":{"type":"object","required":["run","logs"],"properties":{"logs":{"type":"array","items":{"$ref":"#/components/schemas/AgentRunLogResponse"}},"run":{"$ref":"#/components/schemas/AgentRunResponse"}}},"AgentSandboxSettings":{"type":"object","description":"Global agent sandbox settings. Controls whether agent runs are isolated\ninside Docker containers by default. Individual agents can override this.","properties":{"api_key_encrypted":{"type":["string","null"],"description":"DEPRECATED: use `providers[default_provider].credentials_encrypted` instead.","default":null},"auth_type":{"type":"string","description":"DEPRECATED: use `providers[default_provider].auth_type` instead.","default":"subscription"},"cpu_limit":{"type":"number","format":"double","description":"CPU limit in cores for sandbox containers","default":4.0,"example":4.0},"custom_image":{"type":"string","description":"Custom Docker image (only used when runtime is \"custom\").\nMust have git and claude CLI installed.","default":"","example":""},"default_provider":{"type":"string","description":"Default AI provider for agents: \"claude_cli\", \"opencode\", or \"codex_cli\".\nWorkspaces always use this provider — no per-session override.","default":"claude_cli","example":"claude_cli"},"enabled":{"type":"boolean","description":"Sandbox is always enabled — the executor refuses to run any agent\noutside a sandboxed container. Field is retained so existing settings\nrows still deserialize, but it is ignored at runtime.","default":true},"memory_limit_mb":{"type":"integer","format":"int64","description":"Memory limit in MB for sandbox containers","default":8192,"example":8192,"minimum":0},"network_mode":{"type":"string","description":"Network access level: \"full\" (unrestricted), \"restricted\" (Temps network only), \"none\" (no network)","default":"full","example":"full"},"providers":{"type":"object","description":"Per-provider auth + config. Keyed by provider id (e.g. `claude_cli`,\n`codex_cli`, `opencode`). Adding a new provider only requires a new\ncatalog entry on the Rust side — the JSON column stays migration-free.","default":{},"additionalProperties":{"$ref":"#/components/schemas/ProviderConfig"},"propertyNames":{"type":"string"}},"runtime":{"type":"string","description":"Runtime preset: \"node\", \"bun\", \"python\", \"rust\", \"go\", \"full\", or \"custom\"","default":"node","example":"node"},"sandbox_backend":{"type":["string","null"],"description":"Default isolation backend for sandboxes: \"docker\" (default) or\n\"firecracker\" (ADR-029; requires `temps firecracker setup`). Only\nconsulted when the Firecracker backend probes available — otherwise\nDocker is used regardless.","default":null,"example":"docker"}}},"AgentSandboxSettingsMasked":{"type":"object","description":"Agent sandbox settings with masked per-provider credentials.\nEach provider entry reports only whether a credential is saved, not\nthe encrypted blob itself. Non-sensitive fields (auth_type, default_model,\nextra) are passed through so the UI can render provider-specific state.","required":["default_provider","providers","api_key_saved","auth_type","enabled","runtime","custom_image","cpu_limit","memory_limit_mb","network_mode","sandbox_backend"],"properties":{"api_key_saved":{"type":"boolean"},"auth_type":{"type":"string"},"cpu_limit":{"type":"number","format":"double"},"custom_image":{"type":"string"},"default_provider":{"type":"string"},"enabled":{"type":"boolean"},"memory_limit_mb":{"type":"integer","format":"int64","minimum":0},"network_mode":{"type":"string"},"providers":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/ProviderConfigMasked"},"propertyNames":{"type":"string"}},"runtime":{"type":"string"},"sandbox_backend":{"type":"string"}}},"AggregatedBucketItem":{"type":"object","required":["timestamp","count"],"properties":{"count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"}}},"AggregatedBucketsQuery":{"type":"object","description":"Query parameters for aggregated metrics by time bucket","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events, sessions, or visitors"},"bucket_size":{"type":"string","description":"Time bucket size: \"1 hour\", \"1 day\", \"1 week\", etc. (default: \"1 hour\")"},"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment filter"},"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment filter"},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"AggregatedBucketsResponse":{"type":"object","required":["bucket_size","aggregation_level","items","total"],"properties":{"aggregation_level":{"type":"string"},"bucket_size":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AggregatedBucketItem"}},"total":{"type":"integer","format":"int64"}}},"AggregationLevel":{"type":"string","enum":["events","sessions","visitors"]},"AggregationTemporality":{"type":"string","description":"The aggregation temporality of a Sum/Histogram/ExponentialHistogram metric.\n\nMirrors OTel's `AggregationTemporality` proto enum: whether reported values\nare cumulative since the start of the series (Cumulative) or only the delta\nsince the previous report (Delta).","enum":["unspecified","delta","cumulative"]},"AiAgentBreakdownResponse":{"type":"object","description":"Response wrapping the AI agent breakdown rows.","required":["items","start_time","end_time"],"properties":{"end_time":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiAgentBreakdownRow"}},"start_time":{"type":"string"}}},"AiAgentBreakdownRow":{"type":"object","description":"One row in the AI-agent analytics breakdown. `agent` is the canonical\ncrawler name (e.g. `GPTBot`, `Claude-User`), `provider` is the vendor used\nfor grouping + logos. The UI mirrors the browsers card and ranks by\n`request_count`.","required":["provider","agent","purpose","request_count","unique_ips"],"properties":{"agent":{"type":"string"},"last_seen":{"type":["string","null"],"description":"Last-seen timestamp in RFC3339 format, or `None` if no rows matched.","example":"2026-05-29T12:00:00Z"},"provider":{"type":"string"},"purpose":{"type":"string"},"request_count":{"type":"integer","format":"int64"},"unique_ips":{"type":"integer","format":"int64"}}},"AiAgentDescriptor":{"type":"object","description":"Static descriptor for one entry in the known-AI-agents taxonomy.","required":["provider","agent","purpose"],"properties":{"agent":{"type":"string"},"provider":{"type":"string"},"purpose":{"type":"string"}}},"AiAgentPageRow":{"type":"object","description":"One row in the pages-by-agent breakdown. Returned by\n[`ProxyLogService::get_ai_agent_pages`] for a single named agent.\n`unique_ips` counts distinct client IPs that hit this path via that agent\n(same definition as the per-agent unique-IPs in [`AiAgentBreakdownRow`]).","required":["path","request_count","unique_ips"],"properties":{"last_seen":{"type":["string","null"],"description":"Last-seen timestamp in RFC3339 format, or `None` if no rows matched.","example":"2026-05-29T12:00:00Z"},"path":{"type":"string"},"request_count":{"type":"integer","format":"int64"},"unique_ips":{"type":"integer","format":"int64"}}},"AiAgentPagesResponse":{"type":"object","description":"Response wrapping the per-agent pages breakdown rows.","required":["agent","items","start_time","end_time"],"properties":{"agent":{"type":"string","description":"The agent name this breakdown is scoped to."},"end_time":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiAgentPageRow"}},"start_time":{"type":"string"}}},"AiAgentTimelineResponse":{"type":"object","description":"Response wrapping the AI agent timeline rows.","required":["items","start_time","end_time","bucket","group_by"],"properties":{"bucket":{"type":"string","description":"Bucket interval used for the buckets (so the UI can label the x-axis).","example":"1 hour"},"end_time":{"type":"string"},"group_by":{"type":"string","description":"Echoes the grouping dimension actually applied.","example":"provider"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiAgentTimelineRow"}},"start_time":{"type":"string"}}},"AiAgentTimelineRow":{"type":"object","description":"One point in the AI-agent timeline: the request count for a single\n(`bucket`, `key`) pair, where `key` is a provider or agent name depending on\nthe requested grouping. The UI pivots these into one stacked series per\n`key` across the shared bucket x-axis.","required":["bucket","key","request_count"],"properties":{"bucket":{"type":"string","description":"Bucket start in RFC3339 format.","example":"2026-05-29T12:00:00Z"},"key":{"type":"string","description":"Provider or agent name this count belongs to.","example":"OpenAI"},"request_count":{"type":"integer","format":"int64"}}},"AiChatLimitsSettings":{"type":"object","description":"Bounds on one AI chat turn.\n\nA turn is bounded by TIME rather than by a number of steps. A step count\nsays nothing about cost or about how long someone has been watching a\nspinner, and it cuts short exactly the long, productive turns the chat\nexists for. The user can already see each tool call and press Stop; the\ndeadline is what guarantees an *unattended* turn still ends.\n\nThe right value is a property of the model, which is why it is configurable\nrather than compiled in: a full alert-suggestion turn takes ~10 minutes\nagainst a slow local model and seconds against a hosted one.","properties":{"turn_timeout_secs":{"type":"integer","format":"int32","description":"How long one turn may run before it is stopped and the partial answer\nreturned, in seconds. The user is told the turn was cut short.\n\nChecked between steps, not mid-call: a model round already in flight\nfinishes, so a turn can overrun by up to one round. Against a slow\nself-hosted model that is a minute or two. Aborting mid-stream would cut\nthe answer off in the middle of a sentence and throw away work already\npaid for, which is worse than a late stop.","default":900,"example":900,"maximum":3600,"minimum":30}}},"AiConfigSettings":{"type":"object","description":"Global AI configuration settings. Controls the default config repo\ncontaining `.claude/` directory (skills, MCP servers, plugins) that\ngets overlaid into every agent sandbox.","properties":{"config_repo":{"type":"string","description":"Global config repo URL in \"owner/repo\" format (e.g. \"myorg/claude-config\").\nCloned at agent run time and overlaid into the sandbox's `.claude/` directory.","default":"","example":""},"config_repo_branch":{"type":"string","description":"Branch of the config repo to use.","default":"main","example":"main"}}},"AiDataAccessResponse":{"type":"object","required":["service_id","enabled"],"properties":{"enabled":{"type":"boolean","description":"Whether the AI assistant may read row data from this service","example":false},"service_id":{"type":"integer","format":"int32","description":"Service id"}}},"AiPageBreakdownResponse":{"type":"object","description":"Response wrapping the AI page breakdown rows.","required":["items","start_time","end_time"],"properties":{"end_time":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiPageBreakdownRow"}},"start_time":{"type":"string"}}},"AiPageBreakdownRow":{"type":"object","description":"One row in the AI-crawled-pages breakdown. `agent_count` is the number of\n*distinct* AI agents that hit this path, so the UI can show both how heavily\nand how broadly a page is being crawled.","required":["path","request_count","agent_count"],"properties":{"agent_count":{"type":"integer","format":"int64"},"last_seen":{"type":["string","null"],"description":"Last-seen timestamp in RFC3339 format, or `None` if no rows matched.","example":"2026-05-29T12:00:00Z"},"path":{"type":"string"},"request_count":{"type":"integer","format":"int64"}}},"AiStatusBreakdownResponse":{"type":"object","description":"Response wrapping the AI status breakdown rows.","required":["items","start_time","end_time"],"properties":{"end_time":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiStatusBreakdownRow"}},"start_time":{"type":"string"}}},"AiStatusBreakdownRow":{"type":"object","description":"One row in the AI-agent HTTP status breakdown: the request count for a\nstatus class (`2xx`/`3xx`/`4xx`/`5xx`/`other`) across crawler traffic.","required":["status_class","request_count"],"properties":{"request_count":{"type":"integer","format":"int64"},"status_class":{"type":"string","description":"Status class label.","example":"2xx"}}},"AlarmListResponse":{"type":"object","description":"Paginated list of alarms.","required":["items","total","page","page_size"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AlarmResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"AlarmResponse":{"type":"object","description":"Full alarm representation returned by list/summary endpoints.","required":["id","project_id","alarm_type","severity","status","title","fired_at","created_at","updated_at"],"properties":{"acknowledged_at":{"type":["string","null"],"description":"ISO-8601 UTC timestamp when the alarm was acknowledged, if any."},"acknowledged_by":{"type":["integer","null"],"format":"int32","description":"User ID who acknowledged the alarm, if any."},"alarm_type":{"type":"string"},"container_id":{"type":["integer","null"],"format":"int32"},"created_at":{"type":"string","description":"ISO-8601 UTC timestamp when the row was created."},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"fired_at":{"type":"string","description":"ISO-8601 UTC timestamp when the alarm fired."},"id":{"type":"integer","format":"int32"},"message":{"type":["string","null"]},"metadata":{"description":"Arbitrary JSON metadata attached by the alarm source."},"project_id":{"type":"integer","format":"int32"},"resolved_at":{"type":["string","null"],"description":"ISO-8601 UTC timestamp when the alarm was resolved, if any."},"service_id":{"type":["integer","null"],"format":"int32"},"severity":{"type":"string"},"status":{"type":"string"},"title":{"type":"string"},"updated_at":{"type":"string","description":"ISO-8601 UTC timestamp when the row was last updated."}}},"AlarmSummaryResponse":{"type":"object","description":"Re-export AlarmSummary for the OpenAPI schema.","required":["total_active","firing","acknowledged","critical","warning","by_type"],"properties":{"acknowledged":{"type":"integer","format":"int32","minimum":0},"by_type":{"type":"object","additionalProperties":{"type":"integer","format":"int32","minimum":0},"propertyNames":{"type":"string"}},"critical":{"type":"integer","format":"int32","minimum":0},"firing":{"type":"integer","format":"int32","minimum":0},"total_active":{"type":"integer","format":"int32","minimum":0},"warning":{"type":"integer","format":"int32","minimum":0}}},"AlertRuleResponse":{"type":"object","required":["id","project_id","name","trigger_type","trigger_config","notification_priority","cooldown_minutes","enabled","created_at","updated_at"],"properties":{"cooldown_minutes":{"type":"integer","format":"int32"},"created_at":{"type":"string"},"enabled":{"type":"boolean"},"environment_filter":{"type":["integer","null"],"format":"int32"},"error_level_filter":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"notification_priority":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"trigger_config":{},"trigger_type":{"type":"string"},"updated_at":{"type":"string"}}},"AllocEntry":{"type":"object","description":"Wire-format allocation. `null` in the JSON when the node hasn't been\nallocated yet — workers should treat that as \"single-host mode, do\nnot bring up the overlay\".","required":["node_id","compute_cidr","bridge_address","underlay_address"],"properties":{"bridge_address":{"type":"string"},"compute_cidr":{"type":"string"},"node_id":{"type":"string","description":"Stable v5 UUID derived from the database node id."},"underlay_address":{"type":"string"}}},"AnalyticsSessionEventsResponse":{"type":"object","required":["session_id","events","total_events"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/SessionEvent"}},"session_id":{"type":"string"},"total_events":{"type":"integer","minimum":0}}},"AnnotatedSpan":{"type":"object","description":"A single span annotated with the project that originally stored it.\nUsed in `UnifiedTrace` to let the UI colour-code spans by project.","required":["project_id","project_name","span"],"properties":{"project_id":{"type":"integer","format":"int32","description":"The project that stored this span (same as `span.project_id`)."},"project_name":{"type":"string","description":"Human-readable project name for waterfall colour-coding and legend."},"span":{"$ref":"#/components/schemas/SpanRecord","description":"Original span data verbatim from storage."}}},"AnomalyAlgorithm":{"type":"string","description":"Anomaly baseline algorithm. Adding one (e.g. a new robust variant) is a\ncode-only enum addition — no migration, since it lives inside the blob.","enum":["robust","basic","agile","ewma"]},"AnomalyParams":{"type":"object","description":"Seasonal anomaly-band detector parameters (stub — not yet evaluated).","properties":{"algorithm":{"$ref":"#/components/schemas/AnomalyAlgorithm","description":"Baseline model. `robust` is the default (seasonal, stable, flags level\nshifts); `ewma`/`agile` adopt level shifts; `basic` is non-seasonal."},"baseline_lookback_days":{"type":["integer","null"],"format":"int32","description":"How far back to build the baseline. `None` = an evaluator default."},"deviations":{"type":"number","format":"double","description":"Band width in robust standard deviations (Datadog's `bounds`)."},"direction":{"$ref":"#/components/schemas/Direction","description":"Which side(s) of the band a deviation must be on to count."},"pct_anomalous":{"type":"number","format":"double","description":"Fraction (0..=1) of points in the window that must be anomalous to fire."},"seasonality":{"$ref":"#/components/schemas/Seasonality","description":"Seasonality model for the baseline."}}},"AnomalyPreviewPointResponse":{"type":"object","required":["bucket","value","lower","upper","breaching"],"properties":{"breaching":{"type":"boolean"},"bucket":{"type":"string","example":"2025-10-12T12:15:47Z"},"lower":{"type":"number","format":"double","description":"Lower edge of the expected band at this point."},"upper":{"type":"number","format":"double","description":"Upper edge of the expected band at this point."},"value":{"type":"number","format":"double"}}},"AnomalyPreviewRequest":{"type":"object","required":["project_id","metric_name","aggregation","window_secs","detection_config"],"properties":{"aggregation":{"type":"string","description":"One of `avg|sum|min|max|count|rate|p50|p90|p95|p99`."},"detection_config":{"$ref":"#/components/schemas/DetectionConfig","description":"The detector to backtest. `static` and `anomaly` are supported — the\nkinds the evaluator actually runs."},"end_time":{"type":["string","null"],"description":"RFC 3339; defaults to now.","example":"2025-10-12T12:15:47Z"},"metric_name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"start_time":{"type":["string","null"],"description":"RFC 3339; defaults to 7 days before `end_time`.","example":"2025-10-12T12:15:47Z"},"window_secs":{"type":"integer","format":"int32"}}},"AnomalyPreviewResponse":{"type":"object","required":["points","breach_count","baseline_samples","sufficient"],"properties":{"baseline_samples":{"type":"integer","format":"int64","description":"Baseline sample count (drives the `sufficient` flag)."},"breach_count":{"type":"integer","format":"int64","description":"How many points in the range would have fired."},"points":{"type":"array","items":{"$ref":"#/components/schemas/AnomalyPreviewPointResponse"}},"sufficient":{"type":"boolean","description":"Whether the baseline had enough history for a trustworthy band."}}},"ApiKeyListResponse":{"type":"object","required":["api_keys","total"],"properties":{"api_keys":{"type":"array","items":{"$ref":"#/components/schemas/ApiKeyResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"ApiKeyResponse":{"type":"object","required":["id","name","key_prefix","role_type","is_active","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00Z"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"key_prefix":{"type":"string"},"last_used_at":{"type":["string","null"],"format":"date-time","example":"2024-01-01T00:00:00Z"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"}},"role_type":{"type":"string"}}},"AppSettings":{"type":"object","description":"Application settings stored in the database\nAll fields have sensible defaults for easy onboarding","properties":{"agent_sandbox":{"oneOf":[{"$ref":"#/components/schemas/AgentSandboxSettings"}],"default":{"default_provider":"claude_cli","providers":{},"auth_type":"subscription","api_key_encrypted":null,"enabled":true,"runtime":"node","custom_image":"","cpu_limit":4.0,"memory_limit_mb":8192,"network_mode":"full","sandbox_backend":null}},"ai_chat_limits":{"oneOf":[{"$ref":"#/components/schemas/AiChatLimitsSettings","description":"Limits on a single AI chat turn. Operator-tunable because the right\nvalue depends on the model: a turn against a slow self-hosted model can\nlegitimately take ten minutes, while a hosted one finishes in seconds\nand a shorter ceiling keeps costs predictable."}],"default":{"turn_timeout_secs":900}},"ai_config":{"oneOf":[{"$ref":"#/components/schemas/AiConfigSettings"}],"default":{"config_repo":"","config_repo_branch":"main"}},"build_limits":{"oneOf":[{"$ref":"#/components/schemas/BuildLimitsSettings","description":"Build-time resource limits applied on the control plane to prevent\n`docker build` from saturating host CPU/RAM. Worker nodes are\nintentionally NOT subject to these limits (each worker is dedicated\nhardware that already has its own per-host headroom)."}],"default":{"max_concurrent":2,"cpu_limit_cores":0.0,"memory_limit_mb":0}},"cloud":{"oneOf":[{"$ref":"#/components/schemas/CloudSettings","description":"Managed control-plane connection. Credentials are deliberately not\nstored here; they live in the owner-only cloud-link state file."}],"default":{"backend_url":"https://app.temps.sh"}},"cluster_dns":{"oneOf":[{"$ref":"#/components/schemas/ClusterDnsSettings","description":"Cluster-DNS resolver settings (ADR-024, experimental beta). Off by\ndefault — see `ClusterDnsSettings` for the incident background and\ntrade-offs. Must be explicitly enabled by operators who need\n`*.temps.local` service-to-service resolution inside containers."}],"default":{"enabled":false}},"console_version":{"type":["string","null"],"description":"Binary version tag (e.g. \"v0.1.0\") of the *console* process\n(`temps serve`, role=all or role=console) that last started. Written\non console startup; read by the standalone `temps proxy` to detect\nversion skew during a rolling upgrade (ADR-017 Phase 3). `None` on\ninstalls that never ran a console build carrying this field.\n\nThis is informational state written by the binary itself — NOT an\noperator-tunable setting. It is intentionally absent from\n`AppSettingsResponse` and the PATCH path so an operator cannot\naccidentally overwrite the self-recorded value.","default":null},"container_logs":{"oneOf":[{"$ref":"#/components/schemas/ContainerLogSettings"}],"default":{"max_size":"50m","max_file":3,"service_max_size":"20m","service_max_file":3}},"disk_space_alert":{"oneOf":[{"$ref":"#/components/schemas/DiskSpaceAlertSettings"}],"default":{"enabled":true,"threshold_percent":80,"check_interval_seconds":300,"monitor_path":null}},"dns_provider":{"oneOf":[{"$ref":"#/components/schemas/DnsProviderSettings"}],"default":{"provider":"manual","cloudflare_api_key":null}},"docker_registry":{"oneOf":[{"$ref":"#/components/schemas/DockerRegistrySettings"}],"default":{"enabled":false,"registry_url":null,"username":null,"password":null,"tls_verify":true,"ca_certificate":null}},"edge_target":{"type":["string","null"],"description":"Public edge target that generated DNS records point at when a managed\ndomain opts into automatic record sync. An IPv4/IPv6 address produces an\n`A`/`AAAA` record; anything else is treated as a `CNAME` target. `None`\ndisables DNS record sync regardless of per-domain opt-in.","default":null},"external_url":{"type":["string","null"],"default":null},"insecure_tls":{"type":"boolean","description":"Skip TLS certificate verification on outbound HTTP clients built by the\nserver (deployer, agent, remote service client). Strictly opt-in for\noperators running self-signed control plane / worker certs on a trusted\ninternal network. Worker→control-plane traffic that traverses the public\ninternet must keep this `false` — otherwise a MitM steals the join token.","default":false},"internal_url":{"type":["string","null"],"description":"URL that service containers use to reach the Temps API from *inside*\nthe Docker network (OTLP metrics ingest, agent callbacks, etc.). On\nDocker Desktop this defaults to `http://host.docker.internal:`;\non Linux it requires the `host.docker.internal:host-gateway` host\nmapping (which Temps adds to provisioned containers). Distinct from\n`external_url`, which is the public-facing address.","default":null},"letsencrypt":{"oneOf":[{"$ref":"#/components/schemas/LetsEncryptSettings"}],"default":{"email":null,"environment":"production"}},"monitoring":{"oneOf":[{"$ref":"#/components/schemas/MonitoringSettings","description":"Metrics observability settings. Controls the MetricsStore backend,\nscrape interval, and tiered retention windows."}],"default":{"enabled":false,"store":"timescale_db","scrape_interval_secs":30,"retention_raw_days":7,"retention_hourly_days":90,"retention_daily_years":2,"clickhouse_url":null}},"multi_node":{"oneOf":[{"$ref":"#/components/schemas/MultiNodeSettings"}],"default":{"join_token_hash":null,"private_address":null,"legacy_shared_token_enabled":true,"cluster_ca_cert_pem":null,"cluster_ca_key_encrypted":null,"require_mtls":false,"node_cpu_alert_percent":90.0,"node_memory_alert_percent":90.0,"node_disk_alert_percent":90.0}},"observability_compression":{"oneOf":[{"$ref":"#/components/schemas/ObservabilityCompressionSettings","description":"TimescaleDB compression delays for immutable observability data.\nChanges are applied at runtime by the Settings API."}],"default":{"proxy_logs_after_hours":24,"otel_spans_after_hours":24}},"observability_retention":{"oneOf":[{"$ref":"#/components/schemas/ObservabilityRetentionSettings","description":"Retention windows for raw proxy and OpenTelemetry telemetry.\nTimescaleDB policies are updated at runtime by the Settings API."}],"default":{"proxy_logs_days":30,"otel_spans_days":90,"otel_logs_days":90,"otel_metrics_days":90}},"on_demand_tls":{"oneOf":[{"$ref":"#/components/schemas/OnDemandTlsSettings"}],"default":{"enabled":false,"zone":null,"max_concurrent":3,"hourly_cap":10,"deployment_url_mode":"http"}},"preview_domain":{"type":"string","default":"localho.st"},"preview_gateway":{"oneOf":[{"$ref":"#/components/schemas/PreviewGatewaySettings"}],"default":{"image":"ghcr.io/gotempsh/temps-preview-gateway:latest","host_port":8090,"auto_upgrade":true}},"rate_limiting":{"oneOf":[{"$ref":"#/components/schemas/RateLimitSettings"}],"default":{"enabled":false,"max_requests_per_minute":60,"max_requests_per_hour":1000,"whitelist_ips":[],"blacklist_ips":[]}},"require_mfa_for_admins":{"type":"boolean","description":"When `true`, any user holding the `Admin` role must have MFA enrolled\n(`users.mfa_enabled = true`) to complete a **password** login. Users\nwithout MFA enrolled are rejected with a typed error instructing them\nto enroll before retrying. This only gates the password-login path\n(`AuthService::login`) -- SSO/OIDC logins are handled by a separate\ncode path (`OidcService::resolve_user` + `oidc_handler`) and are\nintentionally unaffected, since federating identity to a\nproperly-hardened IdP is itself an acceptable alternative to local\nTOTP MFA. Modeled as a settings row (not an env var) per CLAUDE.md so\nan operator can flip it at runtime via the Settings API without\nrestarting the binary.","default":false},"screenshots":{"oneOf":[{"$ref":"#/components/schemas/ScreenshotSettings"}],"default":{"enabled":false,"provider":"local","url":""}},"security_headers":{"oneOf":[{"$ref":"#/components/schemas/SecurityHeadersSettings"}],"default":{"enabled":false,"preset":"moderate","content_security_policy":"default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'self'","x_frame_options":"SAMEORIGIN","x_content_type_options":"nosniff","x_xss_protection":"1; mode=block","strict_transport_security":"max-age=31536000; includeSubDomains","referrer_policy":"strict-origin-when-cross-origin","permissions_policy":"geolocation=(), microphone=(), camera=()"}},"setup_complete":{"type":"boolean","description":"Set to `true` by `temps setup` (all modes) once initial configuration\nhas been applied. The web onboarding wizard reads this from the server\nand skips itself when true, preventing the \"Configure Base Domain\" wall\nfrom appearing on installs that were already configured via the CLI.","default":false}}},"AppSettingsResponse":{"type":"object","description":"Safe response for application settings that masks sensitive fields","required":["preview_domain","screenshots","letsencrypt","dns_provider","security_headers","rate_limiting","docker_registry","disk_space_alert","container_logs","agent_sandbox","ai_config","preview_gateway","multi_node","monitoring","observability_compression","observability_retention","effective_metrics_store","effective_observability_store","insecure_tls","setup_complete","require_mfa_for_admins","cluster_dns","build_limits","ai_chat_limits"],"properties":{"agent_sandbox":{"$ref":"#/components/schemas/AgentSandboxSettingsMasked"},"ai_chat_limits":{"$ref":"#/components/schemas/AiChatLimitsSettings","description":"Per-turn limits for the AI chat. No sensitive content."},"ai_config":{"$ref":"#/components/schemas/AiConfigSettings"},"build_limits":{"$ref":"#/components/schemas/BuildLimitsSettings","description":"Build-time resource limits (control-plane only). No sensitive content,\npassed through as-is."},"cluster_dns":{"$ref":"#/components/schemas/ClusterDnsSettings","description":"Cluster-DNS resolver settings (ADR-024, experimental beta). No masking\nneeded — `enabled` is a plain bool with no sensitive content. Passed\nthrough as-is so the settings UI can read and toggle the flag."},"container_logs":{"$ref":"#/components/schemas/ContainerLogSettings"},"disk_space_alert":{"$ref":"#/components/schemas/DiskSpaceAlertSettings"},"dns_provider":{"$ref":"#/components/schemas/DnsProviderSettingsMasked"},"docker_registry":{"$ref":"#/components/schemas/DockerRegistrySettingsMasked"},"edge_target":{"type":["string","null"],"description":"Public edge target that synced DNS records point at (IP → A/AAAA, else CNAME)."},"effective_metrics_store":{"$ref":"#/components/schemas/MetricsStoreKind","description":"The storage backend the runtime is **actually** using for metrics,\nafter reconciling the `monitoring.store` toggle with the server's\n`TEMPS_CLICKHOUSE_*` configuration. When `monitoring.store` is\n`click_house` but those env vars are not fully set, the runtime falls\nback to TimescaleDB — in that case this reports `timescale_db` even\nthough `monitoring.store` says `click_house`. The UI shows this as the\neffective backend and warns when it diverges from the configured store."},"effective_observability_store":{"$ref":"#/components/schemas/MetricsStoreKind","description":"Storage backend actually used for proxy logs, OTel spans, and OTel\nmetrics. OTel logs remain TimescaleDB-backed. Unlike resource metrics,\nthese domains switch to ClickHouse whenever the server-level ClickHouse\nconnection is configured; they do not use the monitoring store toggle."},"external_url":{"type":["string","null"]},"insecure_tls":{"type":"boolean"},"internal_url":{"type":["string","null"]},"letsencrypt":{"$ref":"#/components/schemas/LetsEncryptSettings"},"monitored_services_count":{"type":["integer","null"],"format":"int64","description":"Number of enabled, running services the MetricsScraper currently\nincludes. Used for the lightweight storage estimate in the UI.","minimum":0},"monitoring":{"$ref":"#/components/schemas/MonitoringSettingsMasked"},"multi_node":{"$ref":"#/components/schemas/MultiNodeSettingsMasked"},"observability_compression":{"$ref":"#/components/schemas/ObservabilityCompressionSettings","description":"TimescaleDB compression delays for immutable proxy logs and OTel spans."},"observability_retention":{"$ref":"#/components/schemas/ObservabilityRetentionSettings","description":"Retention windows for raw proxy logs and OpenTelemetry data."},"preview_domain":{"type":"string"},"preview_gateway":{"$ref":"#/components/schemas/PreviewGatewaySettingsMasked"},"rate_limiting":{"$ref":"#/components/schemas/RateLimitSettings"},"require_mfa_for_admins":{"type":"boolean","description":"When enabled, Admin-role accounts without MFA enrolled are rejected\nat password login (bherila/temps#32). SSO/OIDC logins are unaffected."},"screenshots":{"$ref":"#/components/schemas/ScreenshotSettings"},"security_headers":{"$ref":"#/components/schemas/SecurityHeadersSettings"},"setup_complete":{"type":"boolean","description":"Whether `temps setup` has been run at least once. The web onboarding\nwizard checks this field on load and skips itself when true."}}},"ApplyHostnameModeRequest":{"type":"object","description":"Request to apply a hostname mode (recompute + optional DNS sync).","required":["mode"],"properties":{"mode":{"type":"string","description":"Target mode to apply: `\"standard\"` or `\"flat\"`."},"sync_dns":{"type":"boolean","description":"Also reconcile the provider's DNS zone for the affected hostnames."}}},"ArchiveFlagResponse":{"type":"object","required":["key"],"properties":{"archived_at":{"type":["string","null"]},"key":{"type":"string"}}},"ArchiveMode":{"type":"string","enum":["off","on","always","unknown"]},"AssignRoleRequest":{"type":"object","required":["user_id","role_type"],"properties":{"role_type":{"type":"string"},"user_id":{"type":"integer","format":"int32"}}},"AttachScheduleServicesRequest":{"type":"object","description":"Body for `POST /api/backups/schedules/{id}/services` — attach external\nservices to a backup schedule. Idempotent.","required":["service_ids"],"properties":{"service_ids":{"type":"array","items":{"type":"integer","format":"int32"},"description":"External service ids to attach. Duplicates are de-duplicated server-side."}}},"AttachScheduleServicesResponse":{"type":"object","description":"Response for `POST /api/backups/schedules/{id}/services`.","required":["inserted","total_attached"],"properties":{"inserted":{"type":"integer","format":"int64","description":"Number of rows actually inserted (excludes rows skipped by\n`ON CONFLICT DO NOTHING`).","minimum":0},"total_attached":{"type":"integer","description":"Total number of services now attached to the schedule.","minimum":0}}},"AuditLogIpInfo":{"type":"object","description":"IP address information in audit log","required":["ip"],"properties":{"city":{"type":["string","null"],"description":"City name","example":"San Francisco"},"country":{"type":["string","null"],"description":"Country code","example":"US"},"ip":{"type":"string","description":"IP address","example":"192.168.1.1"},"latitude":{"type":["number","null"],"format":"double","description":"Latitude","example":37.7749},"longitude":{"type":["number","null"],"format":"double","description":"Longitude","example":122.4194}}},"AuditLogResponse":{"type":"object","description":"Response type for audit log entries","required":["id","operation_type","audit_date"],"properties":{"audit_date":{"type":"integer","format":"int64","description":"When the action occurred","example":11932193},"data":{"description":"Additional context about the action"},"id":{"type":"integer","format":"int32","description":"Unique identifier for the audit log entry"},"ip_address":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AuditLogIpInfo","description":"IP address details"}]},"operation_type":{"type":"string","description":"The type of action that was performed","example":"USER_LOGIN"},"user":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AuditLogUserInfo","description":"User details who performed the action"}]},"user_id":{"type":["integer","null"],"format":"int32","description":"The user who performed the action (`null` when that account has\nsince been deleted; `data` retains the original actor context)"}}},"AuditLogUserInfo":{"type":"object","description":"User information in audit log","required":["id","name","email"],"properties":{"email":{"type":"string","description":"User's email","example":"john.doe@example.com"},"id":{"type":"integer","format":"int32","description":"User ID"},"name":{"type":"string","description":"User's name","example":"John Doe"}}},"AuthFlavorDto":{"type":"object","description":"One auth flavor surfaced to the UI. Mirrors `AuthFlavor` in the catalog\nbut without the seed-path / env-var fields the frontend doesn't need\n(those are server-side only — exposing them just bloats the response).","required":["id","label","description","format"],"properties":{"description":{"type":"string"},"env_var":{"type":["string","null"],"description":"For `api_key` format: the env var name that will be set inside the\nsandbox. Useful for showing the user \"we'll set OPENAI_API_KEY\" so\nthey know what their key controls."},"format":{"type":"string","description":"`api_key`, `oauth_token`, or `config_file` — drives which input UI\nthe settings page renders (single-line vs. multi-line textarea)."},"id":{"type":"string"},"label":{"type":"string"}}},"AuthResponse":{"type":"object","required":["success","message","mfa_required","mfa_enrollment_required","password_change_required"],"properties":{"message":{"type":"string"},"mfa_enrollment_required":{"type":"boolean"},"mfa_required":{"type":"boolean"},"mfa_setup":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MfaSetupResponse"}]},"password_change_required":{"type":"boolean"},"success":{"type":"boolean"},"user_id":{"type":["integer","null"],"format":"int32"}}},"AuthStatusResponse":{"type":"object","required":["status"],"properties":{"cli_token":{"type":["string","null"]},"status":{"type":"string"}}},"AuthTokenResponse":{"type":"object","required":["access_token","refresh_token","expires_at"],"properties":{"access_token":{"type":"string"},"expires_at":{"type":"integer","format":"int64"},"refresh_token":{"type":"string"}}},"AutoWatchParams":{"type":"object","description":"Auto-watch (Watchdog-style) detector parameters (stub — not evaluated).","properties":{"direction":{"$ref":"#/components/schemas/Direction","description":"The engine self-tunes the band; the user supplies only the direction."}}},"AutofixRunConfig":{"type":"object","description":"User-chosen per-run options, persisted as JSON in `agent_runs.run_config`.\nEvery field is optional — unset fields fall back to the provider defaults\nin settings, then to built-in defaults.","properties":{"branch":{"type":["string","null"],"description":"Branch to clone instead of the project's main branch.","default":null},"max_turns":{"type":["integer","null"],"format":"int32","description":"Per-run turn cap applied to every phase of this run. Only enforced\nfor CLIs with a turn flag (Claude Code); Codex/OpenCode run to\ncompletion. `None` uses the provider's per-phase defaults.","default":null},"model":{"type":["string","null"],"description":"Model id for the chosen provider. `None` uses the provider's saved\ndefault model, or the CLI's own default.","default":null},"provider":{"type":["string","null"],"description":"AI provider id (\"claude_cli\", \"codex_cli\", \"opencode\"). `None` uses\nthe platform default provider from agent sandbox settings.","default":null}}},"AutofixerRunResponse":{"type":"object","required":["id","project_id","status","tokens_input","tokens_output","files_changed","created_at"],"properties":{"ai_model":{"type":["string","null"]},"ai_output":{"type":["string","null"]},"ai_provider":{"type":["string","null"],"description":"AI provider slug this run executes with (e.g. claude_cli, codex_cli)."},"analysis":{"type":["string","null"]},"branch_name":{"type":["string","null"]},"completed_at":{"type":["string","null"]},"created_at":{"type":"string"},"error_message":{"type":["string","null"]},"files_changed":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"phase":{"type":["string","null"]},"pr_number":{"type":["integer","null"],"format":"int32"},"pr_url":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"run_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AutofixRunConfig","description":"Per-run options the run was started with; used to prefill the\nretry / start-over dialog."}]},"started_at":{"type":["string","null"]},"status":{"type":"string"},"tokens_input":{"type":"integer","format":"int32"},"tokens_output":{"type":"integer","format":"int32"},"trigger_source_id":{"type":["integer","null"],"format":"int32"},"user_context":{"type":["string","null"]}}},"AutofixerRunWithLogsResponse":{"type":"object","required":["run","logs"],"properties":{"logs":{"type":"array","items":{"$ref":"#/components/schemas/AgentRunLogResponse"}},"run":{"$ref":"#/components/schemas/AutofixerRunResponse"}}},"AvailableContainerInfo":{"type":"object","description":"Available Docker container that can be imported as a service","required":["container_id","container_name","image","version","service_type","is_running"],"properties":{"container_id":{"type":"string","description":"Container ID or name","example":"abc123def456"},"container_name":{"type":"string","description":"Container display name","example":"my-postgres"},"exposed_ports":{"type":"array","items":{"type":"integer","format":"int32","minimum":0},"description":"Exposed ports (e.g., [5432] for PostgreSQL, [6379] for Redis)"},"image":{"type":"string","description":"Docker image name (e.g., \"gotempsh/postgres-walg:18-bookworm\")","example":"gotempsh/postgres-walg:18-bookworm"},"is_running":{"type":"boolean","description":"Whether the container is currently running","example":true},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute","description":"Service type this container represents"},"version":{"type":"string","description":"Extracted version from image","example":"18"}}},"AvailablePermissions":{"type":"object","description":"Response containing all available permissions for frontend validation","required":["permissions","roles"],"properties":{"permissions":{"type":"array","items":{"$ref":"#/components/schemas/PermissionInfo"},"description":"All available permissions in the system"},"roles":{"type":"array","items":{"$ref":"#/components/schemas/RoleInfo"},"description":"All available roles"}}},"BackupAlertListResponse":{"type":"object","description":"Response body for the list-backup-alerts endpoint.","required":["alerts"],"properties":{"alerts":{"type":"array","items":{"$ref":"#/components/schemas/BackupAlertResponse"},"description":"All currently open (unresolved) alerts, newest first."}}},"BackupAlertResponse":{"type":"object","description":"A single open backup alert surfaced in the UI banner.\n\nAlerts are auto-opened by the watcher and auto-resolved when the triggering\ncondition clears. No manual dismiss is required or supported.\n\nThe optional `schedule_s3_source_id` field is included so the UI can\ndeep-link an `overdue_schedule` alert to the S3 source detail page that\nhosts the schedule. `stalled_job` alerts no longer carry a deep-link\ntarget — the alert message text contains the backup id for display.","required":["id","kind","severity","message","opened_at"],"properties":{"id":{"type":"integer","format":"int64","description":"Database id of the alert row."},"kind":{"type":"string","description":"`\"overdue_schedule\"` or `\"stalled_job\"`."},"message":{"type":"string","description":"Human-readable description of the alert condition."},"opened_at":{"type":"string","description":"RFC 3339 timestamp when the alert was opened.","example":"2026-05-15T10:00:00Z"},"schedule_id":{"type":["integer","null"],"format":"int32","description":"FK to `backup_schedules.id`. Set for `overdue_schedule` alerts."},"schedule_name":{"type":["string","null"],"description":"Human-readable name of the linked schedule, if applicable."},"schedule_s3_source_id":{"type":["integer","null"],"format":"int32","description":"FK to `backup_schedules.s3_source_id`. The UI uses this to deep-link\nthe alert to the S3 source detail page that hosts the schedule.\nSet for `overdue_schedule` alerts."},"severity":{"type":"string","description":"`\"warning\"` or `\"critical\"`."}}},"BackupResponse":{"type":"object","description":"Response type for backup","required":["id","name","backup_id","backup_type","state","started_at","s3_source_id","s3_location","metadata","compression_type","created_by","tags"],"properties":{"attempts":{"type":["integer","null"],"format":"int32","description":"How many times this job has been claimed and run. `null` for legacy\nbackups with no `backup_jobs` row."},"backup_id":{"type":"string"},"backup_type":{"type":"string"},"checksum":{"type":["string","null"]},"completed_at":{"type":["integer","null"],"format":"int64"},"compression_type":{"type":"string"},"created_by":{"type":"integer","format":"int32"},"current_step":{"type":["string","null"],"description":"Name of the engine step currently executing (e.g., `\"walg_push\"`).\n`null` when no `backup_jobs` row exists for this backup (legacy rows\npre-dating ADR-014), or when the job has not yet completed its first step."},"error_message":{"type":["string","null"]},"expires_at":{"type":["integer","null"],"format":"int64"},"external_service":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ExternalServiceSummary","description":"External service that owns this backup (Redis, Postgres, etc.).\n`null` for control-plane backups (the Temps server's own database)."}]},"file_count":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"live_size_bytes":{"type":["integer","null"],"format":"int64","description":"Best-effort partial size while a backup is still running, computed\nby listing the S3 prefix. Null when the backup is finished\n(`size_bytes` is authoritative in that case)."},"max_attempts":{"type":["integer","null"],"format":"int32","description":"Maximum attempts before the job is permanently failed. `null` for\nlegacy backups."},"max_runtime_secs":{"type":["integer","null"],"format":"int64","description":"Resolved wall-clock timeout for this backup job (seconds). `null` for\nlegacy backups. Derived from the three-tier resolution order:\ncaller override → schedule override → engine default."},"metadata":{},"name":{"type":"string"},"s3_location":{"type":"string"},"s3_source_id":{"type":"integer","format":"int32"},"schedule_id":{"type":["integer","null"],"format":"int32"},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Final size of the backup once completed. Null while running."},"started_at":{"type":"integer","format":"int64"},"state":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}}}},"BackupScheduleResponse":{"type":"object","description":"Response type for backup schedule","required":["id","name","backup_type","retention_period","s3_source_id","schedule_expression","enabled","created_at","updated_at","tags","target_all_services","include_control_plane"],"properties":{"backup_type":{"type":"string"},"created_at":{"type":"integer","format":"int64"},"description":{"type":["string","null"]},"enabled":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"include_control_plane":{"type":"boolean","description":"When `true`, every run also produces a `control_plane` backup\n(Temps's own Postgres). When `false`, only the external service\nfan-out happens."},"last_run":{"type":["integer","null"],"format":"int64"},"max_runtime_secs":{"type":["integer","null"],"format":"int64","description":"Per-schedule wall-clock timeout override for backup jobs (seconds).\n`null` means the engine-family default is used. See\n`temps_backup_core::timeouts::default_max_runtime_secs`."},"name":{"type":"string"},"next_run":{"type":["integer","null"],"format":"int64"},"retention_period":{"type":"integer","format":"int32"},"s3_source_id":{"type":"integer","format":"int32"},"schedule_expression":{"type":"string","example":"0 0 * * *"},"tags":{"type":"array","items":{"type":"string"}},"target_all_services":{"type":"boolean","description":"When `true`, the schedule auto-includes every external service on\nthe host (and any future ones). When `false`, the schedule only\ntargets services attached via `backup_schedule_services`."},"updated_at":{"type":"integer","format":"int64"}}},"BitbucketAuthInput":{"oneOf":[{"type":"object","description":"Personal / Workspace / Repository Access Token.","required":["token","type"],"properties":{"token":{"type":"string","description":"The Bitbucket access token value."},"type":{"type":"string","enum":["access_token"]}}},{"type":"object","description":"HTTP Basic / App Password authentication.","required":["username","password","type"],"properties":{"password":{"type":"string","description":"App password generated in Bitbucket security settings."},"type":{"type":"string","enum":["app_password"]},"username":{"type":"string","description":"Bitbucket account username."}}}],"description":"Authentication input for a Bitbucket Cloud provider. Use `access_token` for\na Repository or Workspace Access Token (PAT), or `username` + `app_password`\nfor App Password (HTTP Basic) authentication."},"BlobResponse":{"type":"object","description":"Response after uploading a blob","required":["url","pathname","contentType","size","uploadedAt"],"properties":{"contentType":{"type":"string","description":"Content type of the blob","example":"image/png"},"pathname":{"type":"string","description":"Original pathname","example":"images/avatar-abc123.png"},"size":{"type":"integer","format":"int64","description":"Size in bytes","example":12345},"uploadedAt":{"type":"string","format":"date-time","description":"Upload timestamp","example":"2025-01-03T12:00:00Z"},"url":{"type":"string","description":"URL path to access the blob","example":"/api/blob/123/images/avatar-abc123.png"}}},"BlobStatusResponse":{"type":"object","description":"Response for Blob service status","required":["enabled","healthy"],"properties":{"docker_image":{"type":["string","null"],"description":"Docker image being used","example":"ghcr.io/rustfs/rustfs:0.5.0"},"enabled":{"type":"boolean","description":"Whether the Blob service is enabled","example":true},"healthy":{"type":"boolean","description":"Whether the service is healthy","example":true},"version":{"type":["string","null"],"description":"Current version (if running)","example":"0.5.0"}}},"BranchInfo":{"type":"object","required":["name","commit_sha","protected"],"properties":{"commit_sha":{"type":"string"},"name":{"type":"string"},"protected":{"type":"boolean"}}},"BranchListResponse":{"type":"object","required":["branches"],"properties":{"branches":{"type":"array","items":{"$ref":"#/components/schemas/BranchInfo"}}}},"BrowserCount":{"type":"object","required":["browser","count","percentage"],"properties":{"browser":{"type":"string"},"count":{"type":"integer","format":"int64"},"percentage":{"type":"number","format":"double"}}},"BrowsersQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"BuildConfiguration":{"type":"object","description":"Build configuration (for building images from source)","required":["context","args"],"properties":{"args":{"type":"object","description":"Build arguments","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"context":{"type":"string","description":"Build context (Dockerfile path or buildpack)"},"dockerfile":{"type":["string","null"],"description":"Dockerfile path (relative to context)"},"target":{"type":["string","null"],"description":"Target stage (for multi-stage builds)"}}},"BuildLimitsSettings":{"type":"object","description":"Control-plane build resource limits.\n\nCaps how many builds run concurrently AND how much CPU/memory each build\nis allowed to consume. A single global semaphore in the deployer crate\ngates every `DockerRuntime::build_image` call to `max_concurrent`. When\nthe semaphore is full, additional builds queue and wait — they do not\nfail. Per-build CPU/memory caps are forwarded to Docker via\n`BuildImageOptions { memory, cpuquota, cpuperiod }`.\n\n`cpu_limit_cores = 0.0` or `memory_limit_mb = 0` means \"no explicit cap\"\n— fall back to the legacy 50%-of-host heuristic for backwards\ncompatibility with operators who never visit the settings page.","properties":{"cpu_limit_cores":{"type":"number","format":"float","description":"CPU cores allowed per build (float, e.g. 2.0 = 2 cores, 0.5 = half\na core). 0 means \"use the legacy 50%-of-host default\".","default":0.0,"example":2.0,"minimum":0},"max_concurrent":{"type":"integer","format":"int32","description":"Maximum number of `docker build` operations allowed to run at the\nsame time on the control plane. Additional builds queue. Min 1.","default":2,"example":2,"minimum":1},"memory_limit_mb":{"type":"integer","format":"int32","description":"Memory allowed per build, in megabytes. 0 means \"use the legacy\n50%-of-host default\". Docker enforces this as a hard cap — builds\nthat exceed it OOM-kill.","default":0,"example":2048,"minimum":0}}},"CancelBackupResponse":{"type":"object","description":"Response body for cancel endpoints.","required":["cancelled"],"properties":{"cancelled":{"type":"integer","format":"int64","description":"Number of rows that were actually flipped to `failed`. `0` is a valid\nsuccess and means the backup was already terminal — the call is\nidempotent.","minimum":0}}},"CertStatusResponse":{"type":"object","description":"Current on-demand cert status for a single hostname (ADR-018 §5). Backs\n`GET /domains/by-host/{hostname}/cert-status`.","required":["hostname"],"properties":{"backoff_until":{"type":["integer","null"],"format":"int64","description":"On-demand negative-cache deadline (epoch millis), when in backoff."},"hostname":{"type":"string","description":"SNI hostname."},"last_attempt":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/OnDemandCertAttemptResponse","description":"The most recent on-demand issuance attempt for this hostname, if any."}]},"status":{"type":["string","null"],"description":"Current cert lifecycle status from the `domains` row, when one exists."}}},"ChallengeConfig":{"type":"object","description":"Challenge configuration (future feature)\nFor CAPTCHA, JS challenges, proof-of-work, etc.","required":["challengeType","difficulty"],"properties":{"challengeType":{"type":"string","description":"Challenge type: \"captcha\", \"js_challenge\", \"proof_of_work\""},"difficulty":{"type":"integer","format":"int32","description":"Challenge difficulty level (1-10)","minimum":0},"protectedPaths":{"type":"array","items":{"type":"string"},"description":"Paths that require challenges"}}},"ChallengeError":{"type":"object","required":["type","detail","status"],"properties":{"detail":{"type":"string","description":"Human-readable error description"},"status":{"type":"integer","format":"int32","description":"HTTP status code"},"type":{"type":"string","description":"Error type (e.g., \"urn:ietf:params:acme:error:unauthorized\")"}}},"ChallengeValidationStatus":{"type":"object","required":["type","url","status","token"],"properties":{"error":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ChallengeError","description":"Error details if validation failed"}]},"status":{"type":"string","description":"Challenge status (e.g., \"pending\", \"valid\", \"invalid\")"},"token":{"type":"string","description":"Challenge token"},"type":{"type":"string","description":"Challenge type (e.g., \"dns-01\", \"http-01\")"},"url":{"type":"string","description":"Challenge validation URL"},"validated":{"type":["string","null"],"description":"When the challenge was validated (if successful)"}}},"ChangePasswordRequest":{"type":"object","required":["current_password","new_password"],"properties":{"current_password":{"type":"string","example":"current_password_value"},"mfa_code":{"type":["string","null"],"description":"TOTP code (or recovery code). Required iff the user has MFA enabled.","example":"123456"},"new_password":{"type":"string","example":"new_password_value"},"revoke_other_sessions":{"type":"boolean","description":"When true, every session OTHER than the one making this request is\nrevoked. Defaults to false; the UI surfaces this as a checkbox."}}},"ChangeProjectSourceRequest":{"type":"object","description":"Change a project's source type to a Git-less type (docker_image /\nstatic_files / manual). Switching TO `git` is done via the Git settings\nendpoint (which also supplies the repository + provider connection).","required":["source_type"],"properties":{"source_type":{"$ref":"#/components/schemas/SourceType"}}},"ChatCompletionChoice":{"type":"object","required":["index","message"],"properties":{"finish_reason":{"type":["string","null"]},"index":{"type":"integer","format":"int32"},"message":{"$ref":"#/components/schemas/ChatMessage"}}},"ChatCompletionRequest":{"allOf":[{"type":["object","null"],"description":"Tolerates extra SDK fields (stream_options, logprobs, etc.)","additionalProperties":{},"propertyNames":{"type":"string"}},{"type":"object","required":["model","messages"],"properties":{"frequency_penalty":{"type":["number","null"],"format":"double"},"max_tokens":{"type":["integer","null"],"format":"int64"},"messages":{"type":"array","items":{"$ref":"#/components/schemas/ChatMessage"}},"model":{"type":"string"},"n":{"type":["integer","null"],"format":"int32"},"presence_penalty":{"type":["number","null"],"format":"double"},"response_format":{},"seed":{"type":["integer","null"],"format":"int64"},"stop":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/StopSequence"}]},"stream":{"type":"boolean"},"temperature":{"type":["number","null"],"format":"double"},"tool_choice":{},"tools":{"type":["array","null"],"items":{}},"top_p":{"type":["number","null"],"format":"double"},"user":{"type":["string","null"]}}}],"description":"OpenAI-compatible chat completion request.\nUses `deny_unknown_fields = false` (serde default) so that SDK-specific\nfields like `stream_options`, `logprobs`, `top_logprobs`, `logit_bias`,\n`parallel_tool_calls`, etc. are silently accepted without breaking."},"ChatCompletionResponse":{"type":"object","required":["id","object","created","model","choices"],"properties":{"choices":{"type":"array","items":{"$ref":"#/components/schemas/ChatCompletionChoice"}},"created":{"type":"integer","format":"int64"},"id":{"type":"string"},"model":{"type":"string"},"object":{"type":"string"},"usage":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/UsageInfo"}]}}},"ChatMessage":{"type":"object","required":["role"],"properties":{"content":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MessageContent"}]},"name":{"type":["string","null"]},"role":{"type":"string"},"tool_call_id":{"type":["string","null"]},"tool_calls":{"type":["array","null"],"items":{}}}},"ChatReadinessResponse":{"type":"object","description":"What still has to be true before an AI chat can run a turn in this project.\n\nThe three gates are independent and fail for different reasons with different\nfixes, so they are reported separately rather than collapsed into one boolean:\nan instance admin configures a provider (instance-wide), while the two toggles\nare per-project. Collapsing them would leave the user with \"AI unavailable\"\nand no idea which of three places to go.","required":["ai_configured","chat_enabled","write_actions_enabled"],"properties":{"ai_configured":{"type":"boolean","description":"An AI provider is configured on this instance. Fixed in\nSettings → AI Providers; instance-wide, not per project."},"chat_enabled":{"type":"boolean","description":"The per-project read-only chat toggle is on (the default)."},"write_actions_enabled":{"type":"boolean","description":"The per-project write-actions opt-in is on. Required for any flow where\nthe assistant *proposes* changes; irrelevant for read-only questions."}}},"ChildBackupEntryResponse":{"type":"object","description":"A single child backup entry in the `GET /backups/{id}/children` response.\n\nEach entry corresponds to one `external_service_backups` row joined with\n`external_services`, providing service metadata without a second request.","required":["id","service_id","service_name","service_type","state","backup_type","started_at","s3_location","compression_type"],"properties":{"backup_type":{"type":"string","description":"Backup variant (e.g. \"full\", \"incremental\")."},"compression_type":{"type":"string","description":"Compression algorithm used (e.g. \"gzip\", \"lz4\")."},"error_message":{"type":["string","null"],"description":"Engine-reported error message when `state = \"failed\"`."},"finished_at":{"type":["string","null"],"description":"When the child backup finished, if known.","example":"2025-01-15T14:35:00.456Z"},"id":{"type":"integer","format":"int32","description":"Row ID from `external_service_backups`."},"s3_location":{"type":"string","description":"Object key or `s3://` URL where the backup data lives."},"service_id":{"type":"integer","format":"int32","description":"FK to `external_services.id`."},"service_name":{"type":"string","description":"Human-readable name of the external service (e.g. \"redis-prod\")."},"service_type":{"type":"string","description":"Service type string (e.g. \"postgres\", \"redis\", \"mongodb\", \"s3\").","example":"postgres"},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size of the child backup in bytes, if available."},"started_at":{"type":"string","description":"When the child backup started (RFC 3339).","example":"2025-01-15T14:30:00.123Z"},"state":{"type":"string","description":"Current state: \"pending\" | \"running\" | \"completed\" | \"failed\"."}}},"ChildBackupListResponse":{"type":"object","description":"Response body for `GET /backups/{id}/children`.\n\nReturns an empty `children` list (not 404) when the parent backup has no\nchild records (e.g. control-plane backups).","required":["children"],"properties":{"children":{"type":"array","items":{"$ref":"#/components/schemas/ChildBackupEntryResponse"},"description":"Zero or more child backup entries ordered by `external_service_backups.id` ASC."}}},"CleanupExpiredBackupsRequest":{"type":"object","properties":{"expected_backup_ids":{"type":["array","null"],"items":{"type":"string"},"description":"Exact candidates returned by the dry run. Execution fails if the\nretention selection has changed since preview."}}},"CliDeviceApproveRequest":{"type":"object","required":["user_code"],"properties":{"user_code":{"type":"string"}}},"CliDeviceApproveResponse":{"type":"object","required":["user_code","status"],"properties":{"status":{"type":"string"},"user_code":{"type":"string"}}},"CliDeviceLookupResponse":{"type":"object","required":["user_code","status","expires_at"],"properties":{"client_name":{"type":["string","null"]},"expires_at":{"type":"string","format":"date-time"},"requested_ip":{"type":["string","null"]},"status":{"type":"string","description":"`pending` | `approved` | `denied` | `expired`."},"user_code":{"type":"string"}}},"CliDevicePollRequest":{"type":"object","required":["device_code"],"properties":{"device_code":{"type":"string"}}},"CliDevicePollResponse":{"oneOf":[{"type":"object","description":"Still waiting on the user to approve in the browser.","required":["status"],"properties":{"status":{"type":"string","enum":["authorization_pending"]}}},{"type":"object","description":"CLI is polling faster than the server-suggested interval.","required":["status"],"properties":{"status":{"type":"string","enum":["slow_down"]}}},{"type":"object","description":"User denied the request in the browser.","required":["status"],"properties":{"status":{"type":"string","enum":["access_denied"]}}},{"type":"object","description":"The session has expired without approval.","required":["status"],"properties":{"status":{"type":"string","enum":["expired_token"]}}},{"type":"object","description":"The session was approved; this is the only response that carries\nthe API key. The key is returned exactly once and then cleared\nfrom the session row.","required":["user_id","email","role","api_key","key_prefix","status"],"properties":{"api_key":{"type":"string"},"email":{"type":"string"},"expires_at":{"type":["string","null"],"format":"date-time"},"key_prefix":{"type":"string"},"role":{"type":"string"},"status":{"type":"string","enum":["approved"]},"user_id":{"type":"integer","format":"int32"}}}]},"CliDeviceStartRequest":{"type":"object","properties":{"client_name":{"type":["string","null"],"description":"Friendly hostname / client identifier shown in the browser approval\nscreen. Sanitized before display.","example":"dviejo-mac.local"}}},"CliDeviceStartResponse":{"type":"object","required":["device_code","user_code","verification_uri","verification_uri_complete","expires_in","interval"],"properties":{"device_code":{"type":"string","description":"Opaque secret the CLI polls with. Never display to a human."},"expires_in":{"type":"integer","format":"int64","description":"Seconds until the device_code expires."},"interval":{"type":"integer","format":"int64","description":"Suggested polling interval, in seconds."},"user_code":{"type":"string","description":"Short human-readable code the user types into the browser.","example":"ABCD-1234"},"verification_uri":{"type":"string","description":"Base verification URL — the CLI may display this when the\npre-filled URL is too long to be useful.","example":"https://temps.example.com/cli-login"},"verification_uri_complete":{"type":"string","description":"`verification_uri` with `user_code` pre-filled. Open this directly.","example":"https://temps.example.com/cli-login/ABCD-1234"}}},"CliLoginRequest":{"type":"object","required":["username","password"],"properties":{"password":{"type":"string"},"username":{"type":"string"}}},"CloudCapability":{"type":"object","required":["configured","setup_path"],"properties":{"configured":{"type":"boolean"},"reason":{"type":["string","null"]},"setup_path":{"type":"string"}}},"CloudProvider":{"type":"string","description":"Cloud provider detected from node metadata","enum":["aws","gcp","azure","hetzner","digitalocean","other"]},"CloudSettings":{"type":"object","description":"Non-secret managed control-plane settings stored with application settings.","properties":{"backend_url":{"type":"string","description":"HTTPS origin used for enrollment and telemetry mirroring.","default":"https://app.temps.sh"}}},"CloudStatus":{"type":"object","required":["status","status_message","health","health_message","spooled_spans","backend_url"],"properties":{"account_email":{"type":["string","null"]},"backend_url":{"type":"string"},"health":{"type":"string"},"health_message":{"type":"string"},"instance_id":{"type":["string","null"]},"spooled_spans":{"type":"integer","minimum":0},"status":{"type":"string"},"status_message":{"type":"string"}}},"CloudflareConfig":{"type":"object","description":"Configuration for a Cloudflare Email Sending notification provider.\n\nNotifications are delivered through Cloudflare's transactional Email Sending\nAPI. Only the account, token, sender and recipients are configured here —\nsubject and body are derived from each notification.","required":["account_id","api_token","from_address","to_addresses"],"properties":{"account_id":{"type":"string","description":"Cloudflare account id that owns the Email Sending configuration.","example":"023e105f4ecef8ad9ca31a8372d0c353"},"api_token":{"type":"string","description":"Cloudflare API token with the Email Sending permission. Encrypted at\nrest and masked in normal API responses."},"from_address":{"type":"string","description":"Verified sender address (must belong to a domain enabled for Cloudflare\nEmail Sending).","example":"welcome@infracf.example.com"},"from_name":{"type":["string","null"],"description":"Optional human-friendly sender name shown in the recipient's inbox."},"to_addresses":{"type":"array","items":{"type":"string"},"description":"Recipients that should receive the notification."}}},"ClusterCapacity":{"type":"object","description":"Total cluster capacity (sum of node allocatable resources)","required":["node_count","cpu_millis","memory_mb"],"properties":{"cpu_millis":{"type":"integer","format":"int64","description":"Total allocatable CPU in millicores"},"memory_mb":{"type":"integer","format":"int64","description":"Total allocatable memory in MB"},"node_count":{"type":"integer","description":"Number of nodes","minimum":0}}},"ClusterDnsSettings":{"type":"object","description":"Cluster-DNS resolver settings (ADR-024, experimental beta).\n\nWhen `enabled`, the Temps control plane starts a Hickory DNS resolver and\ninjects it as the first nameserver into every deployed container via\n`HostConfig.Dns` — giving containers the ability to resolve `*.temps.local`\nFQDNs for service-to-service communication. Worker nodes pick this flag up\nfrom the `/api/internal/nodes/{id}/network/peers` wire response and gate\ntheir own per-node resolver the same way.\n\n**Default: `false` (disabled).**\n\nWhy disabled by default: a production incident showed that when the injected\nHickory resolver was slow or transiently unresponsive for a non-`*.temps.local`\n(external) hostname, glibc's resolver cycled through all three nameservers\n(`172.20.0.1`, `1.1.1.1`, `8.8.8.8`) at ~5 s timeout × 2 attempts each,\ncausing 22–27 s delays for outbound TCP connections. Disabling the injection\nrestores Docker's embedded DNS as the sole resolver, eliminating that failure\nmode. Operators running single/multi-node installs that depend on\n`*.temps.local` resolution must explicitly opt in by setting `enabled: true`.\n\n`bool` defaults to `false` in Rust and JSON (`#[serde(default)]`), so the\nsafe-off behaviour is automatic for new installs and legacy settings rows.","properties":{"enabled":{"type":"boolean","description":"Master switch. When `false` (default), no custom DNS is injected into\ncontainers — they use Docker's embedded DNS which forwards to the host's\nown `resolv.conf`. When `true`, the control-plane Hickory resolver is\nstarted and its bridge IP is injected as the first nameserver so\n`*.temps.local` FQDNs resolve inside containers.","default":false,"example":false}}},"ClusterHealthReportResponse":{"type":"object","description":"Response body for `GET /external-services/{id}/cluster-health`.","required":["checked_at","monitor_response_ms","members"],"properties":{"checked_at":{"type":"string","description":"ISO-8601 wall-clock when the report was generated.","example":"2025-10-12T12:15:47.609192Z"},"members":{"type":"array","items":{"$ref":"#/components/schemas/ClusterMemberHealthResponse"}},"monitor_error":{"type":["string","null"],"description":"Set when the monitor itself was unreachable. UI shows a banner."},"monitor_response_ms":{"type":"integer","format":"int64","description":"Round-trip to query the monitor (ms)."}}},"ClusterMemberHealthResponse":{"type":"object","description":"One row in the cluster Members table — see `GET /external-services/{id}/cluster-health`.","required":["nodename","nodehost","nodeport","reported_state","goal_state","health","seconds_since_report","candidate_priority","replication_quorum"],"properties":{"candidate_priority":{"type":"integer","format":"int32"},"goal_state":{"type":"string","description":"What the monitor *wants* the node to be. Differs from\n`reported_state` mid-transition (failover, demotion, etc.)."},"health":{"type":"integer","format":"int32","description":"pg_auto_failover liveness signal: `1` healthy, `0` unknown\n(no recent report), `-1` unhealthy."},"nodehost":{"type":"string"},"nodename":{"type":"string"},"nodeport":{"type":"integer","format":"int32"},"replay_lag_ms":{"type":["integer","null"],"format":"int64","description":"`replay_lag` from `pg_stat_replication`, in milliseconds."},"replication_quorum":{"type":"boolean"},"reported_state":{"type":"string","description":"What the node *last told the monitor* it was. Stale during outages."},"seconds_since_report":{"type":"integer","format":"int64","description":"Wall-clock seconds since the node last reported in."},"sync_state":{"type":["string","null"],"description":"`sync` / `quorum` / `async` for secondaries; `null` for the primary."}}},"ClusterMemberRequest":{"type":"object","description":"Request spec for a single cluster member.","required":["role"],"properties":{"node_id":{"type":["integer","null"],"format":"int32","description":"Target worker node ID. Omit or null to run on the control plane."},"role":{"type":"string","description":"Service-type-specific role (e.g., \"monitor\", \"primary\", \"replica\")","example":"primary"}}},"CmdBody":{"type":"object","required":["command"],"properties":{"args":{"type":"array","items":{"type":"string"},"description":"Arguments to pass to the binary. Defaults to empty."},"command":{"type":"string","description":"Binary name (argv[0]) — e.g. `\"ls\"`, `\"node\"`. The SDK sends this\nseparately from `args`."},"cwd":{"type":["string","null"],"description":"Working directory override."},"env":{"type":"object","description":"Extra env vars.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"sudo":{"type":"boolean","description":"When true, the SDK runs the command privileged. We ignore it today\n— the underlying provider always runs as the sandbox's own user."},"wait":{"type":"boolean","description":"When true, the response is an `application/x-ndjson` stream where\nthe first line is the running-command envelope and the second line\nis the finished-command envelope with `exitCode`."}}},"CmdInner":{"type":"object","description":"Inner `command` object — matches the SDK's zod validator exactly.\n`exitCode` is `null` until the command terminates; `startedAt` is Unix\nepoch milliseconds.","required":["id","name","args","cwd","sandboxId","startedAt"],"properties":{"args":{"type":"array","items":{"type":"string"}},"cwd":{"type":"string"},"exitCode":{"type":["integer","null"],"format":"int32"},"id":{"type":"string"},"name":{"type":"string"},"sandboxId":{"type":"string"},"startedAt":{"type":"integer","format":"int64"}}},"CmdKillBody":{"type":"object","description":"SDK-shaped kill body. The SDK sends `{signal: AbortSignal}` but only\nuses the signal for HTTP request abortion client-side; there's no\nsignal name on the wire.","properties":{"force":{"type":"boolean","description":"Optional: when true, SIGKILL instead of SIGTERM."}}},"CmdResponse":{"type":"object","description":"`@vercel/sandbox` envelope: `{ command: {...} }`.","required":["command"],"properties":{"command":{"$ref":"#/components/schemas/CmdInner"}}},"CommitExistsResponse":{"type":"object","required":["exists"],"properties":{"commit":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/CommitInfo","description":"Commit metadata when the requested SHA exists."}]},"commit_sha":{"type":["string","null"]},"exists":{"type":"boolean"}}},"CommitInfo":{"type":"object","required":["sha","message","author","author_email","date"],"properties":{"author":{"type":"string","description":"Author name"},"author_email":{"type":"string","description":"Author email"},"date":{"type":"string","format":"date-time","description":"Commit date in ISO 8601 format","example":"2025-10-12T12:15:47.609192Z"},"message":{"type":"string","description":"Commit message"},"sha":{"type":"string","description":"Commit SHA hash"}}},"CommitListResponse":{"type":"object","required":["commits"],"properties":{"commits":{"type":"array","items":{"$ref":"#/components/schemas/CommitInfo"}}}},"Comparator":{"type":"string","description":"Comparator for static/forecast threshold detectors. Serializes to the\nkeyword forms `gt|gte|lt|lte` (NOT the SQL operators used by\n`temps-monitoring::compare`).","enum":["gt","gte","lt","lte"]},"ComposePublicPort":{"type":"object","description":"A port that should be exposed publicly through the proxy for a compose service.","required":["service","port"],"properties":{"port":{"type":"integer","format":"int32","description":"Container port to expose (e.g. 8123)","minimum":0},"service":{"type":"string","description":"Compose service name (e.g. \"web\", \"clickhouse\")"}}},"ConnectionListQuery":{"type":"object","properties":{"direction":{"type":["string","null"]},"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0},"sort":{"type":["string","null"]}}},"ConnectionListResponse":{"type":"object","required":["connections","total_count","page","per_page"],"properties":{"connections":{"type":"array","items":{"$ref":"#/components/schemas/ConnectionResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"per_page":{"type":"integer","format":"int64","minimum":0},"total_count":{"type":"integer","minimum":0}}},"ConnectionResponse":{"type":"object","required":["id","provider_id","account_name","account_type","is_active","is_expired","syncing","synced_repository_count","health_status","consecutive_health_failures","created_at","updated_at"],"properties":{"account_name":{"type":"string"},"account_type":{"type":"string"},"consecutive_health_failures":{"type":"integer","format":"int32"},"created_at":{"type":"string","format":"date-time"},"health_message":{"type":["string","null"],"description":"Human-readable reason when health_status is \"unhealthy\"; null otherwise."},"health_status":{"type":"string","description":"Current health status: \"healthy\", \"unhealthy\", or \"unknown\"."},"id":{"type":"integer","format":"int32"},"installation_id":{"type":["string","null"]},"is_active":{"type":"boolean"},"is_expired":{"type":"boolean"},"last_health_check_at":{"type":["string","null"],"format":"date-time"},"last_synced_at":{"type":["string","null"],"format":"date-time"},"provider_id":{"type":"integer","format":"int32"},"synced_repository_count":{"type":"integer","format":"int32","description":"Running count of repositories persisted by the current (or most\nrecent) sync. Resets to 0 when a new sync begins; useful for showing\nlive progress on large syncs."},"syncing":{"type":"boolean"},"updated_at":{"type":"string","format":"date-time"},"user_id":{"type":["integer","null"],"format":"int32"}}},"ConnectionTestResult":{"type":"object","description":"Connection test result","required":["success","message"],"properties":{"message":{"type":"string"},"success":{"type":"boolean"}}},"ConsoleEventPayload":{"type":"object","description":"Payload for server-side event ingestion via the console API.\n\nThe app backend reads the encrypted `_temps_visitor_id` and `_temps_sid`\ncookie values from the user's request and forwards them here.\nTemps decrypts them server-side to resolve visitor/session identity.","required":["event_name","environment_id","deployment_id"],"properties":{"deployment_id":{"type":"integer","format":"int32","description":"Deployment ID to attribute the event to"},"environment_id":{"type":"integer","format":"int32","description":"Environment ID to attribute the event to"},"event_data":{"description":"Arbitrary JSON event data"},"event_name":{"type":"string","description":"Event name (e.g. \"purchase\", \"signup\", custom event names)"},"request_path":{"type":"string","description":"Page path context (defaults to \"/\")"},"request_query":{"type":"string","description":"Query string context"},"session_id":{"type":["string","null"],"description":"Encrypted `_temps_sid` cookie value from the user's browser"},"visitor_id":{"type":["string","null"],"description":"Encrypted `_temps_visitor_id` cookie value from the user's browser"}}},"ContainerActionResponse":{"type":"object","description":"Response indicating success of container state change","required":["container_id","container_name","action","status","message"],"properties":{"action":{"type":"string"},"container_id":{"type":"string"},"container_name":{"type":"string"},"message":{"type":"string"},"status":{"type":"string"}}},"ContainerDetailResponse":{"type":"object","description":"Detailed container information with environment variables and metrics","required":["id","container_id","container_name","image_name","status","deployment_id","created_at","deployed_at","container_port","environment_variables"],"properties":{"container_id":{"type":"string"},"container_name":{"type":"string"},"container_port":{"type":"integer","format":"int32","description":"Port inside the container"},"cpu_limit_cores":{"type":["number","null"],"format":"double","description":"CPU limit in whole cores (e.g. 1.0). None when no limit is configured."},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"deployed_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"deployment_id":{"type":"integer","format":"int32"},"environment_variables":{"type":"array","items":{"$ref":"#/components/schemas/EnvVarResponse"},"description":"Environment variables (sensitive values masked)"},"error_message":{"type":["string","null"],"description":"Free-form error string from Docker's container state on exit."},"exit_code":{"type":["integer","null"],"format":"int32","description":"Process exit code reported by Docker. None while still running."},"exit_reason":{"type":["string","null"],"description":"Human-readable reason the container exited."},"finished_at":{"type":["string","null"],"description":"When the container exited (Docker's FinishedAt). None while running.","example":"2025-10-12T12:16:47.609192Z"},"host_port":{"type":["integer","null"],"format":"int32","description":"Port on the host machine"},"id":{"type":"integer","format":"int32"},"image_name":{"type":"string"},"oom_killed":{"type":["boolean","null"],"description":"True when Docker's OOM killer terminated the container."},"ready_at":{"type":["string","null"],"example":"2025-10-12T12:16:47.609192Z"},"resource_limits":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ResourceLimitsResponse","description":"Resource limits"}]},"restart_count":{"type":["integer","null"],"format":"int64","description":"Container restart count from Docker"},"service_name":{"type":["string","null"],"description":"Compose service name (e.g. \"web\", \"redis\"). None for single-container deployments."},"service_url":{"type":["string","null"],"description":"Per-service URL for compose deployments"},"started_at":{"type":["string","null"],"description":"When the container's main process most recently started.","example":"2025-10-12T12:15:50.000000Z"},"status":{"type":"string"}}},"ContainerEnvironmentVariableValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"ContainerInfoResponse":{"type":"object","required":["container_id","container_name","image_name","status","created_at"],"properties":{"container_id":{"type":"string"},"container_name":{"type":"string"},"cpu_limit_cores":{"type":["number","null"],"format":"double","description":"CPU limit in whole cores (e.g. 1.0). None when no limit is configured."},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"error_message":{"type":["string","null"],"description":"Free-form error string from Docker's container state on exit."},"exit_code":{"type":["integer","null"],"format":"int32","description":"Process exit code reported by Docker. None while still running."},"exit_reason":{"type":["string","null"],"description":"Human-readable reason the container exited (e.g. \"OOMKilled\",\n\"Killed by SIGKILL (exit code 137)\", \"Exit code 1\"). None while running."},"finished_at":{"type":["string","null"],"description":"When the container exited (Docker's FinishedAt). None while running.","example":"2025-10-12T12:16:47.609192Z"},"image_name":{"type":"string"},"node_name":{"type":["string","null"],"description":"Node name where this container is running. None for local (single-node) deployments."},"oom_killed":{"type":["boolean","null"],"description":"True when Docker's OOM killer terminated the container."},"restart_count":{"type":["integer","null"],"format":"int64","description":"Container restart count from Docker. The UI shows a chip when this is\n> 0 so a crash loop is visible without opening detail."},"service_name":{"type":["string","null"],"description":"Compose service name (e.g. \"web\", \"redis\"). None for single-container deployments."},"service_url":{"type":["string","null"],"description":"Per-service URL for compose deployments (e.g. \"https://web-myapp.localho.st\")"},"started_at":{"type":["string","null"],"description":"When the container's main process most recently started. The UI uses\nthis for the uptime label so the count resets when a container is\nrestarted in place. None for containers that never started.","example":"2025-10-12T12:15:50.000000Z"},"status":{"type":"string"}}},"ContainerInventoryItem":{"type":"object","description":"A container reported by the agent during heartbeat reconciliation.","required":["container_id","container_name"],"properties":{"container_id":{"type":"string","description":"Docker container ID"},"container_name":{"type":"string","description":"Docker container name"}}},"ContainerListResponse":{"type":"object","required":["containers","total"],"properties":{"containers":{"type":"array","items":{"$ref":"#/components/schemas/ContainerInfoResponse"}},"total":{"type":"integer","minimum":0}}},"ContainerLogSettings":{"type":"object","description":"Docker container log rotation settings\nControls the `--log-opt max-size` and `--log-opt max-file` for containers","properties":{"max_file":{"type":"integer","format":"int32","description":"Maximum number of rotated log files to keep (e.g., 3 means up to 3 x max_size total)","default":3,"example":3,"minimum":0},"max_size":{"type":"string","description":"Maximum size of each log file (e.g., \"50m\", \"100m\", \"1g\")\nDocker default is unlimited; we default to \"50m\" to prevent disk exhaustion","default":"50m","example":"50m"},"service_max_file":{"type":"integer","format":"int32","description":"Maximum rotated log files for external service containers","default":3,"example":3,"minimum":0},"service_max_size":{"type":"string","description":"Maximum size for external service container logs (postgres, redis, etc.)\nDefaults to \"20m\" since services are typically less verbose than app containers","default":"20m","example":"20m"}}},"ContainerLogsQuery":{"type":"object","properties":{"container_name":{"type":["string","null"],"description":"Optional container name to get logs from (if deployment has multiple containers)"},"end_date":{"type":["integer","null"],"format":"int64"},"follow":{"type":"boolean","description":"Follow log output in real-time (default: true for backward compatibility)"},"start_date":{"type":["integer","null"],"format":"int64"},"tail":{"type":["string","null"]},"timestamps":{"type":"boolean","description":"Include timestamps in log output (default: false)"}}},"ContainerMetricHistoryPoint":{"type":"object","description":"One bucketed data point of a container resource metric time series.","required":["time","value"],"properties":{"time":{"type":"string","description":"Bucket timestamp (ISO 8601 with `Z` suffix).","example":"2025-10-12T12:15:00+00:00"},"value":{"type":"number","format":"double","description":"Averaged metric value for the bucket."}}},"ContainerMetricsHistoryQuery":{"type":"object","description":"Query parameters for the container metrics history endpoint.","required":["metric"],"properties":{"metric":{"type":"string","description":"Dotted metric name, e.g. `container.cpu_percent` or\n`container.memory_used_bytes`."},"range":{"type":"string","description":"Time window: `1h`, `6h`, `24h`, or `7d` (defaults to `1h`)."}}},"ContainerMetricsResponse":{"type":"object","description":"Container resource metrics (CPU, memory usage)","required":["container_id","container_name","cpu_percent","memory_bytes","network_rx_bytes","network_tx_bytes","timestamp"],"properties":{"container_id":{"type":"string"},"container_name":{"type":"string"},"cpu_limit_cores":{"type":["number","null"],"format":"double","description":"CPU limit in whole cores (e.g. 1.0). None = no limit."},"cpu_percent":{"type":"number","format":"double","description":"CPU usage as a multi-core percentage (Docker convention: 200 = 2 cores\nfully pinned). Divide by 100 to get cores used."},"memory_bytes":{"type":"integer","format":"int64","description":"Memory usage in bytes","minimum":0},"memory_limit_bytes":{"type":["integer","null"],"format":"int64","description":"Memory limit in bytes (if set)","minimum":0},"memory_percent":{"type":["number","null"],"format":"double","description":"Memory usage percentage (0-100) if limit is set"},"network_rx_bytes":{"type":"integer","format":"int64","description":"Network bytes received","minimum":0},"network_tx_bytes":{"type":"integer","format":"int64","description":"Network bytes transmitted","minimum":0},"timestamp":{"type":"string","description":"Timestamp of metrics collection","example":"2025-10-12T12:15:47.609192Z"}}},"ContainerResponse":{"type":"object","required":["name","container_type","can_contain_containers","can_contain_entities","metadata"],"properties":{"can_contain_containers":{"type":"boolean","description":"Can this container hold other containers?","example":true},"can_contain_entities":{"type":"boolean","description":"Can this container hold entities (tables, collections, etc.)?","example":false},"child_container_type":{"type":["string","null"],"description":"Type of child containers (if can_contain_containers is true)","example":"schema"},"container_type":{"type":"string","description":"Container type (database, schema, keyspace, bucket, etc.)","example":"database"},"entity_count_hint":{"type":["string","null"],"description":"Hint for UI on expected entity count (small = sidebar, large = pagination)","example":"large"},"entity_type_label":{"type":["string","null"],"description":"Label for entity type (if can_contain_entities is true)","example":"table"},"metadata":{"description":"Additional metadata"},"name":{"type":"string","description":"Container name","example":"mydb"}}},"ContainerRuntimeInfo":{"type":"object","description":"Snapshot of a container's lifecycle state from `docker inspect`.\n`restart_count` and `oom_killed` are the load-bearing fields when\ndiagnosing crash loops — the kernel OOM killer never reaches the\napplication's logs, so seeing `oom_killed=true` is the only signal\nthat a memory limit was the cause.","required":["role","container_name","resource_limits"],"properties":{"container_id":{"type":["string","null"],"description":"Container Docker id, when present. None = container does not exist\n(was never created or was removed externally)."},"container_name":{"type":"string","description":"Stable name of the Docker container (e.g. `postgres-mydb`)."},"exit_code":{"type":["integer","null"],"format":"int64","description":"Last container exit code, when known. Non-zero = unclean stop."},"finished_at":{"type":["string","null"],"description":"ISO-8601 timestamp of the most recent termination, when known."},"image":{"type":["string","null"],"description":"Currently-effective Docker image (e.g. `gotempsh/postgres-walg:18-bookworm`)."},"oom_killed":{"type":["boolean","null"],"description":"True when the container's last termination was caused by the\nkernel OOM killer. Set if the user enabled hard memory limits\nand the working set exceeded them."},"resource_limits":{"$ref":"#/components/schemas/ServiceResourceLimits","description":"Currently-applied resource limits read off the container's\n`HostConfig`. Compare this against the user-configured limits to\ndetect drift (an old container that never picked up new caps)."},"restart_count":{"type":["integer","null"],"format":"int64","description":"Total restarts since the container was created. Useful for\ndetecting crash loops — a steady stream means something is killing\nthe container repeatedly (frequently OOM)."},"role":{"type":"string","description":"`service_members.role` for cluster members; \"standalone\" otherwise."},"started_at":{"type":["string","null"],"description":"ISO-8601 timestamp of when the container last started. None when\nit has never started (i.e. created but never run)."},"status":{"type":["string","null"],"description":"Bollard container state (\"running\", \"exited\", \"dead\", etc.). None\nwhen the container does not exist."}}},"ContainerStatsSample":{"type":"object","description":"Live resource usage sample for a single container.\n\n`cpu_percent` is computed by Docker's standard formula:\n ((cpu_delta / system_delta) * online_cpus) * 100\n`memory_percent` is `(memory_usage / memory_limit) * 100` — when no\nmemory limit is set the limit reported by Docker is the host's total\nRAM, so a 5% reading means \"5% of host RAM\", not \"5% of allocated\".","required":["role","container_name"],"properties":{"container_name":{"type":"string"},"cpu_percent":{"type":["number","null"],"format":"double","description":"CPU usage as a percentage. `None` when the container is not running\n(Docker returns no usable counters)."},"memory_limit_bytes":{"type":["integer","null"],"format":"int64","description":"Memory limit in bytes (host RAM if no limit set).","minimum":0},"memory_percent":{"type":["number","null"],"format":"double","description":"Memory usage as a percentage of `memory_limit_bytes`."},"memory_usage_bytes":{"type":["integer","null"],"format":"int64","description":"Resident memory usage in bytes.","minimum":0},"online_cpus":{"type":["integer","null"],"format":"int32","description":"Number of cores Docker observed at sample time. Used by the UI\nto label \"x/y cores\" instead of just a percent.","minimum":0},"role":{"type":"string"}}},"ContentPart":{"type":"object","required":["type"],"properties":{"image_url":{},"text":{"type":["string","null"]},"type":{"type":"string"}}},"ContextLine":{"type":"object","description":"A line in context response","required":["timestamp","level","message","line_offset","is_match"],"properties":{"fields":{},"is_match":{"type":"boolean","description":"Whether this line matched the original search"},"level":{"$ref":"#/components/schemas/LogLevel"},"line_offset":{"type":"integer","format":"int32"},"message":{"type":"string"},"timestamp":{"type":"string"}}},"ContextLogsRequest":{"type":"object","required":["chunk_id","line_offset"],"properties":{"chunk_id":{"type":"string"},"line_offset":{"type":"integer","format":"int32"},"lines":{"type":["integer","null"],"format":"int32","description":"Number of context lines before and after (default: 25)","minimum":0}}},"ContextLogsResponse":{"type":"object","required":["lines","target_index"],"properties":{"lines":{"type":"array","items":{"$ref":"#/components/schemas/ContextLine"}},"target_index":{"type":"integer","minimum":0}}},"ConversationDetailResponse":{"allOf":[{"$ref":"#/components/schemas/ConversationResponse"},{"type":"object","required":["messages"],"properties":{"messages":{"type":"array","items":{"$ref":"#/components/schemas/MessageResponse"},"description":"Turns oldest-first. The `system` seed message is omitted (internal)."}}}]},"ConversationResponse":{"type":"object","required":["public_id","context_type","context_id","status","created_at","last_activity_at"],"properties":{"context_id":{"type":"string"},"context_type":{"type":"string"},"created_at":{"type":"string"},"last_activity_at":{"type":"string"},"public_id":{"type":"string"},"status":{"type":"string"},"title":{"type":["string","null"]}}},"ConversationSummary":{"type":"object","description":"A conversation summary grouping related AI invocations.","required":["conversation_id","message_count","total_input_tokens","total_output_tokens","total_tokens","total_cost_microcents","avg_latency_ms","models_used","first_at","last_at"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"conversation_id":{"type":"string"},"first_at":{"type":"string"},"last_at":{"type":"string"},"message_count":{"type":"integer","format":"int64"},"models_used":{"type":"array","items":{"type":"string"}},"total_cost_microcents":{"type":"integer","format":"int64"},"total_input_tokens":{"type":"integer","format":"int64"},"total_output_tokens":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"ConversationsQueryParams":{"type":"object","properties":{"from":{"type":["string","null"],"description":"ISO 8601 start time (defaults to 24h ago)"},"limit":{"type":["integer","null"],"format":"int64","description":"Max results (defaults to 50, max 100)","minimum":0},"model":{"type":["string","null"],"description":"Filter by model name"},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"to":{"type":["string","null"],"description":"ISO 8601 end time (defaults to now)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"CopyBlobRequest":{"type":"object","description":"Request to copy a blob","required":["fromUrl","toPathname"],"properties":{"fromUrl":{"type":"string","description":"Source blob URL or pathname","example":"/api/blob/10/images/avatar.png"},"projectId":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1},"toPathname":{"type":"string","description":"Destination pathname","example":"images/avatar-copy.png"}}},"CostAnalysis":{"type":"object","description":"Full cluster cost + rightsizing analysis attached to an import plan.","required":["nodes","capacity","requested","usage_source","overprovisioning","recommendation","notes"],"properties":{"actual_usage":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ResourceFootprint","description":"Measured usage from the metrics API (`metrics.k8s.io`).\n`None` when metrics-server is not installed."}]},"capacity":{"$ref":"#/components/schemas/ClusterCapacity","description":"Total cluster capacity (sum of node allocatable resources)"},"control_plane_monthly_usd":{"type":["number","null"],"format":"double","description":"Managed control-plane fee included in `current_monthly_usd` (EKS/GKE\ncharge ~$73/mo per cluster). `None` when not applicable/unknown."},"current_monthly_usd":{"type":["number","null"],"format":"double","description":"Estimated total infrastructure cost per month in USD (compute nodes +\ncontrol-plane fee). `None` when no node could be priced."},"nodes":{"type":"array","items":{"$ref":"#/components/schemas/NodeCostInfo"},"description":"Per-node inventory with price estimates where the instance type is known"},"notes":{"type":"array","items":{"type":"string"},"description":"Honesty notes: what could not be measured, which numbers are\nestimates, and any assumptions made. Always shown to the user."},"overprovisioning":{"$ref":"#/components/schemas/OverprovisioningAssessment","description":"Requests-vs-capacity-vs-usage assessment"},"provider":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/CloudProvider","description":"Detected cloud provider (from node `providerID` prefixes)"}]},"recommendation":{"$ref":"#/components/schemas/TargetRecommendation","description":"The temps/Hetzner target sizing and savings estimate"},"requested":{"$ref":"#/components/schemas/ResourceFootprint","description":"Sum of pod resource *requests* across running pods — what the\nscheduler has reserved, i.e. what the cluster is sized for."},"usage_source":{"$ref":"#/components/schemas/UsageSource","description":"How the usage numbers were obtained (drives UI wording)"}}},"CreateAlertRuleRequest":{"type":"object","required":["name","trigger_type"],"properties":{"cooldown_minutes":{"type":"integer","format":"int32","description":"Minimum minutes between notifications for same rule+group"},"enabled":{"type":"boolean"},"environment_filter":{"type":["integer","null"],"format":"int32","description":"Optional environment ID to filter alerts"},"error_level_filter":{"type":["string","null"],"description":"Optional error type/level filter"},"name":{"type":"string"},"notification_priority":{"type":"string","description":"Notification priority: Low, Normal, High, Critical"},"trigger_config":{"description":"Trigger-specific configuration (e.g., {\"count\": 100, \"window_minutes\": 60} for frequency)"},"trigger_type":{"type":"string","description":"Trigger type: new_issue, regression, frequency, new_user, user_count, status_change"}}},"CreateApiKeyRequest":{"type":"object","required":["name","role_type"],"properties":{"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"},"example":["projects:read","deployments:read"]},"role_type":{"type":"string","example":"admin"}}},"CreateApiKeyResponse":{"type":"object","required":["id","name","key_prefix","role_type","api_key","created_at"],"properties":{"api_key":{"type":"string"},"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00Z"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"id":{"type":"integer","format":"int32"},"key_prefix":{"type":"string"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"}},"role_type":{"type":"string"}}},"CreateBackupScheduleRequest":{"type":"object","required":["name","backup_type","retention_period","schedule_expression","enabled","tags"],"properties":{"backup_type":{"type":"string"},"description":{"type":["string","null"]},"enabled":{"type":"boolean"},"include_control_plane":{"type":["boolean","null"],"description":"When `true` (default), every run also produces a `control_plane`\nbackup of Temps's own database. Operators who use Temps purely as\na backup orchestrator for external DBs can set this to `false` to\nkeep the run history focused on those services."},"max_runtime_secs":{"type":["integer","null"],"format":"int64","description":"Optional wall-clock timeout override for jobs created by this schedule\n(seconds). When set, overrides the engine-family default. `null` means\n\"use engine default.\" The per-job `max_runtime_secs` in\n`EnqueueJobParams` can still override this for ad-hoc triggers."},"name":{"type":"string"},"retention_period":{"type":"integer","format":"int32"},"s3_source_id":{"type":["integer","null"],"format":"int32","description":"Optional S3 source. If omitted, the current default S3 source is used."},"schedule_expression":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"target_all_services":{"type":["boolean","null"],"description":"When `true` (default), the schedule backs up every external service\non the host — including databases created in the future. When\n`false`, the schedule backs up only the services explicitly attached\nvia `POST /backups/schedules/{id}/services`. Omit to use the default."}}},"CreateBitbucketRequest":{"type":"object","required":["name","auth"],"properties":{"auth":{"$ref":"#/components/schemas/BitbucketAuthInput","description":"Authentication credentials — either an access token or an app password."},"name":{"type":"string","description":"Display name for this provider."}}},"CreateCloudflareProviderRequest":{"type":"object","required":["name","config"],"properties":{"config":{"$ref":"#/components/schemas/CloudflareConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":"string"}}},"CreateConversationRequest":{"type":"object","required":["context_type","context_id"],"properties":{"context_id":{"type":"string","description":"The entity id (ints stringified)."},"context_type":{"type":"string","description":"e.g. `\"deployment\"`."}}},"CreateDSNRequest":{"type":"object","properties":{"base_url":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"name":{"type":["string","null"]}}},"CreateDashboardRequest":{"type":"object","required":["project_id","name","layout"],"properties":{"layout":{"$ref":"#/components/schemas/DashboardLayout"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"}}},"CreateDeploymentTokenRequest":{"type":"object","required":["name"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment ID - if set, token is scoped to a specific deployment"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment ID - if not set, token applies to all environments"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"},"description":"List of permissions (e.g., [\"visitors:enrich\", \"emails:send\"])\nIf not provided, defaults to full access","example":["visitors:enrich","emails:send"]}}},"CreateDeploymentTokenResponse":{"type":"object","required":["id","project_id","name","token_prefix","token","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00Z"},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"}},"project_id":{"type":"integer","format":"int32"},"token":{"type":"string","description":"The full token value - only returned on creation"},"token_prefix":{"type":"string"}}},"CreateDnsProviderRequest":{"type":"object","description":"Request to create a new DNS provider","required":["name","provider_type","credentials"],"properties":{"credentials":{"$ref":"#/components/schemas/DnsProviderCredentials","description":"Provider credentials"},"description":{"type":["string","null"],"description":"Optional description"},"name":{"type":"string","description":"User-friendly name","example":"My Cloudflare"},"provider_type":{"$ref":"#/components/schemas/DnsProviderType","description":"Provider type"}}},"CreateDomainRequest":{"type":"object","required":["domain"],"properties":{"challenge_type":{"type":"string","description":"Challenge type for Let's Encrypt validation. Options: \"http-01\" (default) or \"dns-01\""},"domain":{"type":"string"}}},"CreateEmailDomainRequest":{"type":"object","required":["provider_id","domain"],"properties":{"domain":{"type":"string","description":"Domain name (e.g., \"updates.example.com\")","example":"updates.example.com"},"provider_id":{"type":"integer","format":"int32","description":"Provider ID to use for this domain"}}},"CreateEmailProviderRequest":{"type":"object","required":["name","provider_type","region"],"properties":{"name":{"type":"string","description":"User-friendly name for the provider","example":"My AWS SES"},"provider_type":{"$ref":"#/components/schemas/EmailProviderTypeRoute","description":"Provider type"},"region":{"type":"string","description":"Cloud region. For SMTP this is informational only — the host/port carry the real routing.","example":"us-east-1"},"scaleway_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ScalewayCredentialsRequest","description":"Scaleway credentials (required if provider_type is scaleway)"}]},"ses_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SesCredentialsRequest","description":"AWS SES credentials (required if provider_type is ses)"}]},"smtp_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SmtpCredentialsRequest","description":"Generic SMTP credentials (required if provider_type is smtp). Use when\nyou only have SMTP creds and want to import an already-set-up domain."}]},"sns_topic_arn":{"type":["string","null"],"description":"Exact SNS topic allowed to deliver SES events for this provider."}}},"CreateEnvironmentRequest":{"type":"object","required":["name","branch"],"properties":{"branch":{"type":"string"},"name":{"type":"string"},"set_as_preview":{"type":"boolean","description":"If true, set this environment as the preview environment for the project"}}},"CreateEnvironmentVariableRequest":{"type":"object","required":["key","value","environment_ids"],"properties":{"environment_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"include_in_preview":{"type":"boolean","description":"Include this environment variable in preview environments (default: true)"},"is_secret":{"type":"boolean","description":"When true the variable is treated as write-only: never returned in\nplaintext from the API, masked in the UI, and updates that omit the\nvalue preserve the existing ciphertext. The flag is one-way — secret\nvars cannot be demoted back to regular vars."},"key":{"type":"string"},"value":{"type":"string"}}},"CreateExternalServiceRequest":{"type":"object","required":["name","service_type","parameters"],"properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/ClusterMemberRequest"},"description":"Cluster member specifications. Required when topology is \"cluster\"."},"name":{"type":"string"},"node_id":{"type":["integer","null"],"format":"int32","description":"Target node ID for the service. Omit or null to run on the control plane."},"parameters":{"type":"object","additionalProperties":{},"propertyNames":{"type":"string"}},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute"},"topology":{"type":"string","description":"Service topology: \"standalone\" (default) or \"cluster\" (HA multi-member).","example":"standalone"},"version":{"type":["string","null"]}}},"CreateFlagRequest":{"type":"object","required":["key","value_type","default_value"],"properties":{"client_visible":{"type":"boolean","description":"Whether the flag may be exposed on the unauthenticated same-origin\nevaluation endpoint. Defaults to `false`: flags are server-only unless\nexplicitly opted in, because targeting rules can encode business logic."},"default_value":{"description":"Served whenever evaluation cannot do better. Must match `value_type`.\n\nLeft unannotated so utoipa emits a free-form schema: a bool flag's\ndefault is `false`, not an object, and `value_type = Object` would tell\nevery generated client otherwise."},"description":{"type":["string","null"]},"key":{"type":"string","description":"Stable key used in application code. Immutable after create.","example":"checkout.v2"},"value_type":{"$ref":"#/components/schemas/FlagValueType","description":"Fixed at create: retyping would invalidate every stored value and every\ncall site."}}},"CreateFunnelRequest":{"type":"object","required":["name","steps"],"properties":{"description":{"type":["string","null"]},"name":{"type":"string"},"steps":{"type":"array","items":{"$ref":"#/components/schemas/CreateFunnelStep"}}}},"CreateFunnelResponse":{"type":"object","required":["funnel_id","message"],"properties":{"funnel_id":{"type":"integer","format":"int32"},"message":{"type":"string"}}},"CreateFunnelStep":{"type":"object","required":["event_name"],"properties":{"event_filter":{"type":"array","items":{"$ref":"#/components/schemas/SmartFilter"}},"event_name":{"type":"string"}}},"CreateGenericRequest":{"type":"object","required":["name","clone_url"],"properties":{"base_url":{"type":["string","null"],"description":"Optional base URL of the git host for display purposes (no API is called)."},"clone_url":{"type":"string","description":"HTTPS clone URL for the repository, e.g. `https://git.example.com/org/repo.git`."},"name":{"type":"string","description":"Display name for this provider."},"token":{"type":["string","null"],"description":"Access token or password. Omit (or set to `null`) for public repositories."},"token_username":{"type":["string","null"],"description":"HTTP Basic username used with the token. Defaults to `x-access-token` when\nabsent or empty. Ignored for public (unauthenticated) repositories."}}},"CreateGitHubPATRequest":{"type":"object","required":["name","token"],"properties":{"name":{"type":"string"},"token":{"type":"string"}}},"CreateGitLabOAuthRequest":{"type":"object","required":["name","client_id","client_secret","redirect_uri"],"properties":{"base_url":{"type":["string","null"]},"client_id":{"type":"string"},"client_secret":{"type":"string"},"name":{"type":"string"},"redirect_uri":{"type":"string"}}},"CreateGitLabPATRequest":{"type":"object","required":["name","token"],"properties":{"base_url":{"type":["string","null"]},"name":{"type":"string"},"token":{"type":"string"}}},"CreateGiteaPATRequest":{"type":"object","required":["name","token","base_url"],"properties":{"base_url":{"type":"string","description":"HTTPS base URL of the Gitea instance, e.g. `https://git.example.com`."},"name":{"type":"string","description":"Display name for this provider."},"token":{"type":"string","description":"Personal access token issued by the Gitea instance."}}},"CreateIncidentRequest":{"type":"object","required":["title","severity"],"properties":{"description":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"monitor_id":{"type":["integer","null"],"format":"int32"},"severity":{"type":"string"},"title":{"type":"string"}}},"CreateIntegrationBody":{"type":"object","required":["provider","signing_secret"],"properties":{"provider":{"type":"string","description":"Registered provider name, e.g. \"stripe\"."},"signing_secret":{"type":"string","description":"Signing secret from the provider's dashboard."}}},"CreateIpAccessControlRequest":{"type":"object","description":"Request to create an IP access control rule","required":["ip_address","action"],"properties":{"action":{"type":"string","description":"Action to take: \"block\" or \"allow\"","example":"block"},"ip_address":{"type":"string","description":"IP address in CIDR notation (e.g., \"192.168.1.1\" or \"10.0.0.0/24\")","example":"192.168.1.100"},"reason":{"type":["string","null"],"description":"Optional reason for the action","example":"Malicious activity detected"}}},"CreateMcpRequest":{"type":"object","required":["slug","name","config"],"properties":{"config":{"type":"object"},"description":{"type":["string","null"]},"name":{"type":"string"},"slug":{"type":"string"}}},"CreateMetricAlertRequest":{"type":"object","required":["project_id","name","metric_name","aggregation","detection_config","window_secs","for_duration_secs","severity","enabled"],"properties":{"aggregation":{"type":"string","description":"One of `avg|sum|min|max|count|rate|p50|p90|p95|p99`."},"detection_config":{"$ref":"#/components/schemas/DetectionConfig","description":"The detector: a discriminated union keyed by `kind`. Today only\n`{ \"kind\": \"static\", \"comparator\": \"gt\", \"threshold\": 500 }` is evaluable."},"dynamic_alerts":{"type":"boolean","description":"When true (and `group_by` is set) fire one independent alarm per breaching\nseries. Static detectors only. Default false."},"enabled":{"type":"boolean"},"for_duration_secs":{"type":"integer","format":"int32"},"group_by":{"type":"array","items":{"type":"string"},"description":"Label keys to break the metric down by, e.g. `[\"endpoint\",\"region\"]`. Empty\n(the default) = one aggregate stream. Max 2 keys; keys must match\n`[a-zA-Z0-9_.:-]`."},"grouped_notification_threshold":{"type":"integer","format":"int32","description":"When more than this many series transition to firing in the same tick, only\nthe first gets the expensive chart/AI enrichment. Range 1–1000, default 5."},"label_filters":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"AND-combined label equality filters: `[[\"key\",\"value\"],…]`. Empty = no\nfiltering (the default). Max 10 pairs; keys must match `[a-zA-Z0-9_.:-]`;\nvalues capped at 500 characters."},"max_series":{"type":"integer","format":"int32","description":"Cardinality cap for dynamic alerting: at most this many series (top by\n`|value|`). Range 1–100, default 20."},"metric_name":{"type":"string"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"severity":{"type":"string","description":"One of `info|warning|critical`."},"window_secs":{"type":"integer","format":"int32"}}},"CreateMonitorRequest":{"type":"object","required":["name","monitor_type","environment_id"],"properties":{"check_interval_seconds":{"type":["integer","null"],"format":"int32"},"check_path":{"type":["string","null"]},"environment_id":{"type":"integer","format":"int32"},"monitor_type":{"type":"string"},"name":{"type":"string"}}},"CreateNotificationEmailProviderRequest":{"type":"object","required":["name","config"],"properties":{"config":{"$ref":"#/components/schemas/EmailConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":"string"}}},"CreateOidcProviderRequest":{"type":"object","required":["name","issuer_url","client_id","client_secret"],"properties":{"client_id":{"type":"string"},"client_secret":{"type":"string"},"default_role":{"type":"string"},"enabled":{"type":"boolean"},"group_claim":{"type":"string"},"issuer_url":{"type":"string"},"jit_provisioning":{"type":"boolean"},"name":{"type":"string"},"role_claim":{"type":"string"},"scopes":{"type":"string"},"template":{"type":"string"},"trust_idp_email":{"type":"boolean","description":"Defaults false. Set to true only for IdPs where an admin\ncontrols user provisioning (corporate Okta, Azure AD) and\nself-signup of arbitrary emails is not possible — see the\n`trust_idp_email` field on `oidc_providers::Model` for the\nsecurity tradeoff this enables."}}},"CreateOidcRoleMappingRequest":{"type":"object","required":["priority","idp_group","role"],"properties":{"idp_group":{"type":"string"},"priority":{"type":"integer","format":"int32"},"role":{"type":"string"}}},"CreatePlanRequest":{"type":"object","description":"Request to create an import plan","required":["source","workload_id"],"properties":{"credentials":{"$ref":"#/components/schemas/ImportCredentials","description":"Platform credentials (required for cloud platforms like Vercel, Railway)"},"repository_id":{"type":["integer","null"],"format":"int32","description":"Optional repository ID to associate with the import\nIf provided, preset will be detected from the repository"},"source":{"$ref":"#/components/schemas/ImportSource","description":"Source to import from"},"workload_id":{"$ref":"#/components/schemas/WorkloadId","description":"Workload ID to import"}}},"CreatePlanResponse":{"type":"object","description":"Response with created plan","required":["session_id","plan","validation","can_execute"],"properties":{"can_execute":{"type":"boolean","description":"Whether the plan can be executed"},"plan":{"$ref":"#/components/schemas/ImportPlan","description":"Generated import plan"},"session_id":{"type":"string","description":"Session ID for tracking"},"validation":{"$ref":"#/components/schemas/ValidationReport","description":"Validation report"}}},"CreatePrResponse":{"type":"object","required":["run","pr_url","pr_number","branch_name"],"properties":{"branch_name":{"type":"string"},"pr_number":{"type":"integer","format":"int32"},"pr_url":{"type":"string"},"run":{"$ref":"#/components/schemas/AutofixerRunResponse"}}},"CreateProjectAccessRequest":{"type":"object","required":["team_id","role"],"properties":{"role":{"$ref":"#/components/schemas/TeamRole"},"team_id":{"type":"integer","format":"int32"}}},"CreateProjectFromTemplateRequest":{"type":"object","description":"Request to create a project from a template\n\nSupports two deploy modes:\n * **Fork mode** — when `git_provider_connection_id` is set, the template\n repo is cloned into a new repository under the user's Git account and the\n project tracks that fork (git-push deploys, automatic deploy on push).\n * **One-click public-repo mode** — when `git_provider_connection_id` is\n omitted, the project deploys directly from the template's public source\n repository (no fork, no Git account required). This is the activation\n path: a brand-new user with no Git provider connected can still deploy a\n demo in one click. `repository_name` / `repository_owner` are ignored in\n this mode, and automatic-deploy-on-push is unavailable (there is no fork\n to receive webhooks).","required":["template_slug","project_name"],"properties":{"automatic_deploy":{"type":"boolean","description":"Enable automatic deployment on push (defaults to true). Only honoured in\nfork mode; public-repo deploys cannot receive push webhooks."},"environment_variables":{"type":"array","items":{"$ref":"#/components/schemas/EnvVarInput"},"description":"Environment variables to set (key-value pairs)"},"git_provider_connection_id":{"type":["integer","null"],"format":"int32","description":"Git provider connection ID. When omitted, the project deploys directly\nfrom the template's public source repository instead of forking it."},"private":{"type":"boolean","description":"Whether to make the repository private (defaults to true)"},"project_name":{"type":"string","description":"Name for the new project"},"repository_name":{"type":["string","null"],"description":"Name for the new repository to create. Required in fork mode; ignored in\none-click public-repo mode."},"repository_owner":{"type":["string","null"],"description":"Owner/organization for the new repository (defaults to authenticated user)"},"storage_service_ids":{"type":"array","items":{"type":"integer","format":"int32"},"description":"External storage service IDs to attach to the project"},"template_slug":{"type":"string","description":"Template slug to use as the base"}}},"CreateProjectFromTemplateResponse":{"type":"object","description":"Response after creating a project from template","required":["project_id","project_slug","project_name","repository_url","template_slug","message"],"properties":{"message":{"type":"string","description":"Message with additional info"},"project_id":{"type":"integer","format":"int32","description":"ID of the created project"},"project_name":{"type":"string","description":"Name of the created project"},"project_slug":{"type":"string","description":"Slug of the created project"},"repository_url":{"type":"string","description":"URL of the created repository"},"template_slug":{"type":"string","description":"Template that was used"}}},"CreateProjectRequest":{"type":"object","required":["name","directory","main_branch","preset","storage_service_ids"],"properties":{"automatic_deploy":{"type":["boolean","null"]},"build_command":{"type":["string","null"]},"custom_domain":{"type":["string","null"]},"directory":{"type":"string"},"environment_variables":{"type":["array","null"],"items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]}},"exposed_port":{"type":["integer","null"],"format":"int32","description":"Port exposed by the container (fallback when image has no EXPOSE directive)\n\nPriority order for port resolution:\n1. Image EXPOSE directive (auto-detected from built image)\n2. Environment-level exposed_port (overrides this value per environment)\n3. This project-level exposed_port (fallback)\n4. Default: 3000\n\nOnly set this if your image doesn't use EXPOSE directive.","example":8080},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"git_url":{"type":["string","null"]},"install_command":{"type":["string","null"]},"is_on_demand":{"type":["boolean","null"]},"is_public_repo":{"type":["boolean","null"]},"is_web_app":{"type":["boolean","null"]},"main_branch":{"type":"string"},"name":{"type":"string"},"output_dir":{"type":["string","null"]},"performance_metrics_enabled":{"type":"boolean"},"preset":{"type":"string"},"preset_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PresetConfigSchema","description":"Preset-specific configuration\n\nDifferent presets accept different configuration options:\n- **Dockerfile preset**: Accepts `DockerfilePresetConfig` with `dockerfile_path` and `build_context`\n- **Nixpacks preset**: Accepts ordered `providers` (for example `[\"...\", \"python\"]`)\n and optional inline `nixpacksConfig` TOML\n- **Static presets** (Vite, Next.js, etc.): Accept `StaticPresetConfig` with build commands and output dir\n\nExample for Dockerfile preset:\n```json\n{\n \"dockerfilePath\": \"docker/Dockerfile\",\n \"buildContext\": \"./api\"\n}\n```"}]},"project_type":{"type":["string","null"]},"repo_name":{"type":["string","null"]},"repo_owner":{"type":["string","null"]},"source_type":{"$ref":"#/components/schemas/SourceType","description":"Source type for deployments\n\nDetermines how the project is deployed:\n- **git** (default): Traditional Git-based deployments - source code is pulled, built, and deployed\n- **docker_image**: Deploy pre-built Docker images from external registries (DockerHub, GHCR, etc.)\n- **static_files**: Deploy pre-built static files uploaded as tar.gz or zip bundles\n\nFor `docker_image` and `static_files` source types, `repo_name` and `repo_owner` are optional."},"storage_service_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"use_default_wildcard":{"type":["boolean","null"]}}},"CreateProjectSecretRequest":{"type":"object","description":"Request to create a new project secret.\n\nProject secrets are mounted into the container as files under\n`/run/secrets/` (mode 0400, tmpfs) instead of as environment variables.\nValues are always encrypted at rest and never returned in plaintext from\nthe API after create. Distinct from agent secrets (global `/settings/secrets`).","required":["key","value"],"properties":{"environment_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"include_in_preview":{"type":"boolean","description":"Include this secret in preview environments."},"key":{"type":"string","description":"Identifier for the secret. Becomes the filename at `/run/secrets/`.\nMust start with a letter or underscore and contain only A-Z, a-z, 0-9, _."},"value":{"type":"string","description":"Plaintext value, <= 1 MiB."}}},"CreateProviderKeyRequest":{"type":"object","required":["provider","display_name","api_key"],"properties":{"api_key":{"type":"string"},"base_url":{"type":["string","null"]},"default_model":{"type":["string","null"],"description":"Optional model id to pin for this provider (e.g. \"gpt-4o-mini\")."},"display_name":{"type":"string"},"provider":{"type":"string"}}},"CreateProviderRequest":{"type":"object","required":["name","provider_type","config"],"properties":{"config":{},"enabled":{"type":["boolean","null"]},"name":{"type":"string"},"provider_type":{"type":"string"}}},"CreateRouteRequest":{"type":"object","required":["domain","host","port"],"properties":{"domain":{"type":"string"},"host":{"type":"string"},"port":{"type":"integer","format":"int32"},"route_type":{"type":["string","null"],"description":"Route type: \"http\" (default) matches on HTTP Host header,\n\"tls\" matches on TLS SNI hostname for TCP passthrough"}}},"CreateS3SourceRequest":{"type":"object","required":["name","bucket_name","bucket_path","access_key_id","secret_key","region"],"properties":{"access_key_id":{"type":"string"},"bucket_name":{"type":"string"},"bucket_path":{"type":"string"},"endpoint":{"type":["string","null"],"description":"Optional endpoint URL for S3-compatible services like MinIO","example":"http://minio.example.com:9000"},"force_path_style":{"type":["boolean","null"],"description":"Whether to use path-style addressing (default: true)","example":true},"is_default":{"type":["boolean","null"],"description":"When true, make this the default source (will swap out any existing default).\nThe very first S3 source is always created as default regardless of this flag.","example":false},"name":{"type":"string"},"region":{"type":"string"},"secret_key":{"type":"string"}}},"CreateSandboxBody":{"type":"object","properties":{"_runtime":{"type":["string","null"]},"backend":{"type":["string","null"],"description":"Isolation backend: `\"docker\"` (default) or `\"firecracker\"` (ADR-029,\nhardware-virtualized microVM — requires a host provisioned with\n`temps firecracker setup`). Omit for the platform default; existing\nclients are unaffected. Requesting an unavailable backend fails with\n400 rather than silently downgrading isolation."},"cpu_limit":{"type":["number","null"],"format":"double"},"disk_size_mb":{"type":["integer","null"],"format":"int64","description":"Root disk size in MB (Firecracker only; Docker ignores it). Omit for\nthe platform default (1 GiB).","minimum":0},"env":{"type":"object","description":"Extra env vars baked into the container on create.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"image":{"type":["string","null"],"description":"Docker image override. `null` uses the platform default."},"memory_limit_mb":{"type":["integer","null"],"format":"int64","minimum":0},"name":{"type":["string","null"]},"networkPolicy":{},"pids_limit":{"type":["integer","null"],"format":"int64"},"ports":{"type":"array","items":{"type":"integer","format":"int32","minimum":0},"description":"Ports the sandbox will listen on. Each port becomes a `routes[]`\nentry in the create/get response so `@vercel/sandbox`'s\n`sandbox.domain(port)` can resolve it client-side without an\nextra round-trip."},"preview_password":{"type":["string","null"],"description":"Optional preview-URL password. When set, every preview URL served\nfor this sandbox is gated behind a login form. 8–256 characters.\nOmit to leave preview URLs open (the sandbox ID remains the only\ngate). The plaintext is never returned; only the last-4 hint is\nsurfaced in `SandboxResponse.preview_password_hint`."},"projectId":{"type":["string","null"]},"resources":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ResourcesBody","description":"`@vercel/sandbox`'s nested resources object. When present, its\n`memory` / `vcpus` populate `memory_limit_mb` / `cpu_limit` if those\nweren't sent directly."}]},"source":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SourceBody","description":"Optional initial content to seed into the work dir. Clones a\nrepo or extracts a tarball after the sandbox is created."}]},"timeout":{"type":["integer","null"],"format":"int64","description":"Idle timeout as sent by `@vercel/sandbox` (milliseconds). Converted\nto seconds when `timeout_secs` is absent.","minimum":0},"timeout_secs":{"type":["integer","null"],"format":"int64","description":"Idle timeout in seconds (temps-native). Clamped to `[60, 86400]`.","minimum":0}}},"CreateSkillRequest":{"type":"object","required":["slug","name","content"],"properties":{"content":{"type":"string"},"description":{"type":["string","null"]},"name":{"type":"string"},"slug":{"type":"string"}}},"CreateSlackProviderRequest":{"type":"object","required":["name","config"],"properties":{"config":{"$ref":"#/components/schemas/SlackConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":"string"}}},"CreateTeamMemberRequest":{"type":"object","required":["user_id","role"],"properties":{"role":{"$ref":"#/components/schemas/TeamRole"},"user_id":{"type":"integer","format":"int32"}}},"CreateTeamRequest":{"type":"object","required":["name","slug"],"properties":{"description":{"type":["string","null"]},"name":{"type":"string"},"slug":{"type":"string"}}},"CreateUserRequest":{"type":"object","required":["username","roles"],"properties":{"email":{"type":["string","null"]},"must_change_password":{"type":"boolean"},"password":{"type":["string","null"]},"roles":{"type":"array","items":{"type":"string"}},"username":{"type":"string"}}},"CreateWebhookProviderRequest":{"type":"object","required":["name","config"],"properties":{"config":{"$ref":"#/components/schemas/WebhookConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":"string"}}},"CreateWebhookRequestBody":{"type":"object","required":["url","events"],"properties":{"enabled":{"type":["boolean","null"],"description":"Whether the webhook is enabled","default":true},"events":{"type":"array","items":{"type":"string"},"description":"Event types to subscribe to","example":["deployment.created","deployment.succeeded"]},"secret":{"type":["string","null"],"description":"Secret for HMAC signature verification (optional)"},"url":{"type":"string","description":"Target URL for webhook delivery","example":"https://example.com/webhook"}}},"CreatedResource":{"type":"object","description":"Resource created during import (for rollback / audit)","required":["resource_type","resource_id","resource_name"],"properties":{"resource_id":{"type":"integer","format":"int32","description":"Resource ID"},"resource_name":{"type":"string","description":"Resource name"},"resource_type":{"type":"string","description":"Resource type (project, environment, deployment, service, domain, etc.)"}}},"CronExecutionInfo":{"type":"object","required":["id","cron_id","executed_at","url","status_code","headers","response_time_ms"],"properties":{"cron_id":{"type":"integer","format":"int32"},"error_message":{"type":["string","null"]},"executed_at":{"type":"string"},"headers":{"type":"string"},"id":{"type":"integer","format":"int32"},"response_time_ms":{"type":"integer","format":"int32"},"status_code":{"type":"integer","format":"int32"},"url":{"type":"string"}}},"CronInfo":{"type":"object","required":["id","project_id","environment_id","path","schedule","created_at","updated_at"],"properties":{"created_at":{"type":"string"},"deleted_at":{"type":["string","null"]},"environment_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"next_run":{"type":["string","null"]},"path":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"schedule":{"type":"string"},"updated_at":{"type":"string"}}},"CrossProjectSiblingRef":{"type":"object","description":"A sibling project that shares the same `trace_id`, returned by the\nPhase 1 cross-project banner endpoint.","required":["project_id","project_name","project_slug","first_seen"],"properties":{"first_seen":{"type":"string","format":"date-time","description":"ISO 8601 timestamp (UTC, `Z` suffix) of first span ingest for this\n`(trace_id, project_id)` pair."},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"project_slug":{"type":"string","description":"URL slug used to link into the sibling project's single-project trace view."}}},"CrossProjectTraceResponse":{"type":"object","description":"Response body for `GET /otel/traces/cross-project/{trace_id}`.\n\nAn empty `siblings` vec is the normal single-project case — never 404.","required":["trace_id","siblings"],"properties":{"siblings":{"type":"array","items":{"$ref":"#/components/schemas/CrossProjectSiblingRef"},"description":"Projects other than the caller's that hold spans for this trace,\nordered by `first_seen ASC`."},"trace_id":{"type":"string","description":"The trace_id that was queried (echoed back for client convenience)."}}},"CurrentStatusResponse":{"type":"object","required":["monitor_id","current_status","uptime_percentage"],"properties":{"avg_response_time_ms":{"type":["number","null"],"format":"double"},"current_status":{"type":"string"},"last_check_at":{"type":["string","null"],"format":"date-time"},"monitor_id":{"type":"integer","format":"int32"},"uptime_percentage":{"type":"number","format":"double"}}},"CustomDomainRequest":{"type":"object","required":["domain","environment_id"],"properties":{"branch":{"type":["string","null"]},"domain":{"type":"string"},"environment_id":{"type":"integer","format":"int32"},"redirect_to":{"type":["string","null"]},"service_name":{"type":["string","null"],"description":"Docker Compose service name this domain routes to (only for docker-compose projects)"},"status_code":{"type":["integer","null"],"format":"int32"}}},"CustomDomainResponse":{"type":"object","required":["id","project_id","domain","status","created_at","updated_at"],"properties":{"branch":{"type":["string","null"]},"created_at":{"type":"integer","format":"int64"},"domain":{"type":"string"},"domain_id":{"type":["integer","null"],"format":"int32"},"environment":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DomainEnvironmentResponse"}]},"expiration_time":{"type":["integer","null"],"format":"int64"},"id":{"type":"integer","format":"int32"},"last_renewed":{"type":["integer","null"],"format":"int64"},"message":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"redirect_to":{"type":["string","null"]},"service_name":{"type":["string","null"],"description":"Docker Compose service name this domain routes to"},"status":{"type":"string"},"status_code":{"type":["integer","null"],"format":"int32"},"updated_at":{"type":"integer","format":"int64"}}},"CustomerMovementResponse":{"type":"object","required":["bucket","new_customers","churned_customers"],"properties":{"bucket":{"type":"string","format":"date-time"},"churned_customers":{"type":"integer","format":"int64"},"new_customers":{"type":"integer","format":"int64"}}},"DashboardLayout":{"type":"object","description":"The typed layout persisted (as JSONB) in `metric_dashboards.layout`.","required":["sections"],"properties":{"sections":{"type":"array","items":{"$ref":"#/components/schemas/DashboardSection"},"description":"Ordered sections that make up the dashboard."}}},"DashboardProjectsAnalyticsQuery":{"type":"object","description":"Query parameters for batch dashboard analytics","required":["project_ids","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"project_ids":{"type":"string","description":"Comma-separated list of project IDs"},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"DashboardProjectsAnalyticsResponse":{"type":"object","description":"Batch response for dashboard project analytics","required":["projects"],"properties":{"projects":{"type":"object","description":"Map of project_id -> analytics data","additionalProperties":{"$ref":"#/components/schemas/ProjectDashboardAnalytics"},"propertyNames":{"type":"string"}}}},"DashboardSection":{"type":"object","description":"A titled group of tiles within a dashboard.","required":["id","title","tiles"],"properties":{"id":{"type":"string","description":"Stable client-generated section id."},"tiles":{"type":"array","items":{"$ref":"#/components/schemas/DashboardTile"},"description":"Tiles rendered within this section."},"title":{"type":"string","description":"Section heading."}}},"DashboardTile":{"type":"object","description":"A single metric tile within a dashboard section.","required":["id","metric_name","aggregation"],"properties":{"aggregation":{"type":"string","description":"Aggregation applied per bucket: one of\n`avg|sum|min|max|count|rate|p50|p90|p95|p99`."},"group_by":{"type":"array","items":{"type":"string"},"description":"Label keys to break the metric down by (group-by / multi-series view).\nEmpty = single aggregated series (current behavior). Max 2 keys — more\ndimensions are unreadable in a chart (ADR-026 Phase 2). Each key must\nmatch `[a-zA-Z0-9_.:-]`. Wired directly to `MetricQuery.group_by` by\nthe tile query path (separate frontend task)."},"id":{"type":"string","description":"Stable client-generated tile id (used as a React key / for reordering)."},"label_filters":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"AND-combined label equality filters: `[[\"key\",\"value\"],…]`. Empty = no\nfiltering. Max 10 pairs; keys must match `[a-zA-Z0-9_.:-]`; values\ncapped at 500 characters. Not yet wired into the tile query path\n(Phase 1 ADR-026 — field round-trips and validates; query wiring is\na separate frontend task)."},"metric_name":{"type":"string","description":"The metric name to chart (e.g. `http.server.duration`)."},"title":{"type":["string","null"],"description":"Optional display title; falls back to the metric name in the UI."}}},"DataImplication":{"type":"object","description":"A specific data implication the user needs to understand","required":["severity","message"],"properties":{"message":{"type":"string","description":"Human-readable description of what could happen"},"recommended_action":{"type":["string","null"],"description":"What the user should do about it (if anything)"},"severity":{"$ref":"#/components/schemas/DataImplicationSeverity","description":"Severity of this implication"}}},"DataImplicationSeverity":{"type":"string","description":"Severity of a data implication","enum":["info","warning","data-not-migrated","potential-data-loss"]},"DatabaseMetricsResponse":{"type":"object","description":"Response for the per-database metrics breakdown.","required":["databases"],"properties":{"databases":{"type":"array","items":{"$ref":"#/components/schemas/DatabaseMetricsRow"},"description":"One entry per database, sorted by the first metric descending\n(largest first) so the biggest database leads the table."}}},"DatabaseMetricsRow":{"type":"object","description":"Per-database metric values for a Postgres service.\n\nA Postgres instance can host many databases (some unrelated to this\nservice). The collector records per-`datname` series; this groups the\nlatest value of each requested metric by database so the UI can render a\n\"Databases\" breakdown table instead of one collapsed number.","required":["database","metrics"],"properties":{"database":{"type":"string","description":"Database name (`datname`)."},"metrics":{"type":"object","description":"Latest value of each requested metric for this database\n(e.g. `{\"pg.database_size_bytes\": 7943871, \"pg.cache_hit_ratio\": 0.99}`).","additionalProperties":{"type":"number","format":"double"},"propertyNames":{"type":"string"}}}},"DelRequest":{"type":"object","description":"Request to delete keys","required":["keys"],"properties":{"keys":{"type":"array","items":{"type":"string"},"description":"The key(s) to delete","example":["user:123","user:456"]},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"DelResponse":{"type":"object","description":"Response for delete operation","required":["deleted"],"properties":{"deleted":{"type":"integer","format":"int64","description":"Number of keys deleted","example":2}}},"DeleteBlobRequest":{"type":"object","description":"Request to delete blobs","required":["pathnames"],"properties":{"pathnames":{"type":"array","items":{"type":"string"},"description":"Pathnames to delete (relative to project)","example":["images/avatar.png","documents/file.pdf"]},"projectId":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"DeleteBlobResponse":{"type":"object","description":"Response after deleting blobs","required":["deleted"],"properties":{"deleted":{"type":"integer","format":"int64","description":"Number of blobs deleted","example":2}}},"DeleteResponse":{"type":"object","required":["deleted"],"properties":{"deleted":{"type":"integer","format":"int64","minimum":0}}},"DeployFromImageRequest":{"type":"object","properties":{"external_image_id":{"type":["integer","null"],"format":"int32","description":"External image ID (if already registered). If provided without image_ref,\nthe image reference will be fetched from the registered external image."},"health_check_path":{"type":["string","null"],"description":"Optional HTTP health-check path override (e.g. \"/api/healthz\").\nImage deploys can't read `.temps.yaml`, so this sets the path the deployer\nprobes after the container starts and the path the environment's uptime\nmonitor checks. Must start with '/'. When omitted, defaults to \"/\".","example":"/api/healthz"},"image_ref":{"type":["string","null"],"description":"Docker image reference (e.g., \"ghcr.io/org/app:v1.0\")\nRequired if external_image_id is not provided","example":"ghcr.io/myorg/myapp:v1.0"},"metadata":{"description":"Optional deployment metadata"}}},"DeployFromImageUploadQuery":{"type":"object","description":"Query parameters for deploying from an uploaded image tarball","properties":{"health_check_path":{"type":["string","null"],"description":"Optional HTTP health-check path override (e.g. \"/api/healthz\").\nMust start with '/'. When omitted, defaults to \"/\".","example":"/api/healthz"},"tag":{"type":["string","null"],"description":"Tag to apply to the imported image (e.g., \"myapp:v1.0\")\nIf not provided, a unique tag will be generated","example":"myapp:v1.0"}}},"DeployFromStaticRequest":{"type":"object","required":["static_bundle_id"],"properties":{"health_check_path":{"type":["string","null"],"description":"Optional HTTP health-check path override (e.g. \"/api/healthz\").\nStatic deploys can't read `.temps.yaml`, so this sets the path the deployer\nprobes after the container starts and the path the environment's uptime\nmonitor checks. Must start with '/'. When omitted, defaults to \"/\".","example":"/api/healthz"},"metadata":{"description":"Optional deployment metadata"},"static_bundle_id":{"type":"integer","format":"int32","description":"Static bundle ID (required)"}}},"DeploymentConfig":{"type":"object","description":"Deployment configuration shared between projects and environments\n\nThis configuration can be set at the project level (as defaults) and\noverridden at the environment level for specific deployments.\n\nNote: Environment variables are managed separately and are not part of this config.","properties":{"antiAffinity":{"type":"boolean","description":"Anti-affinity: spread replicas across different nodes.\n\nWhen enabled, the scheduler avoids placing two replicas of the same\nenvironment on the same node. If there are fewer eligible nodes than\nreplicas, remaining replicas wrap around (best-effort spreading).\n\nDefaults to `true` — replicas spread by default."},"automaticDeploy":{"type":["boolean","null"],"description":"Enable automatic deployments on git push.\n`None` = inherit from project config; `Some(true/false)` = explicit override.\nStored as JSONB so absent key → `None` (inherit), never silently defaults to false."},"containerExecEnabled":{"type":"boolean","description":"Enable container exec/shell access (disabled by default for security)"},"cpuLimit":{"type":["integer","null"],"format":"int32","description":"CPU limit in microcores, where 1_000_000 = 1 full CPU core\n(e.g., 2_000_000 = 2 CPUs). NOT millicores. `None` = uncapped."},"cpuRequest":{"type":["integer","null"],"format":"int32","description":"CPU request in microcores, where 1_000_000 = 1 full CPU core\n(e.g., 100_000 = 0.1 CPU, 500_000 = 0.5 CPU, 2_000_000 = 2 CPUs).\nNOT millicores — the deployer formats this as `{n}u` and converts\n`n / 1_000_000` cores into Docker nano_cpus."},"crossArchitectureBuilds":{"type":["boolean","null"],"description":"Build one image per architecture the eligible nodes run.\n\n`None`/`false` (the default) builds exactly once, on the control\nplane's native platform — byte-for-byte the behaviour of a\nsingle-architecture cluster. When enabled and the nodes this\ndeployment could land on span more than one architecture, the build\njob produces one image per architecture; the non-native ones go\nthrough the daemon's `platform` option, which requires QEMU binfmt\nhandlers registered on the control plane.\n\n**Opt-in on purpose.** Cross-architecture builds are emulated and\nsubstantially slower, and deriving them from cluster topology would\nmean a single node joining silently changes build behaviour for every\ndeployment in the cluster. It also keeps the decision on operator\nconfig rather than on a value each node reports about itself.\n\n`Option` so an environment inherits the project's setting\n(`None`) or overrides it, matching `automatic_deploy`."},"exposedPort":{"type":["integer","null"],"format":"int32","description":"Port exposed by the container\nIf not specified, will be auto-detected from Docker image or default to 3000"},"idleTimeoutSeconds":{"type":"integer","format":"int32","description":"Seconds of inactivity before containers are stopped in on-demand mode.\nOnly used when `on_demand` is true. Min: 60, Max: 86400 (24h).\nDefault: 300 (5 minutes)."},"memoryLimit":{"type":["integer","null"],"format":"int32","description":"Memory limit in megabytes. Three-state semantics:\n- `None` → inherit the parent layer (env inherits project, project\n inherits the seeded default); used by the settings UI's \"Use default\".\n- `Some(0)` → explicit **uncapped**: stop inheriting and run with no\n memory limit. This is the deliberate escape hatch for dedicated\n workloads, distinct from `None`.\n- `Some(n)` → hard cap of `n` MB.\n\n`merge`/resolution keep `Some(0)` as a present value (it wins precedence\nover a parent cap), and the deployer collapses it to \"no limit\" before\ntalking to Docker."},"memoryRequest":{"type":["integer","null"],"format":"int32","description":"Memory request in megabytes (e.g., 128 = 128MB)"},"onDemand":{"type":"boolean","description":"Enable on-demand mode (scale-to-zero).\nWhen enabled, containers are stopped after `idle_timeout_seconds` of no traffic\nand automatically started when a new request arrives."},"performanceMetricsEnabled":{"type":"boolean","description":"Enable performance metrics collection (speed insights)"},"replicas":{"type":"integer","format":"int32","description":"Number of replicas/instances to run\nDefaults to 1 replica"},"security":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SecurityConfig","description":"Security configuration (headers, rate limiting, attack mode, etc.)\nThese settings inherit and override from parent level (Environment > Project > Global)"}]},"sessionRecordingEnabled":{"type":"boolean","description":"Enable session recording for analytics"},"targetLabels":{"description":"Label selector for node-based scheduling. Replicas are only deployed to\nnodes whose labels match the selector.\n\nMatching rules:\n- **Same key, array value** → OR: node must match any value\n- **Different keys** → AND: node must satisfy all keys\n\nExample: `{\"region\": [\"us\", \"asia\"], \"gpu\": \"true\"}`\n→ (region=us OR region=asia) AND gpu=true\n\nApplied after `target_nodes` filtering (they stack)."},"targetNodes":{"type":["array","null"],"items":{"type":"integer","format":"int32"},"description":"Optional list of node IDs to deploy to. When set, replicas are distributed\nonly across these nodes (round-robin). When None, the scheduler distributes\nacross all active nodes (or deploys locally if no nodes exist)."},"wakeTimeoutSeconds":{"type":"integer","format":"int32","description":"Max seconds to wait for containers to start when waking from on-demand sleep.\nRequests return 503 if exceeded. Default: 30."}}},"DeploymentConfigSnapshot":{"type":"object","description":"Deployment configuration snapshot for deployments\n\nThis extends DeploymentConfig with environment variables to capture\nthe complete state of a deployment at the time it was created.","properties":{"automaticDeploy":{"type":"boolean","description":"Enable automatic deployments on git push"},"containerExecEnabled":{"type":"boolean","description":"Enable container exec/shell access"},"cpuLimit":{"type":["integer","null"],"format":"int32","description":"CPU limit in millicores"},"cpuRequest":{"type":["integer","null"],"format":"int32","description":"CPU request in millicores"},"environmentVariables":{"type":"object","description":"Environment variables used for this deployment","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"exposedPort":{"type":["integer","null"],"format":"int32","description":"Port exposed by the container"},"memoryLimit":{"type":["integer","null"],"format":"int32","description":"Memory limit in megabytes"},"memoryRequest":{"type":["integer","null"],"format":"int32","description":"Memory request in megabytes"},"performanceMetricsEnabled":{"type":"boolean","description":"Enable performance metrics collection"},"replicas":{"type":"integer","format":"int32","description":"Number of replicas"},"sessionRecordingEnabled":{"type":"boolean","description":"Enable session recording"}}},"DeploymentConfiguration":{"type":"object","description":"Deployment-level configuration","required":["image","strategy","env_vars","ports","volumes","network","resources"],"properties":{"build":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/BuildConfiguration","description":"Build configuration (if building from source)"}]},"command":{"type":["array","null"],"items":{"type":"string"},"description":"Command override"},"entrypoint":{"type":["array","null"],"items":{"type":"string"},"description":"Entrypoint override"},"env_vars":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentVariable"},"description":"Environment variables"},"git":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/GitSourcePlan","description":"Where the application's source code lives, when the source platform\nbuilds from a git repository. Execution uses this to link the temps\nproject to the same repository so the real deployment pipeline can\nclone and build it."}]},"health_check":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/HealthCheckConfiguration","description":"Health check configuration"}]},"image":{"type":"string","description":"Image to deploy"},"network":{"$ref":"#/components/schemas/NetworkConfiguration","description":"Network configuration"},"ports":{"type":"array","items":{"$ref":"#/components/schemas/PortMapping"},"description":"Port mappings"},"resources":{"$ref":"#/components/schemas/ResourceLimits","description":"Resource limits"},"strategy":{"$ref":"#/components/schemas/DeploymentStrategy","description":"Deployment strategy"},"volumes":{"type":"array","items":{"$ref":"#/components/schemas/VolumeMount"},"description":"Volume mounts"},"working_dir":{"type":["string","null"],"description":"Working directory"}}},"DeploymentContainerLogContentResponse":{"type":"object","description":"A single captured container-log dump, including its full text content.","required":["id","container_name","size_bytes","truncated","captured_at","content"],"properties":{"captured_at":{"type":"integer","format":"int64"},"container_name":{"type":"string"},"content":{"type":"string","description":"The captured plain-text log content."},"id":{"type":"integer","format":"int32"},"service_name":{"type":["string","null"]},"size_bytes":{"type":"integer","format":"int64"},"truncated":{"type":"boolean"}}},"DeploymentContainerLogResponse":{"type":"object","description":"Metadata for one captured (historical) container-log dump. Listed on the\ndeployment detail page so a user can pick which past container's logs to read.","required":["id","deployment_id","container_id","container_name","size_bytes","truncated","captured_at"],"properties":{"captured_at":{"type":"integer","format":"int64","description":"Unix epoch milliseconds of when the logs were captured (just before\nteardown). Matches the timestamp convention used by `DeploymentResponse`."},"container_id":{"type":"string"},"container_name":{"type":"string"},"deployment_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"node_id":{"type":["integer","null"],"format":"int32"},"service_name":{"type":["string","null"]},"size_bytes":{"type":"integer","format":"int64"},"truncated":{"type":"boolean"}}},"DeploymentContainerLogsListResponse":{"type":"object","description":"The list of captured container-log dumps for a deployment.","required":["logs"],"properties":{"logs":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentContainerLogResponse"}}}},"DeploymentEnvironmentResponse":{"type":"object","required":["id","name","slug","domains"],"properties":{"domains":{"type":"array","items":{"type":"string"}},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"slug":{"type":"string"}}},"DeploymentJobResponse":{"type":"object","required":["id","deployment_id","job_id","job_type","name","status","created_at","updated_at","log_id"],"properties":{"created_at":{"type":"integer","format":"int64"},"dependencies":{},"deployment_id":{"type":"integer","format":"int32"},"description":{"type":["string","null"]},"error_message":{"type":["string","null"]},"execution_order":{"type":["integer","null"],"format":"int32"},"finished_at":{"type":["integer","null"],"format":"int64"},"id":{"type":"integer","format":"int32"},"job_config":{"description":"Internal workflow configuration is intentionally redacted. It can\ncontain legacy plaintext secrets or encrypted secret envelopes."},"job_id":{"type":"string"},"job_type":{"type":"string"},"log_id":{"type":"string"},"name":{"type":"string"},"outputs":{},"started_at":{"type":["integer","null"],"format":"int64"},"status":{"type":"string"},"updated_at":{"type":"integer","format":"int64"}}},"DeploymentJobsResponse":{"type":"object","required":["jobs","total"],"properties":{"jobs":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentJobResponse"}},"total":{"type":"integer","minimum":0}}},"DeploymentListResponse":{"type":"object","required":["deployments","total","page","per_page"],"properties":{"deployments":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentResponse"}},"page":{"type":"integer","format":"int64"},"per_page":{"type":"integer","format":"int64"},"total":{"type":"integer","format":"int64"}}},"DeploymentMetadata":{"type":"object","description":"Deployment metadata - typed information about the deployment","properties":{"buildDurationMs":{"type":["integer","null"],"format":"int64","description":"Build duration in milliseconds"},"builder":{"type":["string","null"],"description":"Docker builder used (e.g., \"nixpacks\", \"dockerfile\")"},"deploymentDurationMs":{"type":["integer","null"],"format":"int64","description":"Deployment duration in milliseconds"},"deploymentSourceType":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SourceType","description":"Source type for THIS specific deployment (for Manual/flexible projects)\nThis allows Manual projects to have deployments via different methods\n(docker_image, static_files, or git) while keeping per-deployment tracking"}]},"dockerfilePath":{"type":["string","null"],"description":"Dockerfile path if using Dockerfile builder"},"externalImageId":{"type":["integer","null"],"format":"int32","description":"External image ID (reference to external_images table)"},"externalImageRef":{"type":["string","null"],"description":"External Docker image reference (for docker_image source type)\ne.g., \"ghcr.io/org/app:v1.0\" or \"docker.io/myapp:sha-abc123\""},"fileCount":{"type":["integer","null"],"format":"int32","description":"Number of files in the build output"},"gitPushEvent":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/GitPushEvent","description":"Git push event that triggered this deployment (if from webhook)"}]},"healthCheckPath":{"type":["string","null"],"description":"Explicit deploy-time HTTP health-check path override.\nImage/static deploys can't read `.temps.yaml`, so this lets the deploy\nrequest set a custom path (e.g. \"/api/healthz\"). When present it takes\npriority over any `.temps.yaml` `health.path` value. Always starts with '/'."},"imageSizeBytes":{"type":["integer","null"],"format":"int64","description":"Total size of the built image in bytes"},"imageUploadedLocally":{"type":"boolean","description":"Whether the image was uploaded directly (via docker save/load) rather than pulled from registry\nWhen true, the PullExternalImageJob is skipped since the image is already loaded locally"},"isRollback":{"type":"boolean","description":"Whether this is a rollback deployment"},"labels":{"type":"array","items":{"type":"string"},"description":"Custom labels/tags for the deployment"},"rolledBackFromId":{"type":["integer","null"],"format":"int32","description":"ID of the deployment this was rolled back from (if applicable)"},"sourceBundleContentType":{"type":["string","null"],"description":"Uploaded source archive content type."},"sourceBundleId":{"type":["integer","null"],"format":"int32","description":"Uploaded source archive ID. Source archives are extracted before the\nregular preset build pipeline and do not require Git metadata."},"sourceBundlePath":{"type":["string","null"],"description":"Uploaded source archive path in the Temps data directory."},"staticBundleContentType":{"type":["string","null"],"description":"Static bundle content type (for proper extraction: application/gzip or application/zip)"},"staticBundleId":{"type":["integer","null"],"format":"int32","description":"Static bundle ID (reference to static_bundles table, for static_files source type)"},"staticBundlePath":{"type":["string","null"],"description":"Static bundle path in blob storage (for static_files source type)"},"uploadedImageId":{"type":["string","null"],"description":"Docker image ID of the locally uploaded image (sha256:...)\nUsed to verify the image exists before deployment"}}},"DeploymentResponse":{"type":"object","required":["id","project_id","environment_id","environment","status","url","created_at","is_current"],"properties":{"branch":{"type":["string","null"]},"cancelled_reason":{"type":["string","null"]},"commit_author":{"type":["string","null"]},"commit_date":{"type":["integer","null"],"format":"int64"},"commit_hash":{"type":["string","null"]},"commit_message":{"type":["string","null"]},"created_at":{"type":"integer","format":"int64"},"deployment_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DeploymentConfigSnapshot","description":"Deployment configuration snapshot (CPU, memory, replicas, environment variables, etc.)"}]},"environment":{"$ref":"#/components/schemas/DeploymentEnvironmentResponse"},"environment_id":{"type":"integer","format":"int32"},"finished_at":{"type":["integer","null"],"format":"int64"},"id":{"type":"integer","format":"int32"},"is_current":{"type":"boolean"},"metadata":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DeploymentMetadata","description":"Deployment metadata (build info, git event, etc.)"}]},"project_id":{"type":"integer","format":"int32"},"screenshot_location":{"type":["string","null"]},"started_at":{"type":["integer","null"],"format":"int64"},"status":{"type":"string"},"tag":{"type":["string","null"]},"url":{"type":"string"}}},"DeploymentStateResponse":{"type":"object","required":["id","state","message"],"properties":{"id":{"type":"integer","format":"int32"},"message":{"type":"string"},"state":{"type":"string"}}},"DeploymentStrategy":{"type":"string","description":"Deployment strategy","enum":["replace","blue-green","rolling"]},"DeploymentTokenListResponse":{"type":"object","required":["tokens","total"],"properties":{"tokens":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentTokenResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"DeploymentTokenResponse":{"type":"object","required":["id","project_id","name","token_prefix","is_active","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00Z"},"created_by":{"type":["integer","null"],"format":"int32"},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"last_used_at":{"type":["string","null"],"format":"date-time","example":"2024-01-01T00:00:00Z"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"}},"project_id":{"type":"integer","format":"int32"},"token_prefix":{"type":"string"}}},"DetectionConfig":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/StaticParams","description":"v0 (shipping): static threshold comparison of the aggregated value."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["static"]}}}],"description":"v0 (shipping): static threshold comparison of the aggregated value."},{"allOf":[{"$ref":"#/components/schemas/AnomalyParams","description":"Seasonal anomaly band (basic/agile/robust/ewma share this variant — the\nalgorithm is a field, not a new kind). Creation rejected until evaluated."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["anomaly"]}}}],"description":"Seasonal anomaly band (basic/agile/robust/ewma share this variant — the\nalgorithm is a field, not a new kind). Creation rejected until evaluated."},{"allOf":[{"$ref":"#/components/schemas/ForecastParams","description":"Predict a future threshold breach (capacity planning). Stub."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["forecast"]}}}],"description":"Predict a future threshold breach (capacity planning). Stub."},{"allOf":[{"$ref":"#/components/schemas/OutlierParams","description":"Cross-series population outlier (one host misbehaving vs its peers). Stub."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["outlier"]}}}],"description":"Cross-series population outlier (one host misbehaving vs its peers). Stub."},{"allOf":[{"$ref":"#/components/schemas/AutoWatchParams","description":"Watchdog-style self-tuning auto-watch (engine picks bounds). Stub."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["auto_watch"]}}}],"description":"Watchdog-style self-tuning auto-watch (engine picks bounds). Stub."}],"description":"The typed detector definition stored (as jsonb) in\n`metric_alert_rules.detection_config`.\n\nToday only [`DetectionConfig::Static`] is evaluable; the other variants are\nschema-present (so the SDK/UI and storage are already future-shaped) but\nrejected by [`DetectionConfig::validate`] until their evaluator lands. Each is\nthen enabled code-only, with no schema migration."},"DeviceCount":{"type":"object","required":["device_type","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"device_type":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"DigestSections":{"type":"object","description":"Sections that can be included in the weekly digest\nNote: `#[serde(default)]` allows backward compatibility when deserializing\nold data that may have `security` and `resources` fields instead of `projects`","properties":{"deployments":{"type":"boolean","default":true},"errors":{"type":"boolean","default":true},"funnels":{"type":"boolean","default":true},"performance":{"type":"boolean","default":true},"projects":{"type":"boolean","default":true}}},"Direction":{"type":"string","description":"Which side(s) of an anomaly band count as a deviation.","enum":["both","above","below"]},"DisableBlobResponse":{"type":"object","description":"Response after disabling Blob service","required":["success","message"],"properties":{"message":{"type":"string","description":"Human-readable message","example":"Blob service disabled successfully"},"success":{"type":"boolean","description":"Whether the operation succeeded","example":true}}},"DisableKvResponse":{"type":"object","description":"Response after disabling KV service","required":["success","message"],"properties":{"message":{"type":"string","description":"Status message","example":"KV service disabled successfully"},"success":{"type":"boolean","description":"Whether the service was successfully disabled"}}},"DisableMfaRequest":{"type":"object","required":["code"],"properties":{"code":{"type":"string"}}},"DiscoverRequest":{"type":"object","description":"Request to discover workloads","required":["source"],"properties":{"credentials":{"$ref":"#/components/schemas/ImportCredentials","description":"Platform credentials (required for cloud platforms like Vercel, Railway)"},"selector":{"$ref":"#/components/schemas/ImportSelector","description":"Optional selector to filter workloads"},"source":{"$ref":"#/components/schemas/ImportSource","description":"Source to discover from"}}},"DiscoverResponse":{"type":"object","description":"Response with discovered workloads","required":["workloads"],"properties":{"workloads":{"type":"array","items":{"$ref":"#/components/schemas/WorkloadDescriptor"},"description":"Discovered workloads"}}},"DiskInfo":{"type":"object","description":"Disk space information for a single disk/partition","required":["mount_point","total_bytes","used_bytes","available_bytes","usage_percent","file_system"],"properties":{"available_bytes":{"type":"integer","format":"int64","description":"Available space in bytes","minimum":0},"file_system":{"type":"string","description":"File system type (e.g., \"ext4\", \"apfs\")"},"mount_point":{"type":"string","description":"Mount point of the disk"},"total_bytes":{"type":"integer","format":"int64","description":"Total space in bytes","minimum":0},"usage_percent":{"type":"number","format":"double","description":"Usage percentage (0-100)"},"used_bytes":{"type":"integer","format":"int64","description":"Used space in bytes","minimum":0}}},"DiskSpaceAlert":{"type":"object","description":"Alert for a disk that exceeds the threshold","required":["mount_point","usage_percent","threshold_percent","available_bytes","available_human"],"properties":{"available_bytes":{"type":"integer","format":"int64","description":"Available space in bytes","minimum":0},"available_human":{"type":"string","description":"Human-readable available space"},"mount_point":{"type":"string","description":"Mount point of the disk"},"threshold_percent":{"type":"integer","format":"int32","description":"Configured threshold percentage","minimum":0},"usage_percent":{"type":"number","format":"double","description":"Current usage percentage"}}},"DiskSpaceAlertSettings":{"type":"object","description":"Disk space alert settings for monitoring disk usage","properties":{"check_interval_seconds":{"type":"integer","format":"int64","description":"Interval in seconds between disk space checks","default":300,"example":300,"minimum":60},"enabled":{"type":"boolean","description":"Whether disk space alerts are enabled","default":true},"monitor_path":{"type":["string","null"],"description":"Restrict monitoring to the disk backing this path. When unset (the\ndefault), every mounted writable volume is monitored — including\ndedicated volumes such as `/var/lib/docker`.","default":null},"threshold_percent":{"type":"integer","format":"int32","description":"Threshold percentage (0-100) at which to trigger alerts","default":80,"example":80,"maximum":100,"minimum":0}}},"DiskSpaceCheckResult":{"type":"object","description":"Result of a disk space check","required":["checked_at","enabled","threshold_percent","disks","alerts"],"properties":{"alerts":{"type":"array","items":{"$ref":"#/components/schemas/DiskSpaceAlert"},"description":"Disks that meet or exceed the threshold"},"checked_at":{"type":"string","format":"date-time","description":"Timestamp of the check (ISO 8601, UTC)","example":"2026-05-28T12:15:47.609192Z"},"disks":{"type":"array","items":{"$ref":"#/components/schemas/DiskInfo"},"description":"List of all monitored disks"},"enabled":{"type":"boolean","description":"Whether disk space monitoring is enabled in settings"},"threshold_percent":{"type":"integer","format":"int32","description":"Configured alert threshold percentage (0-100)","minimum":0}}},"DnsAckRequest":{"type":"object","required":["applied_generation"],"properties":{"applied_generation":{"type":"integer","format":"int64","description":"Highest generation the agent has actually applied locally."}}},"DnsAckResponse":{"type":"object","required":["node_id","applied_generation","server_generation"],"properties":{"applied_generation":{"type":"integer","format":"int64"},"node_id":{"type":"integer","format":"int32"},"server_generation":{"type":"integer","format":"int64"}}},"DnsChallengeRecordResult":{"type":"object","description":"Result of a single DNS TXT record creation for ACME challenge","required":["name","value","success","message"],"properties":{"message":{"type":"string","description":"Human-readable message about the operation"},"name":{"type":"string","description":"TXT record name (e.g., \"_acme-challenge.example.com\")","example":"_acme-challenge.example.com"},"success":{"type":"boolean","description":"Whether the record was created successfully"},"value":{"type":"string","description":"TXT record value (the ACME challenge token)","example":"abc123..."}}},"DnsChangesResponse":{"type":"object","required":["generation","full_snapshot","records","removed_ids"],"properties":{"full_snapshot":{"type":"boolean","description":"`true` ⇒ replace the local zone with `records`. `false` ⇒ merge\n`records` into the existing zone (and remove `removed_ids`)."},"generation":{"type":"integer","format":"int64","description":"Highest generation included in this response. Agent ACKs this back."},"records":{"type":"array","items":{"$ref":"#/components/schemas/EndpointDto"}},"removed_ids":{"type":"array","items":{"type":"integer","format":"int64"},"description":"IDs the agent should remove from its zone. Always empty in the v1\nprotocol — the resolver reconciles by name on snapshot mode. Kept\nin the wire format so a future tombstone-based protocol doesn't\nrequire a breaking change."}}},"DnsCompletionResponse":{"type":"object","required":["domain","status"],"properties":{"domain":{"type":"string"},"status":{"type":"string"}}},"DnsLookupError":{"type":"object","description":"Error response for DNS lookup failures","required":["error","domain"],"properties":{"domain":{"type":"string","description":"Domain name that failed","example":"nonexistent.com"},"error":{"type":"string","description":"Error message","example":"DNS lookup failed: domain not found"}}},"DnsLookupRequest":{"type":"object","description":"Request to lookup DNS A records for a domain","required":["domain"],"properties":{"domain":{"type":"string","description":"Domain name to lookup","example":"example.com"}}},"DnsLookupResponse":{"type":"object","description":"Response containing DNS A records","required":["domain","records","count","dns_servers"],"properties":{"count":{"type":"integer","description":"Number of records found","example":1,"minimum":0},"dns_servers":{"type":"array","items":{"type":"string"},"description":"DNS servers used for the lookup","example":["8.8.8.8","8.8.4.4"]},"domain":{"type":"string","description":"Domain name that was queried","example":"example.com"},"records":{"type":"array","items":{"type":"string"},"description":"List of A record IP addresses","example":["93.184.216.34"]}}},"DnsProviderCredentials":{"oneOf":[{"type":"object","required":["api_token","type"],"properties":{"account_id":{"type":["string","null"]},"api_token":{"type":"string","example":"your-api-token"},"type":{"type":"string","enum":["cloudflare"]}}},{"type":"object","required":["api_user","api_key","type"],"properties":{"api_key":{"type":"string","example":"your-api-key"},"api_user":{"type":"string","example":"your-username"},"client_ip":{"type":["string","null"]},"sandbox":{"type":"boolean"},"type":{"type":"string","enum":["namecheap"]}}},{"type":"object","required":["access_key_id","secret_access_key","type"],"properties":{"access_key_id":{"type":"string","example":"AKIAIOSFODNN7EXAMPLE"},"region":{"type":["string","null"],"example":"us-east-1"},"secret_access_key":{"type":"string","example":"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"},"session_token":{"type":["string","null"]},"type":{"type":"string","enum":["route53"]}}},{"type":"object","required":["api_token","type"],"properties":{"api_token":{"type":"string","example":"dop_v1_your-token"},"type":{"type":"string","enum":["digitalocean"]}}},{"type":"object","required":["service_account_email","private_key","project_id","type"],"properties":{"private_key":{"type":"string","example":"-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"},"project_id":{"type":"string","example":"my-gcp-project"},"service_account_email":{"type":"string","example":"dns-admin@myproject.iam.gserviceaccount.com"},"type":{"type":"string","enum":["gcp"]}}},{"type":"object","required":["tenant_id","client_id","client_secret","subscription_id","resource_group","type"],"properties":{"client_id":{"type":"string","example":"00000000-0000-0000-0000-000000000000"},"client_secret":{"type":"string"},"resource_group":{"type":"string","example":"my-resource-group"},"subscription_id":{"type":"string","example":"00000000-0000-0000-0000-000000000000"},"tenant_id":{"type":"string","example":"00000000-0000-0000-0000-000000000000"},"type":{"type":"string","enum":["azure"]}}},{"type":"object","description":"Pebble challtestsrv mock DNS (LOCAL DEV/TEST ONLY)","required":["management_url","type"],"properties":{"management_url":{"type":"string","example":"http://localhost:8055"},"type":{"type":"string","enum":["pebble"]}}}],"description":"DNS provider credentials (API-facing)"},"DnsProviderResponse":{"type":"object","description":"DNS provider response","required":["id","name","provider_type","credentials","is_active","flat_hostnames_supported","created_at","updated_at"],"properties":{"created_at":{"type":"string"},"credentials":{"description":"Masked credentials for display"},"description":{"type":["string","null"]},"flat_hostnames_supported":{"type":"boolean","description":"Whether this provider benefits from the flat hostname mode (e.g. Cloudflare\nUniversal SSL). The UI surfaces/recommends the Flat toggle when true."},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"last_error":{"type":["string","null"]},"last_used_at":{"type":["string","null"]},"name":{"type":"string"},"provider_type":{"type":"string"},"updated_at":{"type":"string"}}},"DnsProviderSettings":{"type":"object","properties":{"cloudflare_api_key":{"type":["string","null"],"default":null},"provider":{"type":"string","default":"manual"}}},"DnsProviderSettingsMasked":{"type":"object","description":"DNS provider settings with masked sensitive fields","required":["provider"],"properties":{"cloudflare_api_key":{"type":["string","null"]},"provider":{"type":"string"}}},"DnsProviderType":{"type":"string","description":"Supported DNS provider types","enum":["cloudflare","namecheap","route53","digitalocean","gcp","azure","manual","pebble"]},"DnsRecord":{"type":"object","description":"A DNS record","required":["zone","name","fqdn","content","ttl"],"properties":{"content":{"$ref":"#/components/schemas/DnsRecordContent","description":"Record content"},"fqdn":{"type":"string","description":"Fully qualified domain name","example":"www.example.com"},"id":{"type":["string","null"],"description":"Provider-specific record ID (if exists)","example":"abc123"},"metadata":{"type":"object","description":"Provider-specific metadata","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":"string","description":"Record name (without zone, e.g., \"www\" or \"@\" for root)","example":"www"},"proxied":{"type":"boolean","description":"Whether this record is proxied (Cloudflare-specific)"},"ttl":{"type":"integer","format":"int32","description":"Time to live in seconds","example":300,"minimum":0},"zone":{"type":"string","description":"Zone/domain this record belongs to","example":"example.com"}}},"DnsRecordChange":{"type":"object","description":"A single DNS record change the Cloudflare sync would make.","required":["action","name","record_type","value"],"properties":{"action":{"type":"string","description":"`\"create\"`, `\"update\"`, or `\"delete\"`."},"name":{"type":"string"},"record_type":{"type":"string","description":"Record type, e.g. `\"A\"` or `\"CNAME\"`."},"value":{"type":"string"}}},"DnsRecordContent":{"oneOf":[{"type":"object","description":"A record - IPv4 address (as string, e.g., \"192.0.2.1\")","required":["value","type"],"properties":{"type":{"type":"string","enum":["A"]},"value":{"type":"object","description":"A record - IPv4 address (as string, e.g., \"192.0.2.1\")","required":["address"],"properties":{"address":{"type":"string","example":"192.0.2.1"}}}}},{"type":"object","description":"AAAA record - IPv6 address (as string, e.g., \"2001:db8::1\")","required":["value","type"],"properties":{"type":{"type":"string","enum":["AAAA"]},"value":{"type":"object","description":"AAAA record - IPv6 address (as string, e.g., \"2001:db8::1\")","required":["address"],"properties":{"address":{"type":"string","example":"2001:db8::1"}}}}},{"type":"object","description":"CNAME record - canonical name","required":["value","type"],"properties":{"type":{"type":"string","enum":["CNAME"]},"value":{"type":"object","description":"CNAME record - canonical name","required":["target"],"properties":{"target":{"type":"string"}}}}},{"type":"object","description":"TXT record - text content","required":["value","type"],"properties":{"type":{"type":"string","enum":["TXT"]},"value":{"type":"object","description":"TXT record - text content","required":["content"],"properties":{"content":{"type":"string"}}}}},{"type":"object","description":"MX record - mail exchange","required":["value","type"],"properties":{"type":{"type":"string","enum":["MX"]},"value":{"type":"object","description":"MX record - mail exchange","required":["priority","target"],"properties":{"priority":{"type":"integer","format":"int32","minimum":0},"target":{"type":"string"}}}}},{"type":"object","description":"NS record - nameserver","required":["value","type"],"properties":{"type":{"type":"string","enum":["NS"]},"value":{"type":"object","description":"NS record - nameserver","required":["nameserver"],"properties":{"nameserver":{"type":"string"}}}}},{"type":"object","description":"SRV record - service","required":["value","type"],"properties":{"type":{"type":"string","enum":["SRV"]},"value":{"type":"object","description":"SRV record - service","required":["priority","weight","port","target"],"properties":{"port":{"type":"integer","format":"int32","minimum":0},"priority":{"type":"integer","format":"int32","minimum":0},"target":{"type":"string"},"weight":{"type":"integer","format":"int32","minimum":0}}}}},{"type":"object","description":"CAA record - certification authority authorization","required":["value","type"],"properties":{"type":{"type":"string","enum":["CAA"]},"value":{"type":"object","description":"CAA record - certification authority authorization","required":["flags","tag","value"],"properties":{"flags":{"type":"integer","format":"int32","minimum":0},"tag":{"type":"string"},"value":{"type":"string"}}}}},{"type":"object","description":"PTR record - pointer","required":["value","type"],"properties":{"type":{"type":"string","enum":["PTR"]},"value":{"type":"object","description":"PTR record - pointer","required":["target"],"properties":{"target":{"type":"string"}}}}}],"description":"DNS record content - varies by record type"},"DnsRecordResponse":{"type":"object","required":["record_type","name","value","status"],"properties":{"name":{"type":"string","description":"DNS record name (host)","example":"temps._domainkey.example.com"},"priority":{"type":["integer","null"],"format":"int32","description":"Priority (for MX records)","example":"10","minimum":0},"record_type":{"type":"string","description":"Record type: TXT, CNAME, MX","example":"TXT"},"status":{"$ref":"#/components/schemas/DnsRecordStatusResponse","description":"Verification status: unknown, verified, pending, failed"},"value":{"type":"string","description":"DNS record value","example":"v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3..."}}},"DnsRecordSetupResult":{"type":"object","description":"Result of a single DNS record creation","required":["record_type","name","success","automatic","message"],"properties":{"automatic":{"type":"boolean","description":"Whether the operation was automatic or manual"},"message":{"type":"string","description":"Human-readable message"},"name":{"type":"string","description":"Record name"},"record_type":{"type":"string","description":"Record type (TXT, CNAME, MX)"},"success":{"type":"boolean","description":"Whether the record was created successfully"}}},"DnsRecordStatusResponse":{"type":"string","description":"DNS record verification status","enum":["unknown","verified","pending","failed"]},"DnsZone":{"type":"object","description":"A DNS zone (domain managed by the provider)","required":["id","name","status","nameservers"],"properties":{"id":{"type":"string","description":"Provider-specific zone ID","example":"zone123"},"metadata":{"type":"object","description":"Provider-specific metadata","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":"string","description":"Zone name (domain)","example":"example.com"},"nameservers":{"type":"array","items":{"type":"string"},"description":"Nameservers for this zone"},"status":{"type":"string","description":"Zone status","example":"active"}}},"DockerComposePresetConfig":{"type":"object","description":"Configuration for Docker Compose deployments.","properties":{"composeOverride":{"type":["string","null"],"description":"User-provided docker-compose.override.yml content."},"composePath":{"type":["string","null"],"description":"Path to the Compose file relative to the project directory."},"publicPorts":{"type":"array","items":{"$ref":"#/components/schemas/ComposePublicPort"},"description":"Compose service ports that should be publicly routed."}}},"DockerRegistrySettings":{"type":"object","properties":{"ca_certificate":{"type":["string","null"],"default":null},"enabled":{"type":"boolean","default":false},"password":{"type":["string","null"],"default":null},"registry_url":{"type":["string","null"],"default":null},"tls_verify":{"type":"boolean","default":true},"username":{"type":["string","null"],"default":null}}},"DockerRegistrySettingsMasked":{"type":"object","description":"Docker registry settings with masked sensitive fields","required":["enabled","tls_verify"],"properties":{"ca_certificate":{"type":["string","null"]},"enabled":{"type":"boolean"},"password":{"type":["string","null"]},"registry_url":{"type":["string","null"]},"tls_verify":{"type":"boolean"},"username":{"type":["string","null"]}}},"DockerfilePresetConfig":{"type":"object","description":"Configuration for Dockerfile preset\nAllows customizing the Dockerfile path and build context for Docker-based deployments","properties":{"buildContext":{"type":["string","null"],"description":"Custom build context path (relative to repository root)\nIf not specified, uses the project's directory setting","example":"./api"},"dockerfilePath":{"type":["string","null"],"description":"Custom Dockerfile path (relative to build context)\nIf not specified, defaults to \"Dockerfile\" in the build context","example":"docker/Dockerfile"},"variant":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DockerfileVariant","description":"Catalog variant. Normally omitted; `custom` selects the generated\nDockerfile compatibility preset."}]}}},"DockerfileVariant":{"type":"string","description":"Catalog variant persisted under the canonical Dockerfile preset.\n\nExisting rows predate this discriminator and therefore deserialize as\n[`DockerfileVariant::File`].","enum":["file","custom"]},"DomainAction":{"type":"string","description":"What to do with a domain during migration","enum":["import","skip"]},"DomainChallengeResponse":{"type":"object","required":["domain","txt_records","status"],"properties":{"domain":{"type":"string"},"status":{"type":"string"},"txt_records":{"type":"array","items":{"$ref":"#/components/schemas/TxtRecord"},"description":"Array of TXT records to add to DNS. For wildcards, multiple records are required."}}},"DomainEnvironmentResponse":{"type":"object","required":["id","name","slug"],"properties":{"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"slug":{"type":"string"}}},"DomainError":{"type":"object","required":["message","code"],"properties":{"code":{"type":"string"},"details":{"type":["string","null"]},"message":{"type":"string"}}},"DomainPlan":{"type":"object","description":"Plan for migrating a single custom domain","required":["domain","environment","action","action_description"],"properties":{"action":{"$ref":"#/components/schemas/DomainAction","description":"What to do with this domain"},"action_description":{"type":"string","description":"Human-readable explanation"},"domain":{"type":"string","description":"Full domain name"},"environment":{"type":"string","description":"Which environment to associate with (\"production\")"},"redirect_to":{"type":["string","null"],"description":"Redirect target (if this is a redirect domain)"},"replacement":{"type":["string","null"],"description":"The temps-side address that replaces this domain when it is skipped.\n\nSource-generated domains (sslip.io / traefik.me / platform subdomains)\nembed the source server's IP and would keep pointing at the old\nmachine — this tells the user where the app will be reachable on\ntemps instead."},"status_code":{"type":["integer","null"],"format":"int32","description":"Redirect status code"}}},"DomainResponse":{"type":"object","required":["id","domain","status","is_wildcard","verification_method","created_at","updated_at"],"properties":{"certificate":{"type":["string","null"],"description":"The PEM-encoded certificate chain (can be displayed in browser or downloaded)"},"created_at":{"type":"integer","format":"int64"},"dns_challenge_token":{"type":["string","null"]},"dns_challenge_value":{"type":["string","null"]},"domain":{"type":"string"},"expiration_time":{"type":["integer","null"],"format":"int64"},"id":{"type":"integer","format":"int32"},"is_wildcard":{"type":"boolean"},"last_error":{"type":["string","null"]},"last_error_type":{"type":["string","null"]},"last_renewed":{"type":["integer","null"],"format":"int64"},"on_demand_backoff_until":{"type":["integer","null"],"format":"int64","description":"On-demand TLS negative-cache deadline (epoch millis), when this hostname's\non-demand HTTP-01 issuance is in backoff after a failure (ADR-018 §4).\n`None` means no active backoff."},"status":{"type":"string"},"updated_at":{"type":"integer","format":"int64"},"verification_method":{"type":"string"}}},"DrainNodeResponse":{"type":"object","required":["id","name","status","affected_environments","message"],"properties":{"affected_environments":{"type":"integer","minimum":0},"id":{"type":"integer","format":"int32"},"message":{"type":"string"},"name":{"type":"string"},"status":{"type":"string"}}},"DrainStatusResponse":{"type":"object","description":"Progress of a node drain operation.","required":["node_id","node_name","status","remaining_containers","drain_complete","can_remove","message"],"properties":{"can_remove":{"type":"boolean","description":"Can the node be safely removed?"},"drain_complete":{"type":"boolean","description":"Whether the drain is complete (all containers migrated)"},"message":{"type":"string"},"node_id":{"type":"integer","format":"int32"},"node_name":{"type":"string"},"remaining_containers":{"type":"integer","description":"Number of containers still on this node","minimum":0},"status":{"type":"string"}}},"DropArchiveUpload":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary"}}},"DropInspectionResponse":{"type":"object","required":["suggestedName","candidates"],"properties":{"candidates":{"type":"array","items":{"$ref":"#/components/schemas/DropPresetCandidate"}},"suggestedName":{"type":"string"}}},"DropOffPoint":{"type":"object","description":"Drop-off point: pages where visitors leave the site","required":["page_path","exit_count","total_views","exit_rate"],"properties":{"exit_count":{"type":"integer","format":"int64","description":"Number of exits from this page"},"exit_rate":{"type":"number","format":"double","description":"Exit rate for this page (exit_count / total_views)"},"page_path":{"type":"string","description":"The page path where visitors drop off"},"total_views":{"type":"integer","format":"int64","description":"Total views of this page"}}},"DropPresetCandidate":{"type":"object","required":["directory","preset","label","confidence","reason","isStatic"],"properties":{"confidence":{"type":"string"},"directory":{"type":"string"},"isStatic":{"type":"boolean"},"label":{"type":"string"},"preset":{"type":"string"},"reason":{"type":"string"}}},"EmailConfig":{"type":"object","required":["smtp_host","smtp_port","username","password","from_address","to_addresses"],"properties":{"accept_invalid_certs":{"type":"boolean"},"from_address":{"type":"string"},"from_name":{"type":["string","null"]},"password":{"type":"string"},"smtp_host":{"type":"string"},"smtp_port":{"type":"integer","format":"int32","minimum":0},"starttls_required":{"type":"boolean"},"tls_mode":{"$ref":"#/components/schemas/TlsMode"},"to_addresses":{"type":"array","items":{"type":"string"}},"username":{"type":"string"}}},"EmailDomainResponse":{"type":"object","required":["id","provider_id","domain","status","created_at","updated_at"],"properties":{"created_at":{"type":"string","example":"2025-12-03T10:30:00Z"},"domain":{"type":"string","example":"updates.example.com"},"id":{"type":"integer","format":"int32"},"last_verified_at":{"type":["string","null"]},"provider_id":{"type":"integer","format":"int32"},"status":{"type":"string","example":"verified"},"updated_at":{"type":"string","example":"2025-12-03T10:30:00Z"},"verification_error":{"type":["string","null"]}}},"EmailDomainWithDnsResponse":{"type":"object","required":["domain","dns_records"],"properties":{"dns_records":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecordResponse"}},"domain":{"$ref":"#/components/schemas/EmailDomainResponse"}}},"EmailProviderResponse":{"type":"object","required":["id","name","provider_type","region","is_active","credentials","created_at","updated_at"],"properties":{"created_at":{"type":"string","example":"2025-12-03T10:30:00Z"},"credentials":{"description":"Masked credentials for display"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"name":{"type":"string","example":"My AWS SES"},"provider_type":{"$ref":"#/components/schemas/EmailProviderTypeRoute"},"region":{"type":"string","example":"us-east-1"},"sns_topic_arn":{"type":["string","null"]},"updated_at":{"type":"string","example":"2025-12-03T10:30:00Z"}}},"EmailProviderTypeRoute":{"type":"string","enum":["ses","scaleway","smtp"]},"EmailRequest":{"type":"object","description":"Request body carrying just an email address (password-reset request).","required":["email"],"properties":{"email":{"type":"string"}}},"EmailResponse":{"type":"object","required":["id","from_address","to_addresses","subject","status","created_at","track_opens","track_clicks","open_count","click_count"],"properties":{"bcc_addresses":{"type":["array","null"],"items":{"type":"string"}},"cc_addresses":{"type":["array","null"],"items":{"type":"string"}},"click_count":{"type":"integer","format":"int32","description":"Number of times links in the email were clicked"},"created_at":{"type":"string","example":"2025-12-03T10:30:00Z"},"domain_id":{"type":["integer","null"],"format":"int32"},"error_message":{"type":["string","null"]},"first_clicked_at":{"type":["string","null"],"description":"When a link was first clicked"},"first_opened_at":{"type":["string","null"],"description":"When the email was first opened"},"from_address":{"type":"string","example":"hello@updates.example.com"},"from_name":{"type":["string","null"]},"headers":{"type":["object","null"],"additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"html_body":{"type":["string","null"]},"id":{"type":"string","example":"550e8400-e29b-41d4-a716-446655440000"},"open_count":{"type":"integer","format":"int32","description":"Number of times the email was opened"},"project_id":{"type":["integer","null"],"format":"int32"},"provider_message_id":{"type":["string","null"]},"reply_to":{"type":["string","null"]},"sent_at":{"type":["string","null"]},"status":{"type":"string","example":"sent"},"subject":{"type":"string"},"tags":{"type":["array","null"],"items":{"type":"string"}},"text_body":{"type":["string","null"]},"to_addresses":{"type":"array","items":{"type":"string"}},"track_clicks":{"type":"boolean","description":"Whether click tracking is enabled"},"track_opens":{"type":"boolean","description":"Whether open tracking is enabled"},"tracked_html_body":{"type":["string","null"],"description":"The final HTML sent to the provider (with tracking pixel and rewritten links)"}}},"EmailStatsResponse":{"type":"object","required":["total","sent","failed","queued","captured"],"properties":{"captured":{"type":"integer","format":"int64","description":"Emails captured without sending (Mailhog mode - no provider configured)","minimum":0},"failed":{"type":"integer","format":"int64","minimum":0},"queued":{"type":"integer","format":"int64","minimum":0},"sent":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"EmailStatusResponse":{"type":"object","required":["email_configured","password_reset_available","oidc_providers"],"properties":{"email_configured":{"type":"boolean"},"oidc_providers":{"type":"array","items":{"$ref":"#/components/schemas/OidcProviderSummary"}},"password_reset_available":{"type":"boolean"}}},"EmailTrackingResponse":{"type":"object","description":"Email tracking summary","required":["email_id","track_opens","track_clicks","open_count","click_count","unique_opens","unique_clicks","links"],"properties":{"click_count":{"type":"integer","format":"int32"},"email_id":{"type":"string"},"first_clicked_at":{"type":["string","null"]},"first_opened_at":{"type":["string","null"]},"links":{"type":"array","items":{"$ref":"#/components/schemas/TrackedLinkResponse"}},"open_count":{"type":"integer","format":"int32"},"track_clicks":{"type":"boolean"},"track_opens":{"type":"boolean"},"unique_clicks":{"type":"integer","format":"int64","minimum":0},"unique_opens":{"type":"integer","format":"int64","minimum":0}}},"EmailTrackingSetupResponse":{"type":"object","description":"Result of the one-click AWS-side event-tracking setup.","required":["topic_arn","webhook_url","subscription_requested","event_destination_attached"],"properties":{"event_destination_attached":{"type":"boolean","description":"The SESv2 event destination (bounce/complaint/delivery) is attached\nto the `temps-tracking` configuration set."},"subscription_requested":{"type":"boolean","description":"The webhook subscription was requested; SNS confirms it\nasynchronously through the webhook itself."},"topic_arn":{"type":"string","example":"arn:aws:sns:us-east-1:123456789012:temps-email-events-1"},"webhook_url":{"type":"string"}}},"EmailTrackingStatusResponse":{"type":"object","description":"Live status of the SES event-tracking pipeline for one provider.","required":["webhook_url","supports_event_tracking"],"properties":{"last_event_at":{"type":["string","null"],"description":"Most recent delivered/bounced/complained event recorded for an email\nsent through this provider. `null` means no provider feedback has\narrived yet.","example":"2026-07-18T10:31:00Z"},"sns_topic_arn":{"type":["string","null"]},"subscription_confirmed_at":{"type":["string","null"],"description":"When the SNS subscription for the current topic was confirmed.\n`null` with a topic set usually means the subscription is still\npending — most often because the endpoint was subscribed before the\ntopic ARN was saved here.","example":"2026-07-18T10:30:00Z"},"supports_event_tracking":{"type":"boolean","description":"Only SES providers support SNS event tracking."},"webhook_url":{"type":"string","description":"Public webhook endpoint SNS must deliver events to.","example":"https://temps.example.com/api/t/webhook/ses"}}},"EmbeddingData":{"type":"object","required":["object","embedding","index"],"properties":{"embedding":{"type":"array","items":{"type":"number","format":"double"}},"index":{"type":"integer","format":"int32"},"object":{"type":"string"}}},"EmbeddingInput":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"EmbeddingRequest":{"type":"object","required":["model","input"],"properties":{"dimensions":{"type":["integer","null"],"format":"int32"},"encoding_format":{"type":["string","null"]},"input":{"$ref":"#/components/schemas/EmbeddingInput"},"model":{"type":"string"}}},"EmbeddingResponse":{"type":"object","required":["object","data","model","usage"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/EmbeddingData"}},"model":{"type":"string"},"object":{"type":"string"},"usage":{"$ref":"#/components/schemas/EmbeddingUsage"}}},"EmbeddingUsage":{"type":"object","required":["prompt_tokens","total_tokens"],"properties":{"prompt_tokens":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"EnableBlobRequest":{"type":"object","description":"Request to enable Blob service","properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use (optional, defaults to RustFS)","example":"ghcr.io/rustfs/rustfs:0.5.0"},"root_password":{"type":["string","null"],"description":"Root password for S3 access"},"root_user":{"type":["string","null"],"description":"Root user for S3 access"}}},"EnableBlobResponse":{"type":"object","description":"Response after enabling Blob service","required":["success","message","status"],"properties":{"message":{"type":"string","description":"Human-readable message","example":"Blob service enabled successfully"},"status":{"$ref":"#/components/schemas/BlobStatusResponse","description":"Current status"},"success":{"type":"boolean","description":"Whether the operation succeeded","example":true}}},"EnableKvRequest":{"type":"object","description":"Request to enable the KV service","properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use (optional, uses default if not provided)","example":"gotempsh/redis-walg:8-bookworm"},"max_memory":{"type":["string","null"],"description":"Maximum memory allocation (e.g., \"256mb\", \"1gb\")","example":"256mb"},"persistence":{"type":"boolean","description":"Enable data persistence"}}},"EnableKvResponse":{"type":"object","description":"Response after enabling KV service","required":["success","message","status"],"properties":{"message":{"type":"string","description":"Status message","example":"KV service enabled successfully"},"status":{"$ref":"#/components/schemas/KvStatusResponse","description":"Current service status"},"success":{"type":"boolean","description":"Whether the service was successfully enabled"}}},"EnablePgStatStatementsResponse":{"type":"object","description":"Response for the enable pg_stat_statements endpoint.","required":["message"],"properties":{"message":{"type":"string","description":"Human-readable message confirming the action."}}},"EndpointDto":{"type":"object","description":"One DNS record on the wire. Mirrors `service_endpoints::Model` but\nkeeps the API stable across entity evolution. `target_ip` is a string\n(v4 or v6 literal, or CNAME target hostname) parsed by the resolver.","required":["id","fqdn","record_type","ttl","owner_kind","owner_id","generation"],"properties":{"fqdn":{"type":"string"},"generation":{"type":"integer","format":"int64"},"id":{"type":"integer","format":"int64"},"node_id":{"type":["integer","null"],"format":"int32"},"owner_id":{"type":"integer","format":"int64"},"owner_kind":{"type":"string"},"record_type":{"type":"string"},"target_ip":{"type":["string","null"]},"target_port":{"type":["integer","null"],"format":"int32"},"ttl":{"type":"integer","format":"int32"}}},"EnqueuedJob":{"type":"object","description":"A single job that was successfully enqueued during a fan-out run.","required":["backup_id","job_id","engine"],"properties":{"backup_id":{"type":"integer","format":"int32","description":"FK to `backups.id` for this job."},"engine":{"type":"string","description":"Engine key (e.g. `\"control_plane\"`, `\"redis\"`, `\"postgres_pgdump\"`)."},"job_id":{"type":"integer","format":"int64","description":"FK to `backup_jobs.id` for this job."},"target_service_id":{"type":["integer","null"],"format":"int32","description":"FK to `external_services.id` when this is an external-service job.\n`None` for the control-plane job."}}},"EnrichVisitorRequest":{"type":"object","required":["custom_data"],"properties":{"custom_data":{"type":"object"}}},"EnrichVisitorResponse":{"type":"object","required":["success","visitor_id","message"],"properties":{"message":{"type":"string"},"success":{"type":"boolean"},"visitor_id":{"type":"string"}}},"EnrollCloudRequest":{"type":"object","required":["enrollment_code"],"properties":{"enrollment_code":{"type":"string","example":"ABCD-EFGH","minLength":1}}},"EnrollmentTokenInfo":{"type":"object","required":["id","expires_at","used_count","max_uses","created_at"],"properties":{"bound_node_name":{"type":["string","null"]},"created_at":{"type":"string"},"expires_at":{"type":"string"},"id":{"type":"integer","format":"int32"},"max_uses":{"type":"integer","format":"int32"},"used_count":{"type":"integer","format":"int32"}}},"EnrollmentTokenListResponse":{"type":"object","required":["tokens"],"properties":{"tokens":{"type":"array","items":{"$ref":"#/components/schemas/EnrollmentTokenInfo"}}}},"EntityInfoResponse":{"type":"object","required":["container_path","entity","entity_type","fields"],"properties":{"container_path":{"type":"array","items":{"type":"string"},"description":"Full container path","example":["mydb","public"]},"entity":{"type":"string","description":"Entity name","example":"users"},"entity_type":{"type":"string","description":"Entity type","example":"table"},"fields":{"type":"array","items":{"$ref":"#/components/schemas/FieldResponse"},"description":"Field definitions"},"metadata":{"description":"Additional metadata (content_type, last_modified, etag, etc.)"},"row_count":{"type":["integer","null"],"description":"Approximate row count (for tables/collections)","example":1234,"minimum":0},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size in bytes (for objects/files)","example":1048576,"minimum":0},"sort_schema":{"description":"JSON Schema for sort options (if supported)"}}},"EntityResponse":{"type":"object","required":["name","entity_type"],"properties":{"entity_type":{"type":"string","description":"Entity type (table, view, collection, etc.)","example":"table"},"name":{"type":"string","description":"Entity name (table/collection)","example":"users"},"row_count":{"type":["integer","null"],"description":"Approximate row count","example":1234,"minimum":0},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size in bytes (for files/objects)","example":1048576,"minimum":0}}},"EnvVarInput":{"type":"object","description":"Input for environment variable","required":["name","value"],"properties":{"name":{"type":"string","description":"Variable name"},"value":{"type":"string","description":"Variable value"}}},"EnvVarIntegrationInfo":{"type":"object","required":["service_id","service_name","service_type","service_updated_at"],"properties":{"service_id":{"type":"integer","format":"int32"},"service_name":{"type":"string"},"service_slug":{"type":["string","null"]},"service_type":{"type":"string"},"service_updated_at":{"type":"string"}}},"EnvVarResponse":{"type":"object","description":"Environment variable with masked sensitive values","required":["key","value","is_masked"],"properties":{"is_masked":{"type":"boolean","description":"Whether this is a sensitive/masked value"},"key":{"type":"string"},"value":{"type":"string"}}},"EnvVarTemplateResponse":{"type":"object","description":"Environment variable template response","required":["name","required"],"properties":{"default":{"type":["string","null"],"description":"Default value if not provided by user"},"default_generator":{"type":["string","null"],"description":"Frontend-side generator hint for the default value\n(e.g. `app_url`, `random_secret`, `random_hex_32`)"},"description":{"type":["string","null"],"description":"Description of what this variable is used for"},"example":{"type":["string","null"],"description":"Example value for documentation"},"name":{"type":"string","description":"Name of the environment variable"},"required":{"type":"boolean","description":"Whether this variable is required"}}},"EnvironmentConfiguration":{"type":"object","description":"Environment-level configuration","required":["name","subdomain","resources"],"properties":{"name":{"type":"string","description":"Environment name"},"resources":{"$ref":"#/components/schemas/ResourceLimits","description":"Resource limits for environment"},"subdomain":{"type":"string","description":"Proposed subdomain"}}},"EnvironmentDomainResponse":{"type":"object","required":["id","environment_id","domain","created_at","url"],"properties":{"created_at":{"type":"integer","format":"int64"},"domain":{"type":"string"},"environment_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"url":{"type":"string","description":"Full URL for this domain (e.g., https://buildtolearndev-production.example.com)","example":"https://buildtolearndev-production.example.com"}}},"EnvironmentInfo":{"type":"object","required":["id","name","main_url"],"properties":{"current_deployment_id":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"main_url":{"type":"string"},"name":{"type":"string"}}},"EnvironmentResponse":{"type":"object","required":["id","project_id","name","slug","main_url","subdomain","created_at","updated_at","is_preview","protected","sleeping"],"properties":{"attack_mode":{"type":["boolean","null"],"description":"Per-environment CAPTCHA attack-mode override.\n`null` means inherit the project-level `attack_mode`; `true`/`false`\nexplicitly enable/disable the challenge for this environment. Always\nserialized (NOT skipped) so the UI can distinguish `null` from `false`."},"branch":{"type":["string","null"]},"created_at":{"type":"integer","format":"int64"},"current_deployment_id":{"type":["integer","null"],"format":"int32"},"deployment_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DeploymentConfig","description":"Deployment configuration for this environment (overrides project-level config)"}]},"estimated_sleep_at":{"type":["integer","null"],"format":"int64","description":"Estimated time (epoch millis) when the environment will go to sleep\nbased on last activity + idle timeout. NULL when sleeping or on-demand disabled."},"force_https":{"type":["boolean","null"],"description":"Per-environment HTTP→HTTPS redirect override.\n`null` means inherit the proxy default (redirect only when the host has\nan active TLS certificate); `true` always redirects plain HTTP for this\nenvironment, `false` never does. Always serialized (NOT skipped) so the\nUI can distinguish `null` from `false`."},"id":{"type":"integer","format":"int32"},"is_preview":{"type":"boolean","description":"Indicates if this is a preview environment (auto-created per branch)\nFor preview environments, 'branch' contains the feature branch name"},"last_activity_at":{"type":["integer","null"],"format":"int64","description":"Last proxied request timestamp (epoch millis) for on-demand environments.\nNULL when on-demand is disabled or no traffic has been received yet."},"main_url":{"type":"string"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"protected":{"type":"boolean","description":"When true, git pushes do NOT auto-deploy to this environment.\nDeployments must be promoted from another environment."},"sleeping":{"type":"boolean","description":"When true, the environment's containers are currently stopped due to\ninactivity (on-demand mode) and will start on the next request."},"slug":{"type":"string"},"subdomain":{"type":"string","description":"The host label stored for this environment (e.g.\n`myproject-production`). This is the prefix that is combined with the\nplatform's preview domain at request time to produce `main_url`. Edit\nthis via the rename-subdomain endpoint, not the full URL."},"updated_at":{"type":"integer","format":"int64"}}},"EnvironmentVariable":{"type":"object","description":"Environment variable","required":["key","value","is_secret"],"properties":{"is_secret":{"type":"boolean","description":"Whether this is a secret (should be encrypted)"},"key":{"type":"string","description":"Variable name"},"source_description":{"type":["string","null"],"description":"Where this env var originates from (for traceability)"},"value":{"type":"string","description":"Variable value (may be redacted for secrets)"}}},"EnvironmentVariableInfo":{"type":"object","required":["name","value","sensitive"],"properties":{"name":{"type":"string"},"sensitive":{"type":"boolean","description":"Whether this variable contains sensitive data (passwords, keys, tokens)","example":false},"value":{"type":"string"}}},"EnvironmentVariableResponse":{"type":"object","required":["id","key","created_at","updated_at","environments","include_in_preview","is_secret"],"properties":{"created_at":{"type":"integer","format":"int64"},"environments":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentInfo"}},"id":{"type":"integer","format":"int32"},"include_in_preview":{"type":"boolean","description":"Include this environment variable in preview environments"},"is_secret":{"type":"boolean","description":"Whether the variable is a write-only secret. Secrets always have\n`value: None` in responses."},"key":{"type":"string"},"updated_at":{"type":"integer","format":"int64"},"value":{"type":["string","null"],"description":"Plaintext value for non-secret vars (or `\"***\"` mask for list responses).\n`None` for secret vars — secrets are write-only."}}},"EnvironmentVariableValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"ErrorDashboardStatsQuery":{"type":"object","required":["start_time","end_time"],"properties":{"compare_to_previous":{"type":["boolean","null"]},"end_time":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"start_time":{"type":"string","format":"date-time"}}},"ErrorDashboardStatsResponse":{"type":"object","required":["total_errors","total_errors_previous_period","total_errors_change_percent","error_groups","error_groups_previous_period","start_time","end_time"],"properties":{"comparison_end_time":{"type":["string","null"],"format":"date-time"},"comparison_start_time":{"type":["string","null"],"format":"date-time"},"end_time":{"type":"string","format":"date-time"},"error_groups":{"type":"integer","format":"int64"},"error_groups_previous_period":{"type":"integer","format":"int64"},"start_time":{"type":"string","format":"date-time"},"total_errors":{"type":"integer","format":"int64"},"total_errors_change_percent":{"type":"number","format":"double"},"total_errors_previous_period":{"type":"integer","format":"int64"}}},"ErrorEventResponse":{"type":"object","required":["id","error_group_id","timestamp","created_at"],"properties":{"created_at":{"type":"string"},"data":{"description":"Full error event data (contains raw Sentry event or custom error data)"},"error_group_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int64"},"source":{"type":["string","null"],"description":"Source of the error event (e.g., \"sentry\", \"custom\", \"bugsnag\")"},"timestamp":{"type":"string"}}},"ErrorGroupResponse":{"type":"object","required":["id","title","error_type","first_seen","last_seen","total_count","status","project_id","created_at","updated_at"],"properties":{"assigned_to":{"type":["string","null"]},"created_at":{"type":"string"},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_type":{"type":"string"},"first_seen":{"type":"string"},"id":{"type":"integer","format":"int32"},"last_seen":{"type":"string"},"message_template":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"status":{"type":"string"},"title":{"type":"string"},"total_count":{"type":"integer","format":"int32"},"updated_at":{"type":"string"},"visitor_id":{"type":["integer","null"],"format":"int32"}}},"ErrorGroupStatsResponse":{"type":"object","required":["total_groups","unresolved_groups","resolved_groups","ignored_groups"],"properties":{"ignored_groups":{"type":"integer","format":"int64"},"resolved_groups":{"type":"integer","format":"int64"},"total_groups":{"type":"integer","format":"int64"},"unresolved_groups":{"type":"integer","format":"int64"}}},"ErrorResponse":{"type":"object","required":["error"],"properties":{"details":{"type":["string","null"]},"error":{"type":"string"}}},"ErrorRow":{"type":"object","required":["id","ts","error_group_id","fingerprint","error_class","stacktrace_preview","stacktrace_truncated"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_class":{"type":"string"},"error_group_id":{"type":"integer","format":"int32"},"fingerprint":{"type":"string"},"id":{"type":"integer","format":"int64"},"message":{"type":["string","null"]},"stacktrace_preview":{},"stacktrace_truncated":{"type":"boolean"},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"}}},"ErrorTimeSeriesDataResponse":{"type":"object","required":["timestamp","count"],"properties":{"count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"}}},"ErrorTimeSeriesQuery":{"type":"object","required":["start_time","end_time"],"properties":{"bucket":{"type":"string","description":"Time bucket size (e.g., \"1h\", \"15m\", \"1d\", \"1 hour\", \"30 minutes\")","example":"1h"},"end_time":{"type":"string","format":"date-time"},"start_time":{"type":"string","format":"date-time"}}},"EventActivityBucket":{"type":"object","description":"Time bucket data point for event activity graph","required":["timestamp","count","unique_visitors"],"properties":{"count":{"type":"integer","format":"int64","description":"Number of event occurrences in this bucket"},"timestamp":{"type":"string","description":"Timestamp for this bucket (ISO 8601)"},"unique_visitors":{"type":"integer","format":"int64","description":"Number of unique visitors in this bucket"}}},"EventBreakdown":{"type":"string","enum":["country","region","city"]},"EventBrowserStats":{"type":"object","description":"Browser stats for an event","required":["browser","count","percentage"],"properties":{"browser":{"type":"string","description":"Browser name"},"count":{"type":"integer","format":"int64","description":"Number of event occurrences from this browser"},"percentage":{"type":"number","format":"double","description":"Percentage of total events"}}},"EventCount":{"type":"object","required":["event_name","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"event_name":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"EventCountryStats":{"type":"object","description":"Country stats for an event","required":["country","count","percentage"],"properties":{"count":{"type":"integer","format":"int64","description":"Number of event occurrences from this country"},"country":{"type":"string","description":"Country name"},"country_code":{"type":["string","null"],"description":"ISO country code (2-letter)"},"percentage":{"type":"number","format":"double","description":"Percentage of total events"}}},"EventDetailQuery":{"type":"object","description":"Query parameters for event detail analytics","required":["event_name","project_id","start_date","end_date"],"properties":{"bucket_interval":{"type":["string","null"],"description":"Bucket interval for time series: 'hour', 'day', 'week', 'month' (default: auto)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_name":{"type":"string","description":"The specific event name to get details for"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventDetailResponse":{"type":"object","description":"Summary response for a specific event's analytics","required":["event_name","total_count","unique_visitors","unique_sessions","activity_over_time","referrers","countries","browsers","bucket_interval"],"properties":{"activity_over_time":{"type":"array","items":{"$ref":"#/components/schemas/EventActivityBucket"},"description":"Time series data for event activity graph"},"browsers":{"type":"array","items":{"$ref":"#/components/schemas/EventBrowserStats"},"description":"Browser distribution of visitors who triggered this event"},"bucket_interval":{"type":"string","description":"Bucket interval used for time series ('hour', 'day', etc.)"},"countries":{"type":"array","items":{"$ref":"#/components/schemas/EventCountryStats"},"description":"Geographic distribution of visitors who triggered this event"},"event_name":{"type":"string","description":"The event name being analyzed"},"referrers":{"type":"array","items":{"$ref":"#/components/schemas/EventReferrerStats"},"description":"Top referrer hostnames for visitors who triggered this event"},"total_count":{"type":"integer","format":"int64","description":"Total number of times this event was triggered in the date range"},"unique_sessions":{"type":"integer","format":"int64","description":"Number of unique sessions where this event occurred"},"unique_visitors":{"type":"integer","format":"int64","description":"Number of unique visitors who triggered this event"}}},"EventEntriesQuery":{"type":"object","description":"Query parameters for the raw event entries list","required":["event_name","project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_name":{"type":"string","description":"The specific event name to list occurrences for"},"page":{"type":["integer","null"],"format":"int64","description":"Page number (1-based, default: 1)","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","description":"Items per page (default: 20, max: 100)","minimum":0},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventEntriesResponse":{"type":"object","description":"Paginated response for raw event entries","required":["event_name","total_count","page","per_page","entries"],"properties":{"entries":{"type":"array","items":{"$ref":"#/components/schemas/EventEntryInfo"},"description":"Individual event occurrences, most recent first"},"event_name":{"type":"string","description":"The event name"},"page":{"type":"integer","format":"int64","description":"Current page number","minimum":0},"per_page":{"type":"integer","format":"int64","description":"Items per page","minimum":0},"total_count":{"type":"integer","format":"int64","description":"Total number of occurrences of this event in the date range"}}},"EventEntryInfo":{"type":"object","description":"A single raw occurrence of an event, including its custom JSON properties","required":["id","timestamp","page_path","href"],"properties":{"browser":{"type":["string","null"],"description":"Browser name"},"city":{"type":["string","null"],"description":"City of the visitor at the time of the event"},"country":{"type":["string","null"],"description":"Country of the visitor at the time of the event"},"country_code":{"type":["string","null"],"description":"ISO country code (2-letter)"},"device_type":{"type":["string","null"],"description":"Device type (Desktop, Mobile, Tablet)"},"href":{"type":"string","description":"Full URL where the event was triggered"},"id":{"type":"integer","format":"int64","description":"Event row ID"},"page_path":{"type":"string","description":"Page path where the event was triggered"},"props":{"type":["object","null"],"description":"Custom event properties as JSON (null when the event carried no data)"},"session_id":{"type":["string","null"],"description":"Session ID the event belongs to (if any)"},"timestamp":{"type":"string","format":"date-time","description":"When the event occurred"},"visitor_id":{"type":["integer","null"],"format":"int32","description":"Visitor numeric ID (if known)"},"visitor_uuid":{"type":["string","null"],"description":"Visitor UUID (if known)"}}},"EventKind":{"type":"string","description":"Tag enum for filter parameters and routing. Matches the variant\ndiscriminator used by `ObservabilityEvent`.","enum":["request","span","error","revenue"]},"EventMetricsPayload":{"type":"object","required":["event_name","event_data","request_path","request_query"],"properties":{"cls":{"type":["number","null"],"format":"float","description":"Cumulative Layout Shift (score)"},"event_data":{},"event_name":{"type":"string"},"fcp":{"type":["number","null"],"format":"float","description":"First Contentful Paint (milliseconds)"},"fid":{"type":["number","null"],"format":"float","description":"First Input Delay (milliseconds)"},"inp":{"type":["number","null"],"format":"float","description":"Interaction to Next Paint (milliseconds)"},"language":{"type":["string","null"]},"lcp":{"type":["number","null"],"format":"float","description":"Largest Contentful Paint (milliseconds)"},"page_title":{"type":["string","null"]},"referrer":{"type":["string","null"],"description":"Referrer URL (falls back to Referer header if not provided)"},"request_path":{"type":"string"},"request_query":{"type":"string"},"screen_height":{"type":["integer","null"],"format":"int32","minimum":0},"screen_width":{"type":["integer","null"],"format":"int32","minimum":0},"ttfb":{"type":["number","null"],"format":"float","description":"Time to First Byte (milliseconds)"},"viewport_height":{"type":["integer","null"],"format":"int32","minimum":0},"viewport_width":{"type":["integer","null"],"format":"int32","minimum":0}}},"EventReferrerStats":{"type":"object","description":"Referrer stats for an event","required":["referrer","count","percentage"],"properties":{"count":{"type":"integer","format":"int64","description":"Number of event occurrences from this referrer"},"percentage":{"type":"number","format":"double","description":"Percentage of total events"},"referrer":{"type":"string","description":"Referrer hostname or \"Direct\""}}},"EventTimeline":{"type":"object","required":["date","count"],"properties":{"count":{"type":"integer","format":"int64"},"date":{"type":"string","format":"date-time"}}},"EventTimelineQuery":{"type":"object","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events (raw count), sessions (unique sessions), or visitors (unique visitors)"},"bucket_size":{"type":["string","null"],"description":"Bucket size: hour, day, or week (auto-detected if not specified)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_name":{"type":["string","null"]},"start_date":{"type":"string","format":"date-time"}}},"EventType":{"type":"object","required":["name","count"],"properties":{"count":{"type":"integer","format":"int64"},"name":{"type":"string"}}},"EventTypeBreakdown":{"type":"object","required":["event_type","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"event_type":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"EventTypeBreakdownQuery":{"type":"object","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events (raw count), sessions (unique sessions), or visitors (unique visitors)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventTypeResponse":{"type":"object","required":["event_type","description","category"],"properties":{"category":{"type":"string"},"description":{"type":"string"},"event_type":{"type":"string"}}},"EventTypesResponse":{"type":"object","required":["events","total","page","page_size"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/EventType"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"EventVisitorInfo":{"type":"object","description":"A visitor who triggered a specific event","required":["visitor_id","visitor_uuid","event_count","first_triggered","last_triggered"],"properties":{"browser":{"type":["string","null"],"description":"Browser name"},"city":{"type":["string","null"],"description":"Visitor's city"},"country":{"type":["string","null"],"description":"Visitor's country"},"country_code":{"type":["string","null"],"description":"Visitor's country code"},"device_type":{"type":["string","null"],"description":"Device type (Desktop, Mobile, Tablet)"},"event_count":{"type":"integer","format":"int64","description":"Number of times this visitor triggered the event"},"first_triggered":{"type":"string","format":"date-time","description":"When the visitor first triggered the event in the date range"},"last_triggered":{"type":"string","format":"date-time","description":"When the visitor last triggered the event in the date range"},"referrer_hostname":{"type":["string","null"],"description":"Referrer hostname for the event"},"visitor_id":{"type":"integer","format":"int32","description":"Visitor numeric ID"},"visitor_uuid":{"type":"string","description":"Visitor UUID"}}},"EventVisitorsQuery":{"type":"object","description":"Query parameters for event visitors list","required":["event_name","project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_name":{"type":"string","description":"The specific event name to list visitors for"},"page":{"type":["integer","null"],"format":"int64","description":"Page number (1-based, default: 1)","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","description":"Items per page (default: 20, max: 100)","minimum":0},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventVisitorsResponse":{"type":"object","description":"Paginated response for event visitors","required":["event_name","total_count","page","per_page","visitors"],"properties":{"event_name":{"type":"string","description":"The event name"},"page":{"type":"integer","format":"int64","description":"Current page number","minimum":0},"per_page":{"type":"integer","format":"int64","description":"Items per page","minimum":0},"total_count":{"type":"integer","format":"int64","description":"Total number of unique visitors who triggered this event"},"visitors":{"type":"array","items":{"$ref":"#/components/schemas/EventVisitorInfo"},"description":"Individual visitors who triggered this event"}}},"EventsCountQuery":{"type":"object","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events (raw count), sessions (unique sessions), or visitors (unique visitors)"},"custom_events_only":{"type":["boolean","null"],"description":"Only return custom events, excluding system events like page_view, page_leave, heartbeat (default: true)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventsResponse":{"type":"object","required":["events","applied_kinds"],"properties":{"applied_kinds":{"type":"array","items":{"$ref":"#/components/schemas/EventKind"},"description":"Echo of the kinds filter actually applied (server-resolved). Useful\nfor clients that pass `kinds=` empty and want to know what they got."},"events":{"type":"array","items":{"$ref":"#/components/schemas/ObservabilityEvent"}}}},"ExecBody":{"type":"object","required":["cmd"],"properties":{"cmd":{"type":"array","items":{"type":"string"}},"cwd":{"type":["string","null"]},"env":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}}},"additionalProperties":false},"ExecDetachedResponse":{"type":"object","required":["job_id"],"properties":{"job_id":{"type":"string"}}},"ExecResponse":{"type":"object","required":["exit_code","stdout","stderr"],"properties":{"exit_code":{"type":"integer","format":"int32"},"stderr":{"type":"string"},"stdout":{"type":"string"}}},"ExecuteImportRequest":{"type":"object","description":"Request to execute an import","required":["session_id","project_name","preset","directory","main_branch"],"properties":{"directory":{"type":"string","description":"Project directory","example":"."},"dry_run":{"type":["boolean","null"],"description":"Dry run mode (don't create resources)"},"main_branch":{"type":"string","description":"Main branch name","example":"main"},"preset":{"type":"string","description":"Preset to use for the project (e.g., \"nextjs\", \"express\", \"docker\")"},"project_name":{"type":"string","description":"Project name to use (overrides the name from the plan)","example":"my-app"},"session_id":{"type":"string","description":"Session ID from plan creation"}}},"ExecuteImportResponse":{"type":"object","description":"Response from import execution","required":["session_id","status","step_results"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32","description":"Created deployment ID (if completed)"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Created environment ID (if completed)"},"project_id":{"type":["integer","null"],"format":"int32","description":"Created project ID (if completed)"},"session_id":{"type":"string","description":"Session ID"},"status":{"$ref":"#/components/schemas/ImportExecutionStatus","description":"Execution status"},"step_results":{"type":"array","items":{"$ref":"#/components/schemas/StepResult"},"description":"Per-step results (in execution order)"}}},"ExecuteOperationRequest":{"type":"object","required":["operation"],"properties":{"operation":{"type":"string"}}},"ExpireRequest":{"type":"object","description":"Request to set expiration on a key","required":["key","seconds"],"properties":{"key":{"type":"string","description":"The key to set expiration on","example":"session:abc"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1},"seconds":{"type":"integer","format":"int64","description":"Expiration time in seconds","example":3600}}},"ExpireResponse":{"type":"object","description":"Response for expire operation","required":["success"],"properties":{"success":{"type":"boolean","description":"True if expiration was set, false if key doesn't exist"}}},"ExplorerSupportResponse":{"type":"object","required":["supported","service_type","capabilities","hierarchy"],"properties":{"capabilities":{"type":"array","items":{"type":"string"},"description":"Capabilities supported by this service","example":["sql"]},"filter_schema":{"description":"JSON Schema for filter format with embedded UI hints (if supported)"},"hierarchy":{"type":"array","items":{"$ref":"#/components/schemas/HierarchyLevel"},"description":"Hierarchy levels (describes the navigation structure)"},"reason":{"type":["string","null"],"description":"Reason why explorer is not supported (if applicable)"},"service_type":{"type":"string","description":"Service type","example":"postgres"},"supported":{"type":"boolean","description":"Whether the service supports query explorer functionality","example":true}}},"ExtendTimeoutBody":{"type":"object","properties":{"duration":{"type":["integer","null"],"format":"int64","description":"`@vercel/sandbox`-compatible alternative — duration in milliseconds.\nUsed when `extra_secs` is absent.","minimum":0},"extra_secs":{"type":["integer","null"],"format":"int64","description":"Extra seconds to add to the existing `expires_at` (temps-native).","minimum":0}}},"ExternalImageResponse":{"type":"object","required":["id","project_id","image_ref","pushed_at","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"digest":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"image_ref":{"type":"string"},"metadata":{},"project_id":{"type":"integer","format":"int32"},"pushed_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"size_bytes":{"type":["integer","null"],"format":"int64"},"tag":{"type":["string","null"]}}},"ExternalServiceBackupResponse":{"type":"object","description":"Response type for external service backup","required":["id","service_id","backup_id","backup_type","state","started_at","s3_location","metadata","compression_type","created_by"],"properties":{"backup_id":{"type":"integer","format":"int32"},"backup_type":{"type":"string"},"checksum":{"type":["string","null"]},"compression_type":{"type":"string"},"created_by":{"type":"integer","format":"int32"},"error_message":{"type":["string","null"]},"expires_at":{"type":["string","null"],"example":"2025-02-15T14:30:00.123Z"},"finished_at":{"type":["string","null"],"example":"2025-01-15T14:35:00.456Z"},"id":{"type":"integer","format":"int32"},"metadata":{},"s3_location":{"type":"string"},"service_id":{"type":"integer","format":"int32"},"size_bytes":{"type":["integer","null"],"format":"int64"},"started_at":{"type":"string","example":"2025-01-15T14:30:00.123Z"},"state":{"type":"string"}}},"ExternalServiceDetails":{"type":"object","required":["service","sensitive_parameters"],"properties":{"current_parameters":{"type":["object","null"],"additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"parameter_schema":{},"sensitive_parameters":{"type":"array","items":{"type":"string"},"description":"Parameter names whose values are masked in `current_parameters` and\nmay be fetched only through the audited reveal endpoint."},"service":{"$ref":"#/components/schemas/ExternalServiceInfo"}}},"ExternalServiceInfo":{"type":"object","required":["id","name","service_type","status","created_at","updated_at","topology"],"properties":{"connection_info":{"type":["string","null"]},"created_at":{"type":"string"},"error_message":{"type":["string","null"],"description":"Error message from failed initialization."},"id":{"type":"integer","format":"int32"},"members":{"type":"array","items":{"$ref":"#/components/schemas/ServiceMemberInfo"},"description":"Cluster members (empty for standalone services)."},"metrics_enabled":{"type":"boolean","description":"Whether metric collection is enabled for this service. The UI uses this\nto decide whether to poll the monitoring endpoints."},"name":{"type":"string"},"node_id":{"type":["integer","null"],"format":"int32","description":"Node ID where the service runs. Null means control plane (local)."},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute"},"status":{"type":"string"},"topology":{"type":"string","description":"Service topology: \"standalone\" (single container) or \"cluster\" (HA multi-member).","example":"standalone"},"updated_at":{"type":"string"},"version":{"type":["string","null"]}}},"ExternalServiceSummary":{"type":"object","description":"Summary of the external service that owns a backup. Only populated for\nexternal-service backups (Redis, Postgres, etc.); absent for control-plane\nbackups.","required":["id","name","service_type"],"properties":{"id":{"type":"integer","format":"int32","description":"Database id of the external service."},"name":{"type":"string","description":"Human-readable service name (e.g. \"redis-prod\")."},"service_type":{"type":"string","description":"Service type string (e.g. \"postgres\", \"redis\", \"mongodb\").","example":"postgres"}}},"FieldResponse":{"type":"object","required":["name","field_type","nullable"],"properties":{"field_type":{"type":"string","description":"Field type (Int32, String, Timestamp, etc.)","example":"Int64"},"name":{"type":"string","description":"Field name","example":"id"},"nullable":{"type":"boolean","description":"Whether the field is nullable","example":false}}},"FiringSeriesEntry":{"type":"object","description":"A single currently-firing series for a dynamic alert rule, snapshotted from\nthe evaluator's in-memory per-series firing map at read time (ADR-026 Phase 3).","required":["series_key","series_label"],"properties":{"alarm_id":{"type":["integer","null"],"format":"int32","description":"The open alarm's id, when one was created (absent if suppressed)."},"series_key":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"The series' label pairs, e.g. `[[\"endpoint\",\"/checkout\"],[\"region\",\"eu-west\"]]`."},"series_label":{"type":"string","description":"The human-readable joined label, e.g. `endpoint=/checkout, region=eu-west`."}}},"FlagEnvironmentResponse":{"type":"object","required":["environment_id","enabled"],"properties":{"enabled":{"type":"boolean"},"environment_id":{"type":"integer","format":"int32"},"value":{}}},"FlagListResponse":{"type":"object","description":"Note the absence of `salt`: it is never exposed. Publishing the bucketing\nsalt would let a client predict, and self-select into, a rollout cohort.","required":["flags","total","page","page_size","total_pages"],"properties":{"flags":{"type":"array","items":{"$ref":"#/components/schemas/FlagResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","description":"Total flags matching the filter, across all pages.","minimum":0},"total_pages":{"type":"integer","format":"int64","minimum":0}}},"FlagResponse":{"type":"object","required":["id","key","value_type","default_value","client_visible","created_at","updated_at","environments"],"properties":{"archived_at":{"type":["string","null"]},"client_visible":{"type":"boolean"},"created_at":{"type":"string"},"default_value":{},"description":{"type":["string","null"]},"environments":{"type":"array","items":{"$ref":"#/components/schemas/FlagEnvironmentResponse"},"description":"Per-environment overrides. Empty means the flag inherits its default\neverywhere."},"id":{"type":"integer","format":"int32"},"key":{"type":"string"},"last_evaluated_at":{"type":["string","null"],"description":"When an app last actually evaluated this flag. `None` means never seen,\nwhich is a real answer rather than missing data."},"updated_at":{"type":"string"},"value_type":{"type":"string"}}},"FlagSnapshot":{"type":"object","description":"A single flag, already resolved down to one environment. This is what the\nevaluator sees and what the SDK caches in memory.","required":["key","value_type","default_value","enabled"],"properties":{"default_value":{"description":"Served whenever evaluation cannot do better. Genuinely polymorphic by\ndesign — the surrounding struct carries the type."},"enabled":{"type":"boolean","description":"False means the kill switch is engaged for this environment."},"environment_value":{"description":"`None` means \"inherit `default_value`\"."},"key":{"type":"string"},"value_type":{"$ref":"#/components/schemas/FlagValueType"}}},"FlagSnapshotResponse":{"type":"object","required":["environment_id","flags"],"properties":{"environment_id":{"type":"integer","format":"int32"},"flags":{"type":"array","items":{"$ref":"#/components/schemas/FlagSnapshot"},"description":"Flags collapsed to what the evaluator needs, sorted by key so the\nserialized form — and therefore the ETag — is stable."}}},"FlagValueType":{"type":"string","description":"The declared type of a flag's value. Fixed at create time.","enum":["bool","string","number","json"]},"ForecastAlgorithm":{"type":"string","description":"Forecast model family.","enum":["linear","seasonal"]},"ForecastParams":{"type":"object","description":"Forecast detector parameters (stub — not yet evaluated).","required":["forecast_horizon_secs","comparator","threshold"],"properties":{"algorithm":{"$ref":"#/components/schemas/ForecastAlgorithm"},"comparator":{"$ref":"#/components/schemas/Comparator","description":"Comparator + threshold the *forecast* is checked against."},"deviations":{"type":"number","format":"double"},"forecast_horizon_secs":{"type":"integer","format":"int32","description":"How far ahead to project before checking the breach condition."},"threshold":{"type":"number","format":"double"}}},"FullError":{"type":"object","required":["id","ts","error_group_id","fingerprint","error_class"],"properties":{"data":{"description":"Full JSONB blob from `error_events.data` — stack trace, breadcrumbs,\nrequest context, everything. Schema is documented per source SDK."},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_class":{"type":"string"},"error_group_id":{"type":"integer","format":"int32"},"fingerprint":{"type":"string"},"id":{"type":"integer","format":"int64"},"message":{"type":["string","null"]},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"}}},"FullEvent":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/FullRequest"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["request"]}}}]},{"allOf":[{"$ref":"#/components/schemas/FullError"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["error"]}}}]},{"allOf":[{"$ref":"#/components/schemas/RevenueRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["revenue"]}}}]},{"allOf":[{"$ref":"#/components/schemas/SpanRow","description":"`SpanRow.attributes` is the truncated form; re-fetching returns\nthe same shape so the panel has a stable contract."},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["span"]}}}],"description":"`SpanRow.attributes` is the truncated form; re-fetching returns\nthe same shape so the panel has a stable contract."}],"description":"One un-truncated row, returned by the `/full/{type}/{id}` endpoint when\nthe user clicks \"Show full\". Same shape as the list rows, but with the\nraw heavy fields restored (no truncation flags) so the side panel can\nrender the long form."},"FullRequest":{"type":"object","required":["id","ts","method","host","path","status"],"properties":{"client_ip":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_group_id":{"type":["integer","null"],"format":"int32"},"host":{"type":"string"},"id":{"type":"string","description":"The request's unique `request_id` — same identity the list rows carry\n(backend-agnostic; ClickHouse rows have no serial PK)."},"latency_ms":{"type":["integer","null"],"format":"int32"},"method":{"type":"string"},"path":{"type":"string"},"referrer":{"type":["string","null"]},"request_headers":{},"response_headers":{},"status":{"type":"integer","format":"int32"},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"},"user_agent":{"type":["string","null"]}}},"FunnelMetricsResponse":{"type":"object","required":["funnel_id","funnel_name","total_entries","step_conversions","overall_conversion_rate","average_completion_time_seconds"],"properties":{"average_completion_time_seconds":{"type":"number","format":"double"},"funnel_id":{"type":"integer","format":"int32"},"funnel_name":{"type":"string"},"overall_conversion_rate":{"type":"number","format":"double"},"step_conversions":{"type":"array","items":{"$ref":"#/components/schemas/StepConversionResponse"}},"total_entries":{"type":"integer","format":"int64","minimum":0}}},"FunnelResponse":{"type":"object","required":["id","name","is_active","created_at","updated_at"],"properties":{"created_at":{"type":"string"},"description":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"name":{"type":"string"},"updated_at":{"type":"string"}}},"GatewayStatus":{"type":"object","description":"Detailed gateway container status surfaced to the settings UI.","required":["present","running","health","container_name","expected_image","drift","auto_upgrade"],"properties":{"auto_upgrade":{"type":"boolean","description":"True if `auto_upgrade` is enabled in settings."},"container_name":{"type":"string","description":"Container name."},"drift":{"type":"boolean","description":"True when `image != expected_image` and the container is present."},"expected_image":{"type":"string","description":"The image the supervisor *expects* (from settings/constant). If this\ndiffers from `image`, the UI shows a \"drift\" badge."},"health":{"type":"string","description":"Higher-level health label: \"running\" | \"restarting\" | \"crash_looping\"\n| \"stopped\" | \"missing\". UI should prefer this over `running`."},"host_port":{"type":["integer","null"],"format":"int32","description":"Host port that the container's :8080 is published on.","minimum":0},"image":{"type":["string","null"],"description":"Image reference the container was created with (e.g.\n`ghcr.io/gotempsh/temps-preview-gateway:latest`)."},"image_digest":{"type":["string","null"],"description":"Image digest if available (e.g. `sha256:…`)."},"last_error":{"type":["string","null"],"description":"Error string Docker recorded for the container (e.g. startup failure)."},"last_exit_code":{"type":["integer","null"],"format":"int64","description":"Exit code of the last run, if the container is not currently running."},"network":{"type":["string","null"],"description":"Network the container is attached to (should be `temps-sandbox-net`)."},"present":{"type":"boolean","description":"Whether the container exists at all."},"restart_count":{"type":["integer","null"],"format":"int64","description":"Number of times Docker has restarted the container."},"running":{"type":"boolean","description":"Whether the container is currently running."},"started_at":{"type":["string","null"],"description":"ISO 8601 timestamp the container was started at, if running."}}},"GenAiEvent":{"type":"object","description":"A GenAI-related event extracted from span events.\n\nCovers `gen_ai.client.inference.operation.details` and `gen_ai.evaluation.result`\nevents per the OTel GenAI semantic conventions.","required":["span_id","trace_id","event_name","timestamp","attributes"],"properties":{"attributes":{"type":"object","description":"All event attributes.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"event_name":{"type":"string"},"span_id":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"trace_id":{"type":"string"}}},"GenAiSpanDetail":{"type":"object","description":"A single GenAI span with extracted semantic convention fields.\n\nFields are aligned with the OpenTelemetry GenAI Semantic Conventions spec:\n","required":["span_id","name","kind","start_time","duration_ms","status_code","attributes"],"properties":{"agent_description":{"type":["string","null"],"description":"Agent description from `gen_ai.agent.description`."},"agent_id":{"type":["string","null"],"description":"Agent identifier from `gen_ai.agent.id`."},"agent_name":{"type":["string","null"],"description":"Agent name from `gen_ai.agent.name`."},"agent_version":{"type":["string","null"],"description":"Agent version from `gen_ai.agent.version`."},"attributes":{"type":"object","description":"All span attributes for extensibility.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"aws_bedrock_guardrail_id":{"type":["string","null"],"description":"AWS Bedrock guardrail ID from `aws.bedrock.guardrail.id`."},"aws_bedrock_knowledge_base_id":{"type":["string","null"],"description":"AWS Bedrock knowledge base ID from `aws.bedrock.knowledge_base.id`."},"azure_resource_provider_namespace":{"type":["string","null"],"description":"Azure resource provider namespace from `azure.resource_provider.namespace`."},"cache_creation_input_tokens":{"type":["integer","null"],"format":"int64","description":"Tokens written to provider cache from `gen_ai.usage.cache_creation.input_tokens`."},"cache_read_input_tokens":{"type":["integer","null"],"format":"int64","description":"Tokens served from provider cache from `gen_ai.usage.cache_read.input_tokens`."},"conversation_id":{"type":["string","null"],"description":"Unique conversation/session/thread ID from `gen_ai.conversation.id`."},"data_source_id":{"type":["string","null"],"description":"Data source identifier from `gen_ai.data_source.id`."},"duration_ms":{"type":"number","format":"double"},"embeddings_dimension_count":{"type":["integer","null"],"format":"int64","description":"Output embedding dimensions from `gen_ai.embeddings.dimension.count`."},"error_type":{"type":["string","null"],"description":"Error type from `error.type` when the span status is ERROR."},"gen_ai_model":{"type":["string","null"],"description":"The requested model from `gen_ai.request.model`."},"gen_ai_operation":{"type":["string","null"],"description":"The operation type from `gen_ai.operation.name` (e.g. \"chat\", \"embeddings\", \"execute_tool\")."},"gen_ai_response_model":{"type":["string","null"],"description":"The model that actually generated the response from `gen_ai.response.model`."},"gen_ai_system":{"type":["string","null"],"description":"The GenAI provider from `gen_ai.provider.name` (falls back to deprecated `gen_ai.system`)."},"input_messages":{"type":["string","null"],"description":"Chat history input from `gen_ai.input.messages` (opt-in, JSON string)."},"input_tokens":{"type":["integer","null"],"format":"int64"},"kind":{"$ref":"#/components/schemas/SpanKind"},"name":{"type":"string"},"openai_api_type":{"type":["string","null"],"description":"OpenAI API type from `openai.api.type` (chat_completions, responses)."},"openai_request_service_tier":{"type":["string","null"],"description":"Requested service tier from `openai.request.service_tier`."},"openai_response_service_tier":{"type":["string","null"],"description":"Actual service tier from `openai.response.service_tier`."},"openai_system_fingerprint":{"type":["string","null"],"description":"System fingerprint from `openai.response.system_fingerprint`."},"output_messages":{"type":["string","null"],"description":"Model output from `gen_ai.output.messages` (opt-in, JSON string)."},"output_tokens":{"type":["integer","null"],"format":"int64"},"output_type":{"type":["string","null"],"description":"Output content type from `gen_ai.output.type` (text, json, image, speech)."},"parent_span_id":{"type":["string","null"]},"request_choice_count":{"type":["integer","null"],"format":"int64","description":"Number of choices requested from `gen_ai.request.choice.count`."},"request_encoding_formats":{"type":["array","null"],"items":{"type":"string"},"description":"Requested encoding formats from `gen_ai.request.encoding_formats`."},"request_frequency_penalty":{"type":["number","null"],"format":"double","description":"Frequency penalty from `gen_ai.request.frequency_penalty`."},"request_max_tokens":{"type":["integer","null"],"format":"int64","description":"Max tokens from `gen_ai.request.max_tokens`."},"request_presence_penalty":{"type":["number","null"],"format":"double","description":"Presence penalty from `gen_ai.request.presence_penalty`."},"request_seed":{"type":["integer","null"],"format":"int64","description":"Seed for reproducibility from `gen_ai.request.seed`."},"request_stop_sequences":{"type":["array","null"],"items":{"type":"string"},"description":"Stop sequences from `gen_ai.request.stop_sequences`."},"request_temperature":{"type":["number","null"],"format":"double","description":"Temperature setting from `gen_ai.request.temperature`."},"request_top_k":{"type":["number","null"],"format":"double","description":"Top-k setting from `gen_ai.request.top_k`."},"request_top_p":{"type":["number","null"],"format":"double","description":"Top-p setting from `gen_ai.request.top_p`."},"response_finish_reasons":{"type":["array","null"],"items":{"type":"string"},"description":"Reasons the model stopped from `gen_ai.response.finish_reasons` (e.g. [\"stop\"])."},"response_id":{"type":["string","null"],"description":"Unique completion ID from `gen_ai.response.id` (e.g. \"chatcmpl-123\")."},"retrieval_documents":{"type":["string","null"],"description":"Retrieved documents from `gen_ai.retrieval.documents` (opt-in, JSON string)."},"retrieval_query_text":{"type":["string","null"],"description":"Retrieval query text from `gen_ai.retrieval.query.text` (opt-in)."},"server_address":{"type":["string","null"],"description":"GenAI server address from `server.address`."},"server_port":{"type":["integer","null"],"format":"int64","description":"GenAI server port from `server.port`."},"span_id":{"type":"string"},"start_time":{"type":"string","format":"date-time"},"status_code":{"$ref":"#/components/schemas/SpanStatusCode"},"system_instructions":{"type":["string","null"],"description":"System instructions from `gen_ai.system_instructions` (opt-in, JSON string)."},"tool_call_arguments":{"type":["string","null"],"description":"Tool call arguments from `gen_ai.tool.call.arguments` (opt-in, JSON string)."},"tool_call_id":{"type":["string","null"],"description":"Tool call ID from `gen_ai.tool.call.id`."},"tool_call_result":{"type":["string","null"],"description":"Tool call result from `gen_ai.tool.call.result` (opt-in, JSON string)."},"tool_definitions":{"type":["string","null"],"description":"Tool definitions from `gen_ai.tool.definitions` (opt-in, JSON string)."},"tool_description":{"type":["string","null"],"description":"Tool description from `gen_ai.tool.description`."},"tool_name":{"type":["string","null"],"description":"Tool name from `gen_ai.tool.name`."},"tool_type":{"type":["string","null"],"description":"Tool type from `gen_ai.tool.type` (function, extension, datastore)."}}},"GenAiTraceDetailResponse":{"type":"object","required":["trace_id","spans","span_count","events","event_count"],"properties":{"event_count":{"type":"integer","minimum":0},"events":{"type":"array","items":{"$ref":"#/components/schemas/GenAiEvent"}},"span_count":{"type":"integer","minimum":0},"spans":{"type":"array","items":{"$ref":"#/components/schemas/GenAiSpanDetail"}},"trace_id":{"type":"string"}}},"GenAiTraceSummariesResponse":{"type":"object","required":["data","total"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/GenAiTraceSummary"}},"total":{"type":"integer","format":"int64","minimum":0}}},"GenAiTraceSummary":{"type":"object","description":"Summary of a GenAI conversation — aggregated from OTel spans with `gen_ai.*` attributes.","required":["trace_id","root_span_name","service_name","start_time","duration_ms","span_count","error_count"],"properties":{"duration_ms":{"type":"number","format":"double"},"error_count":{"type":"integer","format":"int64"},"gen_ai_model":{"type":["string","null"],"description":"The requested model from `gen_ai.request.model`."},"gen_ai_operation":{"type":["string","null"],"description":"The operation type from `gen_ai.operation.name` (e.g. \"chat\", \"embeddings\")."},"gen_ai_system":{"type":["string","null"],"description":"The GenAI provider (e.g. \"openai\", \"anthropic\") from `gen_ai.provider.name`."},"root_span_name":{"type":"string"},"service_name":{"type":"string"},"span_count":{"type":"integer","format":"int64"},"start_time":{"type":"string","format":"date-time"},"total_cache_creation_input_tokens":{"type":["integer","null"],"format":"int64","description":"Total cache-creation input tokens across all spans."},"total_cache_read_input_tokens":{"type":["integer","null"],"format":"int64","description":"Total cache-read input tokens across all spans."},"total_input_tokens":{"type":["integer","null"],"format":"int64","description":"Total input tokens across all spans in this trace."},"total_output_tokens":{"type":["integer","null"],"format":"int64","description":"Total output tokens across all spans in this trace."},"trace_id":{"type":"string"}}},"GeneralStatsQuery":{"type":"object","required":["start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"start_date":{"type":"string","format":"date-time"}}},"GeneralStatsResponse":{"type":"object","required":["total_unique_visitors","total_visits","total_page_views","total_events","total_projects","avg_bounce_rate","avg_engagement_rate","project_breakdown"],"properties":{"avg_bounce_rate":{"type":"number","format":"double"},"avg_engagement_rate":{"type":"number","format":"double"},"page_views_trend_percentage":{"type":["number","null"],"format":"double","description":"Percentage change in page views vs previous period"},"previous_page_views":{"type":["integer","null"],"format":"int64","description":"Previous period page views"},"previous_unique_visitors":{"type":["integer","null"],"format":"int64","description":"Previous period unique visitors (same duration, shifted back)"},"project_breakdown":{"type":"array","items":{"$ref":"#/components/schemas/ProjectStatsBreakdown"}},"total_events":{"type":"integer","format":"int64"},"total_page_views":{"type":"integer","format":"int64"},"total_projects":{"type":"integer","format":"int64"},"total_unique_visitors":{"type":"integer","format":"int64"},"total_visits":{"type":"integer","format":"int64"},"visitors_trend_percentage":{"type":["number","null"],"format":"double","description":"Percentage change in unique visitors vs previous period"}}},"GenerateDockerfileRequest":{"type":"object","description":"Request body for generating a Dockerfile from a preset","properties":{"build_command":{"type":["string","null"],"description":"Custom build command (overrides preset default)","example":"npm run build"},"install_command":{"type":["string","null"],"description":"Custom install command (overrides preset default)","example":"npm ci"},"output_dir":{"type":["string","null"],"description":"Output directory for static builds","example":"dist"},"package_manager":{"type":["string","null"],"description":"Package manager used by the project (npm, yarn, pnpm, bun)\nIf not provided, defaults to npm","example":"npm"},"project_name":{"type":["string","null"],"description":"Project name/slug used for container naming","example":"my-app"},"use_buildkit":{"type":"boolean","description":"Whether to use BuildKit cache mounts for faster builds"}}},"GenerateDockerfileResponse":{"type":"object","description":"Response containing a generated Dockerfile and build arguments","required":["dockerfile","build_args","preset"],"properties":{"build_args":{"type":"object","description":"Build arguments to pass to `docker build --build-arg KEY=VALUE`","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"dockerfile":{"type":"string","description":"The generated Dockerfile content"},"preset":{"type":"string","description":"The preset slug used for generation"}}},"GenerateJoinTokenResponse":{"type":"object","description":"Response returned when a join token is generated (plaintext shown once)","required":["token","message"],"properties":{"message":{"type":"string"},"token":{"type":"string","description":"The plaintext join token — shown only once, save it now"}}},"GeoLocationResponse":{"type":"object","description":"Response containing geolocation information for an IP address","required":["ip","is_eu"],"properties":{"city":{"type":["string","null"],"description":"City name","example":"Mountain View"},"country":{"type":["string","null"],"description":"Country name","example":"United States"},"country_code":{"type":["string","null"],"description":"ISO country code (2 letters)","example":"US"},"ip":{"type":"string","description":"IP address that was geolocated","example":"8.8.8.8"},"is_eu":{"type":"boolean","description":"Whether the IP is in the European Union","example":false},"latitude":{"type":["number","null"],"format":"double","description":"Latitude coordinate","example":37.386},"longitude":{"type":["number","null"],"format":"double","description":"Longitude coordinate","example":-122.0838},"region":{"type":["string","null"],"description":"Region/state name","example":"California"},"timezone":{"type":["string","null"],"description":"Timezone identifier","example":"America/Los_Angeles"}}},"GeoRestrictionsConfig":{"type":"object","description":"Geographic restrictions configuration (future feature)","properties":{"allowedCountries":{"type":"array","items":{"type":"string"},"description":"Allow traffic only from specific countries"},"blockedCountries":{"type":"array","items":{"type":"string"},"description":"Block traffic from specific countries (ISO 3166-1 alpha-2 codes)"}}},"GetDeploymentsParams":{"type":"object","properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"page":{"type":["integer","null"],"format":"int64"},"per_page":{"type":["integer","null"],"format":"int64"}}},"GetEnvironmentVariablesQuery":{"type":"object","properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"service_id":{"type":["integer","null"],"format":"int32","description":"Required by integration-value reveals to bind the plaintext response to\nthe exact service displayed by the client."},"var_id":{"type":["integer","null"],"format":"int32","description":"Exact manual env-var row to reveal. Required by the dashboard so\nduplicate keys on disjoint environments cannot cross-reveal."}}},"GetFunnelMetricsQuery":{"type":"object","properties":{"country_code":{"type":["string","null"]},"end_date":{"type":["string","null"],"format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"start_date":{"type":["string","null"],"format":"date-time"}}},"GetOrCreateDSNRequest":{"type":"object","properties":{"base_url":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"}}},"GetProjectSecretsQuery":{"type":"object","properties":{"environment_id":{"type":["integer","null"],"format":"int32"}}},"GetProjectSessionReplaysQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0},"project_id":{"type":"integer","format":"int32"}}},"GetProjectSessionReplaysResponse":{"type":"object","required":["sessions","page","per_page","total_count"],"properties":{"page":{"type":"integer","format":"int64","minimum":0},"per_page":{"type":"integer","format":"int64","minimum":0},"sessions":{"type":"array","items":{"$ref":"#/components/schemas/SessionReplayWithVisitorDto"}},"total_count":{"type":"integer","format":"int64","minimum":0}}},"GetRequest":{"type":"object","description":"Request to get a value by key","required":["key"],"properties":{"key":{"type":"string","description":"The key to retrieve","example":"user:123"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"GetResponse":{"type":"object","description":"Response for get operation","properties":{"value":{"description":"The value, or null if not found"}}},"GetSessionReplayResponse":{"type":"object","required":["session"],"properties":{"session":{"$ref":"#/components/schemas/SessionReplayWithVisitorDto"}}},"GetUniqueEventsQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","minimum":0},"page_size":{"type":["integer","null"],"format":"int64","minimum":0}}},"GetVisitorSessionsQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0}}},"GetVisitorSessionsResponse":{"type":"object","required":["sessions","page","per_page","total_count"],"properties":{"page":{"type":"integer","format":"int64","minimum":0},"per_page":{"type":"integer","format":"int64","minimum":0},"sessions":{"type":"array","items":{"$ref":"#/components/schemas/SessionReplayWithVisitorDto"}},"total_count":{"type":"integer","minimum":0}}},"GitPushEvent":{"type":"object","description":"Git push event information that triggered the deployment","required":["repo","owner","branch","commit"],"properties":{"branch":{"type":"string","description":"Branch that was pushed"},"commit":{"type":"string","description":"Commit SHA"},"owner":{"type":"string","description":"Repository owner/organization"},"repo":{"type":"string","description":"Repository name"}}},"GitRefResponse":{"type":"object","description":"Git repository reference response","required":["url","ref"],"properties":{"path":{"type":["string","null"],"description":"Path within the repository (for monorepos)"},"ref":{"type":"string","description":"Git reference (branch, tag, or commit)"},"url":{"type":"string","description":"Git repository URL"}}},"GitSourcePlan":{"type":"object","description":"Git repository the source platform deploys from","required":["owner","repo","branch","is_public"],"properties":{"branch":{"type":"string","description":"Branch the source platform deploys"},"clone_url":{"type":["string","null"],"description":"Full clone URL, e.g. `https://github.com/owner/repo.git`"},"is_public":{"type":"boolean","description":"True when the repository is public (no credentials on the source\nplatform) — the project can then build without a git provider\nconnection."},"owner":{"type":"string","description":"Repository owner (organization or user)"},"repo":{"type":"string","description":"Repository name"}}},"GlobalConversationResponse":{"type":"object","description":"A conversation in the unified cross-project switcher: carries the project it\nbelongs to (name/slug) so the UI can show where the chat was started and\nlink back to the source.","required":["public_id","project_id","context_type","context_id","status","created_at","last_activity_at"],"properties":{"context_id":{"type":"string"},"context_type":{"type":"string"},"created_at":{"type":"string"},"last_activity_at":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":["string","null"]},"project_slug":{"type":["string","null"]},"public_id":{"type":"string"},"status":{"type":"string"},"title":{"type":["string","null"]}}},"GlobalEventStatsResponse":{"type":"object","required":["delivered","opened","clicked","bounced","complained"],"properties":{"bounce_rate":{"type":["number","null"],"format":"double"},"bounced":{"type":"integer","format":"int64","minimum":0},"click_rate":{"type":["number","null"],"format":"double"},"clicked":{"type":"integer","format":"int64","minimum":0},"complained":{"type":"integer","format":"int64","minimum":0},"delivered":{"type":"integer","format":"int64","minimum":0},"open_rate":{"type":["number","null"],"format":"double"},"opened":{"type":"integer","format":"int64","minimum":0}}},"GlobalMrrResponse":{"type":"object","required":["currency","current_mrr_minor","previous_mrr_minor"],"properties":{"change_percentage":{"type":["number","null"],"format":"double","description":"Percentage change vs 24h ago. Null when previous MRR is zero\n(no baseline to compare against)."},"currency":{"type":"string"},"current_mrr_minor":{"type":"integer","format":"int64"},"previous_mrr_minor":{"type":"integer","format":"int64","description":"MRR 24h before now, reconstructed from the event log."}}},"GlobalRecentEventResponse":{"type":"object","required":["id","project_id","project_name","occurred_at","event_type"],"properties":{"amount_minor":{"type":["integer","null"],"format":"int64"},"currency":{"type":["string","null"]},"customer_ref":{"type":["string","null"]},"event_type":{"type":"string"},"id":{"type":"integer","format":"int64"},"mrr_minor":{"type":["integer","null"],"format":"int64"},"occurred_at":{"type":"string","format":"date-time"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"}}},"GlobalRevenueSummaryResponse":{"type":"object","required":["currency","current_mrr_minor","paid_last_30d_minor","refunded_last_30d_minor","paid_all_time_minor","refunded_all_time_minor","active_subscriptions","active_customers","transactions_last_30d"],"properties":{"active_customers":{"type":"integer","format":"int64"},"active_subscriptions":{"type":"integer","format":"int64"},"currency":{"type":"string"},"current_mrr_minor":{"type":"integer","format":"int64"},"paid_all_time_minor":{"type":"integer","format":"int64"},"paid_last_30d_minor":{"type":"integer","format":"int64"},"refunded_all_time_minor":{"type":"integer","format":"int64"},"refunded_last_30d_minor":{"type":"integer","format":"int64"},"transactions_last_30d":{"type":"integer","format":"int64"}}},"GroupedPageMetric":{"type":"object","required":["group_key","events"],"properties":{"cls":{"type":["number","null"],"format":"float"},"country_code":{"type":["string","null"],"description":"ISO 3166-1 alpha-2 code of the group's country. Populated for the\ngeographic dimensions (country/region/city) so clients can match map\ngeometries without name-based lookups; null otherwise."},"events":{"type":"integer","format":"int64"},"fcp":{"type":["number","null"],"format":"float"},"group_key":{"type":"string"},"inp":{"type":["number","null"],"format":"float"},"lcp":{"type":["number","null"],"format":"float"},"ttfb":{"type":["number","null"],"format":"float"}}},"GroupedPageMetricsQuery":{"allOf":[{"$ref":"#/components/schemas/SpeedSegmentFilters","description":"Segment filters — same shape as `PerformanceMetricsQuery`."},{"type":"object","required":["start_date","end_date","project_id","group_by"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"device_type":{"type":["string","null"],"description":"Device type filter: \"desktop\" or \"mobile\""},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"group_by":{"type":"string"},"include_bots":{"type":["boolean","null"],"description":"Include crawler/datacenter (bot) samples. Defaults to false."},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}}]},"GroupedPageMetricsResponse":{"type":"object","required":["groups","total_events","grouped_by"],"properties":{"grouped_by":{"type":"string"},"groups":{"type":"array","items":{"$ref":"#/components/schemas/GroupedPageMetric"}},"total_events":{"type":"integer","format":"int64"}}},"HasAnalyticsEventsResponse":{"type":"object","required":["has_events"],"properties":{"has_events":{"type":"boolean"}}},"HasErrorGroupsResponse":{"type":"object","required":["has_error_groups"],"properties":{"has_error_groups":{"type":"boolean"}}},"HasEventsQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"HasEventsResponse":{"type":"object","required":["has_events"],"properties":{"has_events":{"type":"boolean"}}},"HasMetricsQuery":{"type":"object","required":["project_id"],"properties":{"project_id":{"type":"integer","format":"int32"}}},"HasMetricsResponse":{"type":"object","required":["has_metrics"],"properties":{"has_metrics":{"type":"boolean"}}},"HealthCheckConfiguration":{"type":"object","description":"Health check configuration","required":["port","interval","timeout","retries"],"properties":{"http_path":{"type":["string","null"],"description":"HTTP path to check (if applicable)"},"interval":{"type":"integer","format":"int32","description":"Interval between checks (seconds)","minimum":0},"port":{"type":"integer","format":"int32","description":"Port to check","minimum":0},"retries":{"type":"integer","format":"int32","description":"Number of retries before marking unhealthy","minimum":0},"timeout":{"type":"integer","format":"int32","description":"Timeout for each check (seconds)","minimum":0}}},"HealthCheckEntryResponse":{"type":"object","required":["checked_at","status"],"properties":{"checked_at":{"type":"string","description":"ISO 8601 timestamp of when the probe ran.","example":"2026-04-22T11:30:00Z"},"error_message":{"type":["string","null"],"description":"Present only when the probe failed or was degraded."},"response_time_ms":{"type":["integer","null"],"format":"int32","description":"TCP connect latency in milliseconds."},"status":{"type":"string","description":"\"operational\" | \"degraded\" | \"down\"","example":"operational"}}},"HealthResponse":{"type":"object","required":["summaries"],"properties":{"summaries":{"type":"array","items":{"$ref":"#/components/schemas/HealthSummary"}}}},"HealthStatus":{"type":"string","description":"Overall health status.","enum":["healthy","degraded","down","unknown"]},"HealthSummary":{"type":"object","description":"Pre-computed health summary for a project environment.","required":["project_id","service_name","status","uptime_pct","error_rate","p95_latency_ms","cpu_usage_pct","memory_usage_pct","computed_at"],"properties":{"computed_at":{"type":"string","format":"date-time"},"cpu_usage_pct":{"type":"number","format":"double"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_rate":{"type":"number","format":"double"},"last_deploy_at":{"type":["string","null"],"format":"date-time"},"last_deploy_id":{"type":["integer","null"],"format":"int32"},"memory_usage_pct":{"type":"number","format":"double"},"p95_latency_ms":{"type":"number","format":"double"},"project_id":{"type":"integer","format":"int32"},"service_name":{"type":"string"},"status":{"$ref":"#/components/schemas/HealthStatus"},"uptime_pct":{"type":"number","format":"double"}}},"HeartbeatApiRequest":{"type":"object","properties":{"architecture":{"type":["string","null"],"description":"Container platform of this node's Docker daemon (`linux/amd64`,\n`linux/arm64`), read from `docker info` by the agent. Absent from\npre-multi-arch agents; the stored value is then left untouched."},"capacity":{"description":"Resource capacity/usage info as JSON (cpu_usage, memory_usage, etc.)"},"containers":{"type":["array","null"],"items":{"$ref":"#/components/schemas/ContainerInventoryItem"},"description":"Container inventory for reconciliation (sent on first heartbeat after agent startup).\nEach entry has `container_id` and `container_name` of temps-managed containers."},"labels":{"description":"Updated node labels for scheduling (allows runtime label changes)."}}},"HeartbeatResponse":{"type":"object","required":["status","message"],"properties":{"message":{"type":"string"},"status":{"type":"string"}}},"HierarchyLevel":{"type":"object","description":"Describes a level in the data source hierarchy","required":["level","name","container_type","can_list_containers","can_list_entities"],"properties":{"can_list_containers":{"type":"boolean","description":"Can list containers at this level?","example":true},"can_list_entities":{"type":"boolean","description":"Can list entities at this level?","example":false},"container_type":{"type":"string","description":"Type of container at this level","example":"database"},"level":{"type":"integer","format":"int32","description":"Level number (0 = root)","example":0,"minimum":0},"name":{"type":"string","description":"Human-readable name for this level","example":"root"}}},"HistogramSummary":{"type":"object","description":"An explicit-bucket histogram aggregated over a time bucket.\n\nCarries the reduced scalars (count/sum/min/max) plus the explicit bucket\nlayout — `bounds` (the upper bounds) and `bucket_counts` (observation counts,\nsummed element-wise across the window; length is `bounds.len() + 1`, the last\nentry being the +Inf overflow bucket). With these, a caller can reconstruct\nany quantile (e.g. p95) via cumulative-count interpolation.","required":["count","sum","bounds","bucket_counts"],"properties":{"bounds":{"type":"array","items":{"type":"number","format":"double"},"description":"Explicit bucket upper bounds (OTLP `explicit_bounds`), ascending."},"bucket_counts":{"type":"array","items":{"type":"integer","format":"int64","minimum":0},"description":"Per-bucket observation counts summed element-wise across the window.\nLength is `bounds.len() + 1` (the trailing element is the +Inf bucket)."},"count":{"type":"integer","format":"int64","description":"Total observation count summed across the bucket window.","minimum":0},"max":{"type":["number","null"],"format":"double","description":"Maximum observed value, when reported by the producer."},"min":{"type":["number","null"],"format":"double","description":"Minimum observed value, when reported by the producer."},"sum":{"type":"number","format":"double","description":"Sum of observed values across the bucket window."}}},"HostnameChange":{"type":"object","description":"A single generated-hostname change in a flatten preview/apply.","required":["kind","id","old","new"],"properties":{"id":{"type":"integer","format":"int32","description":"Row id of the affected record."},"kind":{"type":"string","description":"`\"deployment\"` or `\"environment\"`."},"new":{"type":"string"},"old":{"type":"string"}}},"HostnamePreviewResponse":{"type":"object","description":"Combined preview of a hostname-mode change.","required":["hostname_changes","dns_changes","total"],"properties":{"dns_changes":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecordChange"}},"hostname_changes":{"type":"array","items":{"$ref":"#/components/schemas/HostnameChange"}},"total":{"type":"integer","minimum":0},"zone_access_ok":{"type":["boolean","null"],"description":"Whether the provider token can manage this zone (None if not checked)."}}},"HourlyPageSessions":{"type":"object","required":["timestamp","session_count","event_count","avg_duration_seconds"],"properties":{"avg_duration_seconds":{"type":"number","format":"double"},"event_count":{"type":"integer","format":"int64"},"session_count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"}}},"HourlyVisitsQuery":{"type":"object","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events (page views), sessions (unique sessions), or visitors (unique visitors)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"HttpChallengeDebugResponse":{"type":"object","required":["domain","challenge_exists","dns_a_records","dns_aaaa_records"],"properties":{"challenge_exists":{"type":"boolean"},"challenge_token":{"type":["string","null"]},"challenge_url":{"type":["string","null"],"description":"The full URL that Let's Encrypt will try to access to validate the challenge"},"dns_a_records":{"type":"array","items":{"type":"string"},"description":"IPv4 addresses the domain points to"},"dns_aaaa_records":{"type":"array","items":{"type":"string"},"description":"IPv6 addresses the domain points to"},"dns_error":{"type":["string","null"],"description":"Any DNS resolution errors"},"domain":{"type":"string"},"validation_url":{"type":["string","null"],"description":"The ACME validation URL (internal to ACME protocol)"}}},"ImportCredentials":{"type":"object","description":"Platform-specific credentials for accessing the source system.\n\nFor platforms like Vercel and Railway, this contains the API token.\nFor self-hosted platforms like Coolify and Dokploy, this also contains\nthe `base_url` of the instance.\n\nLocal importers (Docker) can use `ImportCredentials::none()`.","properties":{"base_url":{"type":["string","null"],"description":"Base URL override (for self-hosted platforms like Coolify, Dokploy)\n\nExample: `https://coolify.example.com`"},"extra":{"type":"object","description":"Additional platform-specific parameters","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"team_id":{"type":["string","null"],"description":"Team or organization ID (for platforms with team scoping like Vercel)"},"token":{"type":["string","null"],"description":"API token / bearer token for the source platform"}}},"ImportExecutionStatus":{"type":"string","description":"Import execution status","enum":["pending","inprogress","completed","failed"]},"ImportExternalServiceRequest":{"type":"object","description":"Request to import a Docker container as a managed service","required":["name","service_type","parameters","container_id"],"properties":{"container_id":{"type":"string","description":"Container ID or name to import","example":"abc123def456"},"name":{"type":"string","description":"Name to register the service as in Temps","example":"production-database"},"parameters":{"type":"object","description":"Service configuration parameters","additionalProperties":{},"propertyNames":{"type":"string"}},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute","description":"Service type"},"version":{"type":["string","null"],"description":"Optional version override"}}},"ImportOutcomeResponse":{"type":"object","required":["rows_read","inserted","updated","skipped_stale","skipped_invalid","errors"],"properties":{"errors":{"type":"array","items":{"$ref":"#/components/schemas/ImportRowErrorResponse"}},"inserted":{"type":"integer","minimum":0},"rows_read":{"type":"integer","minimum":0},"skipped_invalid":{"type":"integer","minimum":0},"skipped_stale":{"type":"integer","minimum":0},"updated":{"type":"integer","minimum":0}}},"ImportPlan":{"type":"object","description":"Complete import plan describing all operations to onboard a workload.\n\nThe plan is generated from a snapshot and presented to the user for review\nbefore any resources are created. Users can modify individual items\n(skip services, change actions) before approving execution.","required":["version","source","source_id","project","environment","deployment","summary","metadata"],"properties":{"additional_deployments":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentConfiguration"},"description":"Additional deployments (workers, cron jobs, etc.)"},"cost_analysis":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/CostAnalysis","description":"Cost, overprovisioning, and savings analysis. Populated by importers\nthat can observe the whole source cluster (currently Kubernetes);\n`None` for container/platform imports."}]},"deployment":{"$ref":"#/components/schemas/DeploymentConfiguration","description":"Primary deployment configuration"},"domains":{"type":"array","items":{"$ref":"#/components/schemas/DomainPlan"},"description":"Custom domains to migrate"},"environment":{"$ref":"#/components/schemas/EnvironmentConfiguration","description":"Environment configuration"},"metadata":{"$ref":"#/components/schemas/PlanMetadata","description":"Plan metadata"},"project":{"$ref":"#/components/schemas/ProjectConfiguration","description":"Project configuration"},"services":{"type":"array","items":{"$ref":"#/components/schemas/ServicePlan"},"description":"Services to migrate (databases, caches, blob stores)\n\nEach service has an `action` field the user can change before execution."},"source":{"type":"string","description":"Source system this plan was generated from"},"source_id":{"type":"string","description":"Source workload / project ID in the source system"},"steps":{"type":"array","items":{"$ref":"#/components/schemas/MigrationStep"},"description":"Ordered list of migration steps that will be executed.\n\nThis is the human-readable execution plan. Each step describes what\nwill happen, what risks are involved, and what the user should verify.\nSteps are executed in order. If a step fails, execution stops and\nalready-created resources are reported for manual cleanup."},"summary":{"$ref":"#/components/schemas/MigrationSummary","description":"Human-readable summary of the entire migration"},"version":{"type":"string","description":"Plan version for compatibility tracking"}}},"ImportRowErrorResponse":{"type":"object","required":["row","reason"],"properties":{"reason":{"type":"string"},"row":{"type":"integer","minimum":0}}},"ImportSelector":{"type":"object","description":"Selector for discovering workloads","properties":{"label_filter":{"type":["object","null"],"description":"Filter by labels/tags","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"limit":{"type":["integer","null"],"description":"Limit number of results","minimum":0},"name_pattern":{"type":["string","null"],"description":"Filter by name pattern (glob/regex)"},"status_filter":{"type":["array","null"],"items":{"type":"string"},"description":"Filter by status (running, stopped, deployed, etc.)"},"workload_type_filter":{"type":["array","null"],"items":{"type":"string"},"description":"Filter by workload type (container, function, static-site, etc.)"}}},"ImportSource":{"type":"string","description":"Import source identifier","enum":["docker","coolify","dokploy","vercel","netlify","railway","render","fly","kubernetes","caprover","portainer","kamal","custom"]},"ImportSourceCapabilities":{"type":"object","description":"Source capabilities","required":["supports_volumes","supports_networks","supports_health_checks","supports_resource_limits","supports_build","supports_services","supports_domains","supports_project_snapshot","supports_cost_analysis","requires_credentials"],"properties":{"requires_credentials":{"type":"boolean","description":"Whether this source requires API credentials (token, base URL)"},"supports_build":{"type":"boolean"},"supports_cost_analysis":{"type":"boolean","description":"Supports cluster cost + overprovisioning analysis in the plan"},"supports_domains":{"type":"boolean","description":"Supports custom domain migration"},"supports_health_checks":{"type":"boolean"},"supports_networks":{"type":"boolean"},"supports_project_snapshot":{"type":"boolean","description":"Supports full project-level snapshots"},"supports_resource_limits":{"type":"boolean"},"supports_services":{"type":"boolean","description":"Supports service migration (databases, caches, etc.)"},"supports_volumes":{"type":"boolean"}}},"ImportSourceInfo":{"type":"object","description":"Information about an import source","required":["source","name","version","available","capabilities"],"properties":{"available":{"type":"boolean","description":"Whether the source is currently available"},"capabilities":{"$ref":"#/components/schemas/ImportSourceCapabilities","description":"Capabilities"},"name":{"type":"string","description":"Human-readable name"},"source":{"$ref":"#/components/schemas/ImportSource","description":"Source identifier"},"version":{"type":"string","description":"Source version"}}},"ImportStatusResponse":{"type":"object","description":"Response with import status","required":["session_id","status","errors","warnings","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","description":"Created at timestamp"},"deployment_id":{"type":["integer","null"],"format":"int32","description":"Created deployment ID"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Created environment ID"},"errors":{"type":"array","items":{"type":"string"},"description":"Errors (if any)"},"plan":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ImportPlan","description":"Import plan"}]},"project_id":{"type":["integer","null"],"format":"int32","description":"Created project ID"},"session_id":{"type":"string","description":"Session ID"},"status":{"$ref":"#/components/schemas/ImportExecutionStatus","description":"Current status"},"updated_at":{"type":"string","format":"date-time","description":"Updated at timestamp"},"validation":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ValidationReport","description":"Validation report"}]},"warnings":{"type":"array","items":{"type":"string"},"description":"Warnings (if any)"}}},"IncidentBucket":{"type":"object","required":["bucket_start","total_incidents","minor_incidents","major_incidents","critical_incidents","resolved_incidents","active_incidents"],"properties":{"active_incidents":{"type":"integer","format":"int64"},"avg_resolution_time_minutes":{"type":["number","null"],"format":"double"},"bucket_start":{"type":"string","format":"date-time"},"critical_incidents":{"type":"integer","format":"int64"},"major_incidents":{"type":"integer","format":"int64"},"minor_incidents":{"type":"integer","format":"int64"},"resolved_incidents":{"type":"integer","format":"int64"},"total_incidents":{"type":"integer","format":"int64"}}},"IncidentBucketedResponse":{"type":"object","required":["project_id","interval","buckets"],"properties":{"buckets":{"type":"array","items":{"$ref":"#/components/schemas/IncidentBucket"}},"environment_id":{"type":["integer","null"],"format":"int32"},"interval":{"type":"string"},"project_id":{"type":"integer","format":"int32"}}},"IncidentResponse":{"type":"object","required":["id","project_id","title","severity","status","started_at","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time"},"description":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"monitor_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"resolved_at":{"type":["string","null"],"format":"date-time"},"severity":{"type":"string"},"started_at":{"type":"string","format":"date-time"},"status":{"type":"string"},"title":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}},"IncidentUpdateResponse":{"type":"object","required":["id","incident_id","status","message","created_at"],"properties":{"created_at":{"type":"string","format":"date-time"},"id":{"type":"integer","format":"int32"},"incident_id":{"type":"integer","format":"int32"},"message":{"type":"string"},"status":{"type":"string"}}},"IncrRequest":{"type":"object","description":"Request to increment a value","required":["key"],"properties":{"amount":{"type":["integer","null"],"format":"int64","description":"Amount to increment by (default: 1)"},"key":{"type":"string","description":"The key to increment","example":"counter"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"IncrResponse":{"type":"object","description":"Response for increment operation","required":["value"],"properties":{"value":{"type":"integer","format":"int64","description":"New value after increment","example":42}}},"InitAuthResponse":{"type":"object","required":["auth_url","session_token"],"properties":{"auth_url":{"type":"string"},"session_token":{"type":"string"}}},"Insight":{"type":"object","description":"An anomaly insight.","required":["id","project_id","service_name","severity","status","title","description","anomaly_ids","started_at","created_at","updated_at"],"properties":{"anomaly_ids":{"type":"array","items":{"type":"integer","format":"int64"}},"correlated_deploy_id":{"type":["integer","null"],"format":"int32"},"created_at":{"type":"string","format":"date-time"},"description":{"type":"string"},"environment":{"type":["string","null"]},"id":{"type":"integer","format":"int64"},"metric_name":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"resolved_at":{"type":["string","null"],"format":"date-time"},"service_name":{"type":"string"},"severity":{"$ref":"#/components/schemas/InsightSeverity"},"started_at":{"type":"string","format":"date-time"},"status":{"$ref":"#/components/schemas/InsightStatus"},"title":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}},"InsightSeverity":{"type":"string","description":"Severity of an anomaly insight.","enum":["low","medium","high","critical"]},"InsightStatus":{"type":"string","description":"Status of an insight.","enum":["active","resolved"]},"InsightsResponse":{"type":"object","required":["data","count"],"properties":{"count":{"type":"integer","minimum":0},"data":{"type":"array","items":{"$ref":"#/components/schemas/Insight"}}}},"IntegrationResponse":{"type":"object","required":["id","project_id","provider","webhook_path_token","webhook_path","status","has_secret","created_at"],"properties":{"config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ProviderConfig","description":"Typed provider config — allowlist and metered-billing mode. Null\nwhen the operator hasn't configured one yet (accept everything)."}]},"created_at":{"type":"string","format":"date-time"},"has_secret":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"last_event_at":{"type":["string","null"],"format":"date-time"},"project_id":{"type":"integer","format":"int32"},"provider":{"type":"string"},"status":{"type":"string"},"webhook_path":{"type":"string","description":"Relative path the UI can display and copy. The frontend builds\nthe full URL by prefixing its own origin."},"webhook_path_token":{"type":"string","description":"Unguessable token embedded in the public webhook URL. The full\nURL is `{api_origin}/webhooks/revenue/{provider}/{webhook_path_token}`."}}},"IpAccessControlQuery":{"type":"object","description":"Query parameters for listing IP access control rules","properties":{"action":{"type":["string","null"],"description":"Filter by action (\"block\" or \"allow\")"}}},"IpAccessControlResponse":{"type":"object","description":"Response model for IP access control rules","required":["id","ip_address","action","created_at","updated_at"],"properties":{"action":{"type":"string"},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609Z"},"created_by":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":"string"},"reason":{"type":["string","null"]},"updated_at":{"type":"string","example":"2025-10-12T12:15:47.609Z"}}},"JobStatusResponse":{"type":"object","description":"Snapshot of a background job. `status` is one of \"running\" | \"exited\"\n| \"failed\"; `exit_code` is populated only when `status == \"exited\"`.","required":["status","stdout","stderr"],"properties":{"exit_code":{"type":["integer","null"],"format":"int32"},"reason":{"type":["string","null"]},"status":{"type":"string"},"stderr":{"type":"string"},"stdout":{"type":"string"}}},"JobSummaryResponse":{"type":"object","description":"Row in the jobs list. Omits stdout/stderr so a noisy dev server doesn't\nbloat the list payload — callers drill into `GET /jobs/{id}` for the\nfull buffer.","required":["id","status","cmd","started_at"],"properties":{"cmd":{"type":"string"},"exit_code":{"type":["integer","null"],"format":"int32"},"id":{"type":"string"},"reason":{"type":["string","null"]},"started_at":{"type":"string"},"status":{"type":"string"}}},"JoinTokenStatusResponse":{"type":"object","description":"Response for join token status check","required":["has_token"],"properties":{"has_token":{"type":"boolean","description":"Whether a join token has been configured"}}},"JourneyEvent":{"type":"object","description":"A single event in the visitor journey timeline","required":["id","event_type","event_name","occurred_at","is_entry","is_exit","is_bounce"],"properties":{"event_data":{"description":"Custom event properties (for custom events)"},"event_name":{"type":"string","description":"Resolved event name (event_name for custom events, event_type for system events)"},"event_type":{"type":"string","description":"Event type: \"page_view\", \"page_leave\", \"custom\", \"web_vitals\""},"id":{"type":"integer","format":"int64","description":"Event ID"},"is_bounce":{"type":"boolean","description":"Whether this was a bounce"},"is_entry":{"type":"boolean","description":"Whether this is the entry page of the session"},"is_exit":{"type":"boolean","description":"Whether this is the exit page of the session"},"occurred_at":{"type":"string","format":"date-time","description":"When the event occurred"},"page_path":{"type":["string","null"],"description":"Page path where the event happened"},"page_title":{"type":["string","null"],"description":"Page title (if available)"},"referrer":{"type":["string","null"],"description":"Referrer URL for this event"},"scroll_depth":{"type":["integer","null"],"format":"int32","description":"Scroll depth percentage (0-100)"},"session_page_number":{"type":["integer","null"],"format":"int32","description":"Page number within the session (1-indexed)"},"time_on_page":{"type":["integer","null"],"format":"int32","description":"Time spent on page in seconds (computed, not from column)"}}},"JourneySession":{"type":"object","description":"A session within the visitor journey, grouping events","required":["session_id","started_at","duration_seconds","page_views","events_count","is_bounced","is_engaged","events"],"properties":{"channel":{"type":["string","null"],"description":"Traffic source: channel (e.g. \"organic\", \"direct\", \"social\")"},"duration_seconds":{"type":"integer","format":"int64","description":"Session duration in seconds"},"ended_at":{"type":["string","null"],"format":"date-time","description":"When the session ended"},"entry_path":{"type":["string","null"],"description":"Entry page path"},"events":{"type":"array","items":{"$ref":"#/components/schemas/JourneyEvent"},"description":"Events within this session, ordered chronologically"},"events_count":{"type":"integer","format":"int64","description":"Total events in this session"},"exit_path":{"type":["string","null"],"description":"Exit page path"},"is_bounced":{"type":"boolean","description":"Whether the session was a bounce"},"is_engaged":{"type":"boolean","description":"Whether the visitor was engaged (had non-pageview events)"},"page_views":{"type":"integer","format":"int64","description":"Number of page views in this session"},"referrer":{"type":["string","null"],"description":"Traffic source: referrer URL"},"referrer_hostname":{"type":["string","null"],"description":"Traffic source: referrer hostname"},"session_id":{"type":"integer","format":"int32","description":"Session internal ID"},"started_at":{"type":"string","format":"date-time","description":"When the session started"},"utm_campaign":{"type":["string","null"],"description":"UTM campaign parameter"},"utm_medium":{"type":["string","null"],"description":"UTM medium parameter"},"utm_source":{"type":["string","null"],"description":"UTM source parameter"}}},"KeysRequest":{"type":"object","description":"Request to get keys matching a pattern","required":["pattern"],"properties":{"pattern":{"type":"string","description":"Pattern to match (supports * and ? wildcards)","example":"user:*"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"KeysResponse":{"type":"object","description":"Response for keys operation","required":["keys"],"properties":{"keys":{"type":"array","items":{"type":"string"},"description":"List of matching keys","example":["user:1","user:2","user:3"]}}},"KillJobBody":{"type":"object","properties":{"force":{"type":"boolean","description":"When true, sends SIGKILL immediately. Defaults to SIGTERM so the\nprocess gets a chance to flush (mirrors `Command.kill()` in\n`@vercel/sandbox`, which also accepts a signal override)."}},"additionalProperties":false},"KnownAiAgentsResponse":{"type":"object","description":"Response listing every AI agent the detector knows about.","required":["items"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AiAgentDescriptor"}}}},"KvStatusResponse":{"type":"object","description":"Response for KV service status","required":["enabled","healthy"],"properties":{"docker_image":{"type":["string","null"],"description":"Docker image being used","example":"gotempsh/redis-walg:8-bookworm"},"enabled":{"type":"boolean","description":"Whether the KV service is enabled"},"healthy":{"type":"boolean","description":"Whether the underlying Redis service is healthy"},"version":{"type":["string","null"],"description":"Service version","example":"7.2"}}},"LemonSqueezyConfig":{"type":"object","properties":{"product_allowlist":{"type":"array","items":{"type":"string"}},"variant_allowlist":{"type":"array","items":{"type":"string"}}}},"LetsEncryptSettings":{"type":"object","properties":{"email":{"type":["string","null"],"default":null},"environment":{"type":"string","default":"production"}}},"LineContext":{"type":"object","description":"Raw surrounding lines for a single match (grep -C style).","required":["before","after"],"properties":{"after":{"type":"array","items":{"$ref":"#/components/schemas/ContextLine"},"description":"Lines immediately after the match, oldest-first."},"before":{"type":"array","items":{"$ref":"#/components/schemas/ContextLine"},"description":"Lines immediately before the match, oldest-first."}}},"LinkServiceRequest":{"type":"object","required":["project_id"],"properties":{"project_id":{"type":"integer","format":"int32"}}},"ListAgentsResponse":{"type":"object","required":["items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AgentConfigResponse"}},"total":{"type":"integer","minimum":0}}},"ListApiKeysQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","minimum":0},"page_size":{"type":["integer","null"],"format":"int64","minimum":0}}},"ListAuditLogsQuery":{"type":"object","description":"Query parameters for listing audit logs.\n\nEvery field is optional — omitting one means \"don't filter on it\". Deriving\n`IntoParams` makes utoipa render them as optional query params with the\ncorrect types; the previous hand-written `params((\"operation_type\", Query,\n…))` tuples defaulted every param to `required: true, type: string`, which\nmisled both API clients and the AI `describe_api`/`call_api` tools into\nthinking all filters were mandatory.","properties":{"from":{"type":["string","null"],"format":"date-time","description":"Start timestamp (milliseconds since epoch)"},"limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of logs to return"},"offset":{"type":["integer","null"],"format":"int32","description":"Number of logs to skip"},"operation_type":{"type":["string","null"],"description":"Filter logs by operation type (omit for all)"},"to":{"type":["string","null"],"format":"date-time","description":"End timestamp (milliseconds since epoch)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter logs by user ID (omit for all users)"}}},"ListBlobsQuery":{"type":"object","description":"Query parameters for listing blobs","properties":{"cursor":{"type":["string","null"],"description":"Continuation token for pagination"},"limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of items to return","example":100},"prefix":{"type":["string","null"],"description":"Prefix to filter by","example":"images/"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"ListBlobsResponse":{"type":"object","description":"Response for listing blobs","required":["blobs","hasMore"],"properties":{"blobs":{"type":"array","items":{"$ref":"#/components/schemas/BlobResponse"},"description":"List of blobs"},"cursor":{"type":["string","null"],"description":"Continuation token for next page"},"hasMore":{"type":"boolean","description":"Whether there are more results","example":false}}},"ListCustomDomainsResponse":{"type":"object","required":["domains","total"],"properties":{"domains":{"type":"array","items":{"$ref":"#/components/schemas/CustomDomainResponse"}},"total":{"type":"integer","minimum":0}}},"ListDeploymentTokensQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","example":1,"minimum":0},"page_size":{"type":["integer","null"],"format":"int64","example":20,"minimum":0}}},"ListDomainsResponse":{"type":"object","required":["domains","total","page","page_size"],"properties":{"domains":{"type":"array","items":{"$ref":"#/components/schemas/DomainResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"ListEntitiesQuery":{"type":"object","properties":{"limit":{"type":"integer","description":"Maximum number of entities to return","example":100,"minimum":0},"token":{"type":["string","null"],"description":"Continuation token for pagination (backend-specific)"}}},"ListErrorEventsQuery":{"type":"object","properties":{"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0}}},"ListErrorGroupsQuery":{"type":"object","properties":{"end_date":{"type":["string","null"],"format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"sort_by":{"type":["string","null"]},"sort_order":{"type":"string"},"start_date":{"type":["string","null"],"format":"date-time"},"status":{"type":["string","null"]}}},"ListJobsResponse":{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/JobSummaryResponse"}}}},"ListMcpsResponse":{"type":"object","description":"Concrete list wrapper for MCP server definitions (utoipa requires non-generic types).","required":["items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/McpDefinitionResponse"}},"total":{"type":"integer","minimum":0}}},"ListOnDemandCertsResponse":{"type":"object","description":"Paginated list of on-demand cert attempts (ADR-018 §5 console \"Certificates\"\nsurface). Joined with current `domains.status`, newest first.","required":["certs","total","page","page_size"],"properties":{"certs":{"type":"array","items":{"$ref":"#/components/schemas/OnDemandCertRow"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"ListOrdersResponse":{"type":"object","required":["orders"],"properties":{"orders":{"type":"array","items":{"$ref":"#/components/schemas/AcmeOrderResponse"}}}},"ListPresetsResponse":{"type":"object","required":["presets","total"],"properties":{"presets":{"type":"array","items":{"$ref":"#/components/schemas/PresetResponse"}},"total":{"type":"integer","minimum":0}}},"ListRunsResponse":{"type":"object","required":["items","total","page","page_size"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AgentRunResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"ListSandboxesResponse":{"type":"object","description":"SDK list response: `{ sandboxes: [...], pagination: {...} }`.","required":["sandboxes","pagination"],"properties":{"pagination":{"$ref":"#/components/schemas/Pagination"},"sandboxes":{"type":"array","items":{"$ref":"#/components/schemas/SandboxInner"}}}},"ListScansQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","example":1,"minimum":0},"page_size":{"type":["integer","null"],"format":"int64","example":20,"minimum":0}}},"ListSecretsResponse":{"type":"object","required":["items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/SecretResponse"}},"total":{"type":"integer","minimum":0}}},"ListSkillsResponse":{"type":"object","description":"Concrete list wrapper for skill definitions (utoipa requires non-generic types).","required":["items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/SkillDefinitionResponse"}},"total":{"type":"integer","minimum":0}}},"ListTagsResponse":{"type":"object","description":"Response for listing tags","required":["tags","total"],"properties":{"tags":{"type":"array","items":{"type":"string"},"description":"List of available tags"},"total":{"type":"integer","description":"Total number of tags","minimum":0}}},"ListTemplatesQuery":{"type":"object","description":"Query parameters for listing templates","properties":{"featured":{"type":["boolean","null"],"description":"Only return featured templates"},"tag":{"type":["string","null"],"description":"Filter templates by tag"}}},"ListTemplatesResponse":{"type":"object","description":"Response for listing templates","required":["templates","total"],"properties":{"templates":{"type":"array","items":{"$ref":"#/components/schemas/TemplateResponse"},"description":"List of templates"},"total":{"type":"integer","description":"Total number of templates","minimum":0}}},"ListVulnerabilitiesQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","example":1,"minimum":0},"page_size":{"type":["integer","null"],"format":"int64","example":20,"minimum":0},"severity":{"type":["string","null"],"example":"CRITICAL"}}},"LiveVisitorInfo":{"type":"object","required":["id","visitor_id","project_id","environment_id","first_seen","last_seen","is_crawler"],"properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"crawler_name":{"type":["string","null"]},"current_page":{"type":["string","null"],"description":"Most recent page path visited by this visitor"},"custom_data":{},"environment_id":{"type":"integer","format":"int32"},"first_channel":{"type":["string","null"],"description":"Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")"},"first_referrer":{"type":["string","null"],"description":"Full referrer URL from the visitor's first session"},"first_referrer_hostname":{"type":["string","null"],"description":"Hostname extracted from first_referrer"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":["string","null"]},"ip_address_id":{"type":["integer","null"],"format":"int32"},"is_crawler":{"type":"boolean"},"is_eu":{"type":["boolean","null"]},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"latitude":{"type":["number","null"],"format":"double"},"longitude":{"type":["number","null"],"format":"double"},"project_id":{"type":"integer","format":"int32"},"region":{"type":["string","null"]},"timezone":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":"string"}}},"LiveVisitorsListResponse":{"type":"object","required":["total_count","visitors","window_minutes"],"properties":{"total_count":{"type":"integer","format":"int64"},"visitors":{"type":"array","items":{"$ref":"#/components/schemas/LiveVisitorInfo"}},"window_minutes":{"type":"integer","format":"int32"}}},"LocationCount":{"type":"object","required":["location","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"location":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"LocationGranularity":{"type":"string","enum":["country","region","city"]},"LocationInfo":{"type":"object","properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"region":{"type":["string","null"]}}},"LogLevel":{"type":"string","description":"Normalized log level","enum":["TRACE","DEBUG","INFO","WARN","ERROR"]},"LogRecord":{"type":"object","description":"A single log record ready for storage.","required":["project_id","resource","timestamp","observed_timestamp","severity","severity_text","body","attributes"],"properties":{"attributes":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"body":{"type":"string"},"deployment_id":{"type":["integer","null"],"format":"int32"},"observed_timestamp":{"type":"string","format":"date-time"},"project_id":{"type":"integer","format":"int32"},"resource":{"$ref":"#/components/schemas/ResourceInfo"},"severity":{"$ref":"#/components/schemas/LogSeverity"},"severity_text":{"type":"string"},"span_id":{"type":["string","null"]},"timestamp":{"type":"string","format":"date-time"},"trace_id":{"type":["string","null"]}}},"LogSearchLine":{"type":"object","description":"A single line in search results","required":["timestamp","level","service","message","chunk_id","line_offset"],"properties":{"chunk_id":{"type":"string"},"container_id":{"type":"string","description":"Container this line came from — lets the UI tag/group lines by container\nin a combined (\"show all\") multi-container view."},"context":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/LineContext","description":"Raw surrounding lines (grep -C). `None` unless `context_lines > 0` was\nrequested. Overlapping windows between nearby matches are merged: the\nshared neighbors appear on the earlier match only, so the frontend can\nrender one continuous block without duplicated lines."}]},"deploy_id":{"type":["integer","null"],"format":"int32"},"fields":{},"level":{"$ref":"#/components/schemas/LogLevel"},"line_offset":{"type":"integer","format":"int32"},"message":{"type":"string"},"node_id":{"type":["integer","null"],"format":"int32","description":"Worker node the line came from (`None` = control-plane-local)."},"node_name":{"type":["string","null"],"description":"Human-readable node name for display."},"service":{"type":"string"},"timestamp":{"type":"string"}}},"LogSeverity":{"type":"string","description":"Log severity level (simplified from OTel's 24 levels).","enum":["TRACE","DEBUG","INFO","WARN","ERROR","FATAL"]},"LogSource":{"type":"object","description":"A distinct log source (container) seen in the queried scope. Used to populate\nthe history filter dropdowns with the *full* set of containers/nodes for the\nproject + env + deployment + time window — independent of the active\ncontainer/node/service filter, so the user can switch between them.","required":["container_id","service"],"properties":{"container_id":{"type":"string"},"node_id":{"type":["integer","null"],"format":"int32"},"node_name":{"type":["string","null"]},"service":{"type":"string"}}},"LogStream":{"type":"string","description":"Log output stream","enum":["stdout","stderr"]},"LoginRequest":{"type":"object","required":["email","password"],"properties":{"email":{"type":"string"},"password":{"type":"string"}}},"LogsQuery":{"type":"object","properties":{"tail":{"type":["integer","null"],"description":"Number of lines to return from the tail. Defaults to 200, capped at 2000.","minimum":0}}},"LogsResponse":{"type":"object","required":["data","count"],"properties":{"count":{"type":"integer","minimum":0},"data":{"type":"array","items":{"$ref":"#/components/schemas/LogRecord"}}}},"ManagedDomainResponse":{"type":"object","description":"Managed domain response","required":["id","provider_id","domain","auto_manage","verified","generated_hostname_mode","sync_generated_records","created_at","updated_at"],"properties":{"auto_manage":{"type":"boolean"},"created_at":{"type":"string"},"domain":{"type":"string"},"generated_hostname_mode":{"type":"string","description":"Generated hostname layout: `\"standard\"` or `\"flat\"`."},"id":{"type":"integer","format":"int32"},"provider_id":{"type":"integer","format":"int32"},"sync_generated_records":{"type":"boolean","description":"Whether generated hostnames are reconciled into the provider's DNS zone."},"updated_at":{"type":"string"},"verification_error":{"type":["string","null"]},"verified":{"type":"boolean"},"verified_at":{"type":["string","null"]},"zone_access_error":{"type":["string","null"],"description":"Detail for a failed zone-access check."},"zone_access_ok":{"type":["boolean","null"],"description":"Last token zone-access check: `Some(true)`/`Some(false)`/`None` (unchecked)."},"zone_id":{"type":["string","null"]}}},"ManualAction":{"type":"object","description":"A manual action the user must perform outside of the automated migration","required":["timing","description","reason"],"properties":{"description":{"type":"string","description":"Human-readable description"},"reason":{"type":"string","description":"Why this can't be automated"},"timing":{"$ref":"#/components/schemas/ManualActionTiming","description":"When this action needs to happen"}}},"ManualActionTiming":{"type":"string","description":"When a manual action needs to happen relative to migration","enum":["before-migration","after-migration","within-hours"]},"McpDefinitionResponse":{"type":"object","required":["id","slug","name","config","created_at","updated_at"],"properties":{"config":{"type":"object"},"created_at":{"type":"string"},"description":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"project_id":{"type":["integer","null"],"format":"int32"},"slug":{"type":"string"},"updated_at":{"type":"string"}}},"MessageContent":{"oneOf":[{"type":"string"},{"type":"array","items":{"$ref":"#/components/schemas/ContentPart"}}]},"MessagePart":{"oneOf":[{"type":"object","required":["text","type"],"properties":{"text":{"type":"string"},"type":{"type":"string","enum":["text"]}}},{"type":"object","required":["tool","type"],"properties":{"tool":{"$ref":"#/components/schemas/ToolInfo"},"type":{"type":"string","enum":["tool"]}}}],"description":"One ordered segment of an assistant turn: a chunk of prose, or a tool\ninvocation. Mirrors the `metadata.parts` persisted by the chat service."},"MessageResponse":{"type":"object","required":["role","content","created_at"],"properties":{"content":{"type":"string"},"created_at":{"type":"string"},"parts":{"type":["array","null"],"items":{"$ref":"#/components/schemas/MessagePart"},"description":"Ordered render segments (text / tool, in the order they occurred) so a\nreloaded chat shows the same interleaving as the live stream. Absent for\nolder messages persisted before parts were tracked; the client then falls\nback to `tools` (rendered first) + `content`."},"role":{"type":"string"},"tools":{"type":["array","null"],"items":{"$ref":"#/components/schemas/ToolInfo"},"description":"Tools the assistant ran on this turn (persisted in message metadata), so\nthe chat replays its tool work after a reload. Absent for plain turns."}}},"MeteredMode":{"type":"string","description":"How to treat metered-billing subscriptions when computing MRR.\n\n* `DeriveFromInvoices` (default): ignore the subscription row's\n `mrr_minor` for metered items and rely on the per-invoice\n [`NormalizedEventType::MrrRealized`] events instead. Correct for\n pure-metered, hybrid, tiered, and flat — recommended.\n* `UseSubscription`: trust whatever MRR the subscription parser\n returns (0 for metered). Legacy behavior.\n* `Ignore`: drop metered subscriptions from MRR entirely.","enum":["derive_from_invoices","use_subscription","ignore"]},"MetricAggregation":{"oneOf":[{"type":"string","description":"Arithmetic mean of the scalar value in each bucket. The default.","enum":["avg"]},{"type":"string","description":"Sum of the scalar value in each bucket.","enum":["sum"]},{"type":"string","description":"Minimum scalar value in each bucket.","enum":["min"]},{"type":"string","description":"Maximum scalar value in each bucket.","enum":["max"]},{"type":"string","description":"Number of points in each bucket.","enum":["count"]},{"type":"string","description":"Per-second rate of change of a cumulative monotonic counter, computed as\n`(max - min) / window_seconds` within each bucket. Non-monotonic series\nfall back to a simple delta.","enum":["rate_per_sec"]},{"type":"object","description":"A quantile of the scalar value in each bucket. The carried `f64` is the\nrequested quantile in `[0.0, 1.0]`.","required":["quantile"],"properties":{"quantile":{"type":"number","format":"double","description":"A quantile of the scalar value in each bucket. The carried `f64` is the\nrequested quantile in `[0.0, 1.0]`."}}}],"description":"The aggregation applied when reducing raw metric points into a time bucket.\n\nStore-neutral: every storage backend (ClickHouse today, TimescaleDB later)\nmust be able to satisfy this contract. `Quantile(q)` carries the requested\nquantile in `[0.0, 1.0]` (e.g. `0.95` for p95)."},"MetricBucket":{"type":"object","description":"A time-bucketed metric aggregate for chart display.\n\nStore-neutral response contract. The legacy scalar fields\n(`avg_value`/`min_value`/`max_value`/`count`) are always populated for chart\nback-compat. The richer fields describe the explicitly-requested\n[`MetricAggregation`] (`value`), optional `quantiles`, an optional\n`histogram_summary`, and a `series_key` identifying the label-set when the\nquery used `group_by`.","required":["bucket","avg_value","min_value","max_value","count"],"properties":{"avg_value":{"type":"number","format":"double"},"bucket":{"type":"string","format":"date-time"},"count":{"type":"integer","format":"int64"},"histogram_summary":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/HistogramSummary","description":"A reduced histogram summary when the bucketed metric is a histogram."}]},"max_value":{"type":"number","format":"double"},"min_value":{"type":"number","format":"double"},"quantiles":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"number","format":"double"},{"type":"number","format":"double"}]},"description":"Computed quantile/value pairs `(quantile, value)` when the query asked for\nquantile aggregation; otherwise empty."},"series_key":{"type":["array","null"],"items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"The label-set this bucket belongs to, as ordered `(key, value)` pairs,\nwhen the query grouped by labels. Empty/`None` = the single ungrouped\naggregate stream."},"value":{"type":"number","format":"double","description":"The value of the requested [`MetricAggregation`] for this bucket. For the\ndefault `Avg` aggregation this equals `avg_value`. `#[serde(default)]` so\npre-existing payloads (which only carried avg/min/max/count) still parse."}}},"MetricDataPoint":{"type":"object","description":"A single `(timestamp, value)` data point in a metric series.","required":["time","value"],"properties":{"time":{"type":"string","description":"ISO 8601 timestamp with `Z` suffix."},"value":{"type":"number","format":"double","description":"Metric value at this bucket."}}},"MetricType":{"type":"string","description":"The type of an OTel metric.","enum":["gauge","sum","histogram","exponential_histogram","summary"]},"MetricsOverTimeResponse":{"type":"object","required":["timestamps","ttfb","lcp","fid","fcp","cls","inp"],"properties":{"cls":{"type":"array","items":{"type":["number","null"],"format":"float"}},"cls_p75":{"type":["number","null"],"format":"float"},"cls_p90":{"type":["number","null"],"format":"float"},"cls_p95":{"type":["number","null"],"format":"float"},"cls_p99":{"type":["number","null"],"format":"float"},"fcp":{"type":"array","items":{"type":["number","null"],"format":"float"}},"fcp_p75":{"type":["number","null"],"format":"float"},"fcp_p90":{"type":["number","null"],"format":"float"},"fcp_p95":{"type":["number","null"],"format":"float"},"fcp_p99":{"type":["number","null"],"format":"float"},"fid":{"type":"array","items":{"type":["number","null"],"format":"float"}},"fid_p75":{"type":["number","null"],"format":"float"},"fid_p90":{"type":["number","null"],"format":"float"},"fid_p95":{"type":["number","null"],"format":"float"},"fid_p99":{"type":["number","null"],"format":"float"},"inp":{"type":"array","items":{"type":["number","null"],"format":"float"}},"inp_p75":{"type":["number","null"],"format":"float"},"inp_p90":{"type":["number","null"],"format":"float"},"inp_p95":{"type":["number","null"],"format":"float"},"inp_p99":{"type":["number","null"],"format":"float"},"lcp":{"type":"array","items":{"type":["number","null"],"format":"float"}},"lcp_p75":{"type":["number","null"],"format":"float"},"lcp_p90":{"type":["number","null"],"format":"float"},"lcp_p95":{"type":["number","null"],"format":"float"},"lcp_p99":{"type":["number","null"],"format":"float"},"timestamps":{"type":"array","items":{"type":"string"}},"ttfb":{"type":"array","items":{"type":["number","null"],"format":"float"}},"ttfb_p75":{"type":["number","null"],"format":"float"},"ttfb_p90":{"type":["number","null"],"format":"float"},"ttfb_p95":{"type":["number","null"],"format":"float"},"ttfb_p99":{"type":["number","null"],"format":"float"}}},"MetricsQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"MetricsRangeQuery":{"type":"object","description":"Query params for range metric queries.","required":["metric"],"properties":{"metric":{"type":"string","description":"Metric name, e.g. `\"pg.connections_active\"`."},"percentile":{"type":["number","null"],"format":"double","description":"Optional histogram percentile (0–100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile."},"range":{"type":"string","description":"Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`."}}},"MetricsStatusResponse":{"type":"object","description":"Freshness status: when metrics were last received for this service.","properties":{"last_received_at":{"type":["string","null"],"description":"ISO 8601 timestamp of the most recent metric row, or null if none yet."}}},"MetricsStoreKind":{"type":"string","description":"Which storage backend to use for the MetricsStore.","enum":["timescale_db","click_house"]},"MetricsSummaryResponse":{"type":"object","required":["currency","current_mrr_minor","current_arr_minor","active_subscriptions","active_customers","churned_last_30d","arpu_minor"],"properties":{"active_customers":{"type":"integer","format":"int64"},"active_subscriptions":{"type":"integer","format":"int64"},"arpu_minor":{"type":"integer","format":"int64"},"churned_last_30d":{"type":"integer","format":"int64"},"currency":{"type":"string"},"current_arr_minor":{"type":"integer","format":"int64"},"current_mrr_minor":{"type":"integer","format":"int64"}}},"MfaRequiredResponse":{"type":"object","required":["requires_mfa","session_token"],"properties":{"requires_mfa":{"type":"boolean"},"session_token":{"type":"string"}}},"MfaSetupResponse":{"type":"object","required":["secret_key","qr_code","recovery_codes"],"properties":{"qr_code":{"type":"string"},"recovery_codes":{"type":"array","items":{"type":"string"}},"secret_key":{"type":"string"}}},"MfaVerificationRequest":{"type":"object","required":["code"],"properties":{"code":{"type":"string"}}},"MigrationStep":{"type":"object","description":"A single step in the migration execution plan.\n\nSteps are presented to the user before execution so they know exactly\nwhat will happen. During execution, each step runs in order and reports\nits outcome before proceeding to the next.","required":["order","id","title","description","resource_type","risk","skippable","reversible"],"properties":{"data_implications":{"type":"array","items":{"$ref":"#/components/schemas/DataImplication"},"description":"Data implications — what could go wrong or what the user needs to know"},"description":{"type":"string","description":"Detailed description of what this step does"},"estimated_duration":{"type":["string","null"],"description":"Estimated duration hint (e.g., \"< 1 second\", \"10-30 seconds\")"},"id":{"type":"string","description":"Machine-readable step identifier (e.g., \"create-project\", \"create-service-postgres\")"},"order":{"type":"integer","description":"Step number (1-based, for display)","minimum":0},"post_conditions":{"type":"array","items":{"type":"string"},"description":"Things the user should verify AFTER this step completes"},"pre_conditions":{"type":"array","items":{"type":"string"},"description":"Things the user should verify BEFORE this step runs"},"resource_type":{"$ref":"#/components/schemas/StepResourceType","description":"What kind of resource this step creates/modifies"},"reversible":{"type":"boolean","description":"Whether this step is reversible (can be cleaned up on failure)"},"risk":{"$ref":"#/components/schemas/RiskLevel","description":"Risk level for this step"},"skippable":{"type":"boolean","description":"Whether this step can be skipped by the user"},"skipped":{"type":"boolean","description":"Whether the user has chosen to skip this step (set during review)"},"title":{"type":"string","description":"Human-readable title (e.g., \"Create project 'my-app'\")"}}},"MigrationSummary":{"type":"object","description":"Human-readable summary of the entire migration plan","required":["headline","overall_risk","resource_counts"],"properties":{"critical_warnings":{"type":"array","items":{"type":"string"},"description":"Critical warnings that must be acknowledged before proceeding.\nThese are the most important things the user needs to know."},"headline":{"type":"string","description":"One-line summary (e.g., \"Migrate 'my-app' from Vercel with 1 database, 2 domains\")"},"manual_actions_required":{"type":"array","items":{"$ref":"#/components/schemas/ManualAction"},"description":"Manual actions the user must perform (before or after migration)"},"overall_risk":{"$ref":"#/components/schemas/RiskLevel","description":"Overall risk assessment for the migration"},"resource_counts":{"$ref":"#/components/schemas/ResourceCounts","description":"Resource counts for quick overview"},"unsupported_features":{"type":"array","items":{"$ref":"#/components/schemas/UnsupportedFeature"},"description":"Features from the source platform that cannot be migrated"}}},"MintEnrollmentTokenRequest":{"type":"object","properties":{"bound_node_name":{"type":["string","null"],"description":"Optional: restrict the token to register one specific node name."},"max_uses":{"type":["integer","null"],"format":"int32","description":"Maximum registrations this token may authorize (default 1)."},"ttl_secs":{"type":["integer","null"],"format":"int64","description":"Time-to-live in seconds (default 3600 = 1h)."}}},"MintEnrollmentTokenResponse":{"type":"object","required":["id","token","expires_at","max_uses","message"],"properties":{"ca_fingerprint":{"type":["string","null"],"description":"SHA-256 fingerprint of the cluster CA (if mTLS is set up). Pass it to the\nworker as `temps join --ca-fingerprint ` to verify the CA on join."},"expires_at":{"type":"string"},"id":{"type":"integer","format":"int32"},"max_uses":{"type":"integer","format":"int32"},"message":{"type":"string"},"token":{"type":"string","description":"The plaintext enrollment token — shown only once, save it now."}}},"MiscResult":{"type":"object","description":"Miscellaneous validation result","required":["is_disposable","is_role_account","is_b2c"],"properties":{"gravatar_url":{"type":["string","null"],"description":"Gravatar URL if available"},"is_b2c":{"type":"boolean","description":"Whether the email provider is a B2C (consumer) email provider"},"is_disposable":{"type":"boolean","description":"Whether the email is from a disposable email provider"},"is_role_account":{"type":"boolean","description":"Whether the email is a role-based account (e.g., admin@, info@)"}}},"MkdirBody":{"type":"object","required":["path"],"properties":{"path":{"type":"string"}},"additionalProperties":false},"ModelInfo":{"type":"object","required":["id","object","owned_by"],"properties":{"id":{"type":"string"},"object":{"type":"string"},"owned_by":{"type":"string"}}},"ModelListResponse":{"type":"object","required":["object","data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ModelInfo"}},"object":{"type":"string"}}},"ModelPricing":{"type":"object","description":"Pricing for a single model, all values in USD per 1M tokens.\nFields are optional because not every provider supports every pricing tier.","required":["model","display_name","provider","input_per_million","output_per_million"],"properties":{"batch_input_per_million":{"type":["number","null"],"format":"double","description":"Batch API input cost per 1M tokens (if provider offers batch pricing)"},"batch_output_per_million":{"type":["number","null"],"format":"double","description":"Batch API output cost per 1M tokens"},"cache_hit_per_million":{"type":["number","null"],"format":"double","description":"Cache hit / refresh cost per 1M tokens"},"cache_write_1h_per_million":{"type":["number","null"],"format":"double","description":"1-hour cache write cost per 1M tokens"},"cache_write_5m_per_million":{"type":["number","null"],"format":"double","description":"5-minute cache write cost per 1M tokens (Anthropic-style prompt caching)"},"deprecated":{"type":"boolean","description":"Whether the model is deprecated"},"display_name":{"type":"string","description":"Human-readable model name (e.g. \"Claude Sonnet 4.6\")"},"input_per_million":{"type":"number","format":"double","description":"Base input token cost per 1M tokens"},"model":{"type":"string","description":"Model identifier (e.g. \"gpt-5.4\", \"claude-sonnet-4-6\")"},"output_per_million":{"type":"number","format":"double","description":"Output token cost per 1M tokens"},"provider":{"type":"string","description":"Provider ID (e.g. \"openai\", \"anthropic\")"}}},"ModelUsage":{"type":"object","required":["model","provider","request_count","input_tokens","output_tokens","total_tokens","avg_latency_ms"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"input_tokens":{"type":"integer","format":"int64"},"model":{"type":"string"},"output_tokens":{"type":"integer","format":"int64"},"provider":{"type":"string"},"request_count":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"MonitorResponse":{"type":"object","required":["id","project_id","name","monitor_type","monitor_url","check_interval_seconds","is_active","created_at","updated_at"],"properties":{"check_interval_seconds":{"type":"integer","format":"int32"},"check_path":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"monitor_type":{"type":"string"},"monitor_url":{"type":"string"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","format":"date-time"}}},"MonitorStatus":{"type":"object","required":["monitor","current_status","uptime_percentage"],"properties":{"avg_response_time_ms":{"type":["integer","null"],"format":"int32"},"current_status":{"type":"string"},"monitor":{"$ref":"#/components/schemas/MonitorResponse"},"uptime_percentage":{"type":"number","format":"double"}}},"MonitoringSettings":{"type":"object","description":"Global metrics observability configuration.\n\nControls whether the MetricsScraper and AlertEvaluator background tasks\nare active, which storage backend they write to, and how long data is kept\nat each retention tier.","properties":{"clickhouse_url":{"type":["string","null"],"description":"ClickHouse DSN (legacy, optional). The runtime metrics store is built\nfrom the `TEMPS_CLICKHOUSE_*` env vars, never from this field; it is\nretained for compatibility and operator reference only.\nExample: `\"http://localhost:8123\"`.","default":null},"enabled":{"type":"boolean","description":"Enable or disable all metrics collection (scraping + alerting).\nDefaults to `false` so new installs don't write to TimescaleDB until\nan operator explicitly enables the feature.","default":false},"retention_daily_years":{"type":"integer","format":"int32","description":"How many years of daily-aggregate data to keep (converted to days internally).","default":2,"example":2,"maximum":10,"minimum":1},"retention_hourly_days":{"type":"integer","format":"int32","description":"How many days of hourly-aggregate data to keep.","default":90,"example":90,"minimum":1},"retention_raw_days":{"type":"integer","format":"int32","description":"How many days of raw (30 s resolution) metric data to keep.","default":7,"example":7,"minimum":1},"scrape_interval_secs":{"type":"integer","format":"int64","description":"How often the MetricsScraper collects data from all sources, in seconds.\nMinimum effective value is 10 s; values below that are clamped at runtime.","default":30,"example":30,"minimum":10},"store":{"oneOf":[{"$ref":"#/components/schemas/MetricsStoreKind","description":"Storage backend for metric data."}],"default":"timescale_db"}}},"MonitoringSettingsMasked":{"type":"object","description":"Monitoring settings with the ClickHouse DSN masked.\n\n`clickhouse_url` can embed credentials (`http://user:pass@host`), so it is\nreported only as a boolean (`clickhouse_url_set`) rather than echoed back —\nconsistent with how the DNS API key and Docker registry password are masked.","required":["enabled","store","scrape_interval_secs","retention_raw_days","retention_hourly_days","retention_daily_years","clickhouse_url_set"],"properties":{"clickhouse_url_set":{"type":"boolean","description":"True when a ClickHouse DSN is configured. The DSN itself is never\nreturned over HTTP because it may contain credentials."},"enabled":{"type":"boolean"},"retention_daily_years":{"type":"integer","format":"int32","minimum":0},"retention_hourly_days":{"type":"integer","format":"int32","minimum":0},"retention_raw_days":{"type":"integer","format":"int32","minimum":0},"scrape_interval_secs":{"type":"integer","format":"int64","minimum":0},"store":{"$ref":"#/components/schemas/MetricsStoreKind"}}},"MrrBucketResponse":{"type":"object","required":["bucket","mrr_minor","charge_total_minor","refund_total_minor","charge_count"],"properties":{"bucket":{"type":"string","format":"date-time"},"charge_count":{"type":"integer","format":"int64"},"charge_total_minor":{"type":"integer","format":"int64"},"mrr_minor":{"type":"integer","format":"int64"},"refund_total_minor":{"type":"integer","format":"int64"}}},"MultiNodeSettings":{"type":"object","description":"Multi-node cluster settings","properties":{"cluster_ca_cert_pem":{"type":["string","null"],"description":"Per-cluster CA certificate (PEM) for multi-node mTLS (ADR-020 WS-2.1).\nPublic — distributed to nodes as the trust root and used by the control\nplane as the root for verifying agent server certs. Minted lazily on the\nfirst CSR-bearing registration.","default":null},"cluster_ca_key_encrypted":{"type":["string","null"],"description":"Per-cluster CA private key, AES-256-GCM ciphertext (EncryptionService).\nSECRET — never returned over HTTP (elided in the masked response).","default":null},"join_token_hash":{"type":["string","null"],"description":"SHA-256 hash of the join token (never store plaintext)","default":null},"legacy_shared_token_enabled":{"type":"boolean","description":"Whether the legacy single shared join token is still accepted for node\nregistration (ADR-020 WS-1.1). Defaults to `true` so existing clusters\nkeep working on upgrade; fresh installs should set it `false` and rely on\nshort-lived, single-use enrollment tokens instead.","default":true},"node_cpu_alert_percent":{"type":["number","null"],"format":"double","description":"CPU-usage percent above which a worker node raises a resource alert\n(ADR-020 / monitoring). `None` disables CPU alerting. Default 90.","default":90.0},"node_disk_alert_percent":{"type":["number","null"],"format":"double","description":"Disk-usage percent above which a worker node raises a resource alert.\n`None` disables disk alerting. Default 90.","default":90.0},"node_memory_alert_percent":{"type":["number","null"],"format":"double","description":"Memory-usage percent above which a worker node raises a resource alert.\n`None` disables memory alerting. Default 90.","default":90.0},"private_address":{"type":["string","null"],"description":"Private/WireGuard IP address of the control plane node.\nUsed by remote worker nodes to reach services (databases, etc.) running on the control plane.\nSet via `--private-address` or `TEMPS_PRIVATE_ADDRESS`.","default":null},"require_mtls":{"type":"boolean","description":"Whether to enforce multi-node mTLS (ADR-020 WS-2.1). When `false`\n(default), the control plane ignores join-time CSRs and nodes keep\nserving plaintext HTTP — zero behavior change. When `true`, the CP signs\nnode CSRs, nodes serve mutual TLS, and every CP→agent call uses the\ncluster client cert. Observe-then-enforce: flip this on only once all\nworkers have re-enrolled with certs.","default":false}}},"MultiNodeSettingsMasked":{"type":"object","description":"Multi-node settings with `join_token_hash` elided.","required":["has_join_token","require_mtls","legacy_shared_token_enabled"],"properties":{"cluster_ca_fingerprint":{"type":["string","null"],"description":"SHA-256 fingerprint of the cluster CA certificate (public — operators can\nverify it out of band; the CA private key is never exposed)."},"has_join_token":{"type":"boolean"},"legacy_shared_token_enabled":{"type":"boolean","description":"Whether the deprecated shared join token is still accepted."},"node_cpu_alert_percent":{"type":["number","null"],"format":"double","description":"Node resource-alert thresholds (percent); `None` = that alert disabled."},"node_disk_alert_percent":{"type":["number","null"],"format":"double"},"node_memory_alert_percent":{"type":["number","null"],"format":"double"},"private_address":{"type":["string","null"]},"require_mtls":{"type":"boolean","description":"Whether control-plane↔agent mutual TLS is enforced."}}},"MxResult":{"type":"object","description":"MX (Mail Exchange) validation result","required":["accepts_mail","records"],"properties":{"accepts_mail":{"type":"boolean","description":"Whether the domain accepts mail"},"error":{"type":["string","null"],"description":"Error message if MX lookup failed"},"records":{"type":"array","items":{"type":"string"},"description":"List of MX records for the domain","example":["alt1.gmail-smtp-in.l.google.com.","gmail-smtp-in.l.google.com."]}}},"NavEntry":{"type":"object","description":"A navigation entry that the plugin contributes to the Temps UI.","required":["label","icon","section","path","order"],"properties":{"icon":{"type":"string","description":"Lucide icon name (e.g., \"puzzle\", \"database\", \"activity\")"},"label":{"type":"string","description":"Display label in the sidebar"},"order":{"type":"integer","format":"int32","description":"Sort order within the section (lower = higher in list)","minimum":0},"path":{"type":"string","description":"Client-side route path (e.g., \"/my-plugin\")"},"section":{"$ref":"#/components/schemas/NavSection","description":"Which sidebar section this entry belongs to"}}},"NavSection":{"type":"string","description":"Where the plugin's nav entry appears in the Temps UI sidebar.","enum":["platform","settings","project"]},"NetworkConfiguration":{"type":"object","description":"Network configuration","required":["mode","dns_servers"],"properties":{"dns_servers":{"type":"array","items":{"type":"string"},"description":"DNS servers"},"hostname":{"type":["string","null"],"description":"Hostname"},"mode":{"$ref":"#/components/schemas/NetworkMode","description":"Network mode"}}},"NetworkMode":{"oneOf":[{"type":"string","enum":["bridge"]},{"type":"string","enum":["host"]},{"type":"string","enum":["none"]},{"type":"object","required":["custom"],"properties":{"custom":{"type":"string"}}}],"description":"Network mode"},"NixpacksPresetConfig":{"type":"object","description":"Configuration for Nixpacks preset\nNixpacks provider and inline build-plan configuration.","properties":{"nixpacksConfig":{"type":["string","null"],"description":"Optional inline nixpacks.toml contents."},"providers":{"type":"array","items":{"$ref":"#/components/schemas/NixpacksProvider"},"description":"Ordered Nixpacks providers. Empty means repository config or auto-detect;\ninclude `...` to combine auto-detection with explicit providers."}}},"NixpacksProvider":{"type":"string","description":"A Nixpacks build provider.\n\n`Auto` serializes as the native Nixpacks `...` marker, which includes the\nprovider detected from the project alongside any explicitly listed\nproviders.","enum":["...","node","python","rust","go","java","php","ruby","deno","elixir","csharp","fsharp","dart","swift","zig","scala","haskell","clojure","crystal","cobol","gleam","lunatic","scheme","static"]},"NodeContainerListResponse":{"type":"object","required":["containers","total"],"properties":{"containers":{"type":"array","items":{"$ref":"#/components/schemas/NodeContainerResponse"}},"total":{"type":"integer","minimum":0}}},"NodeContainerResponse":{"type":"object","description":"A container running on a specific node, enriched with project/environment context.","required":["container_id","container_name","image_name","status","created_at","deployment_id","project_id","project_name","environment_id","environment_name"],"properties":{"container_id":{"type":"string"},"container_name":{"type":"string"},"created_at":{"type":"string"},"deployment_id":{"type":"integer","format":"int32"},"environment_id":{"type":"integer","format":"int32"},"environment_name":{"type":"string"},"image_name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"status":{"type":"string"}}},"NodeCostInfo":{"type":"object","description":"One cluster node with capacity and (when priceable) a cost estimate","required":["name","cpu_millis","memory_mb"],"properties":{"cpu_millis":{"type":"integer","format":"int64","description":"CPU capacity in millicores"},"instance_type":{"type":["string","null"],"description":"Instance type from `node.kubernetes.io/instance-type` (e.g. \"m5.xlarge\")"},"memory_mb":{"type":"integer","format":"int64","description":"Memory capacity in MB"},"monthly_usd":{"type":["number","null"],"format":"double","description":"Estimated on-demand monthly price in USD. `None` when the instance\ntype is unknown or not in the price table."},"name":{"type":"string","description":"Node name"},"region":{"type":["string","null"],"description":"Region from `topology.kubernetes.io/region`"}}},"NodeInfoResponse":{"type":"object","required":["id","name","address","private_address","role","status","labels","capacity","created_at"],"properties":{"address":{"type":"string"},"architecture":{"type":["string","null"],"description":"Container platform this node runs (`linux/amd64`, `linux/arm64`).\n`None` until an agent that reports it has heartbeated."},"capacity":{"description":"Resource capacity/usage metrics from the latest heartbeat"},"created_at":{"type":"string"},"id":{"type":"integer","format":"int32"},"labels":{},"last_heartbeat":{"type":["string","null"]},"name":{"type":"string"},"private_address":{"type":"string"},"role":{"type":"string"},"status":{"type":"string"}}},"NodeListResponse":{"type":"object","required":["nodes","total"],"properties":{"nodes":{"type":"array","items":{"$ref":"#/components/schemas/NodeInfoResponse"}},"total":{"type":"integer","minimum":0}}},"NotificationPreferencesResponse":{"type":"object","required":["email_enabled","slack_enabled","batch_similar_notifications","minimum_severity","deployment_failures_enabled","build_errors_enabled","runtime_errors_enabled","error_threshold","error_time_window","ssl_expiration_enabled","ssl_days_before_expiration","domain_expiration_enabled","dns_changes_enabled","backup_failures_enabled","backup_successes_enabled","s3_connection_issues_enabled","retention_policy_violations_enabled","route_downtime_enabled","load_balancer_issues_enabled","weekly_digest_enabled","digest_send_day","digest_send_time","digest_sections"],"properties":{"backup_failures_enabled":{"type":"boolean"},"backup_successes_enabled":{"type":"boolean"},"batch_similar_notifications":{"type":"boolean"},"build_errors_enabled":{"type":"boolean"},"deployment_failures_enabled":{"type":"boolean"},"digest_sections":{"$ref":"#/components/schemas/DigestSections"},"digest_send_day":{"type":"string"},"digest_send_time":{"type":"string"},"dns_changes_enabled":{"type":"boolean"},"domain_expiration_enabled":{"type":"boolean"},"email_enabled":{"type":"boolean"},"error_threshold":{"type":"integer","format":"int32"},"error_time_window":{"type":"integer","format":"int32"},"load_balancer_issues_enabled":{"type":"boolean"},"minimum_severity":{"type":"string"},"retention_policy_violations_enabled":{"type":"boolean"},"route_downtime_enabled":{"type":"boolean"},"runtime_errors_enabled":{"type":"boolean"},"s3_connection_issues_enabled":{"type":"boolean"},"slack_enabled":{"type":"boolean"},"ssl_days_before_expiration":{"type":"integer","format":"int32"},"ssl_expiration_enabled":{"type":"boolean"},"weekly_digest_enabled":{"type":"boolean"}}},"NotificationProviderResponse":{"type":"object","required":["id","name","provider_type","config","enabled","created_at","updated_at"],"properties":{"config":{},"created_at":{"type":"integer","format":"int64"},"enabled":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"provider_type":{"type":"string"},"updated_at":{"type":"integer","format":"int64"}}},"ObservabilityCompressionSettings":{"type":"object","description":"TimescaleDB compression policy configuration for append-only observability\ntables. Values are expressed in hours so operators can choose sub-day\nwindows while keeping the API representation unambiguous.","properties":{"otel_spans_after_hours":{"type":"integer","format":"int32","description":"Compress OpenTelemetry span chunks after this many hours. Defaults to\n24 hours.","default":24,"example":24,"maximum":2160,"minimum":1},"proxy_logs_after_hours":{"type":"integer","format":"int32","description":"Compress proxy-log chunks after this many hours. Defaults to 24 hours.","default":24,"example":24,"maximum":720,"minimum":1}}},"ObservabilityEvent":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/RequestRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["request"]}}}]},{"allOf":[{"$ref":"#/components/schemas/SpanRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["span"]}}}]},{"allOf":[{"$ref":"#/components/schemas/ErrorRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["error"]}}}]},{"allOf":[{"$ref":"#/components/schemas/RevenueRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["revenue"]}}}]}],"description":"Discriminated union of every row that can appear in the Observe list.\n\nSerializes to `{ \"type\": \"request\" | \"span\" | ... , ...rest }` so the UI\ncan switch on `event.type` without ambiguity.\n\n**No `Log` variant**: runtime stdout/stderr lines live on a dedicated\nLogs page rather than Observe. Logs are too high-volume to interleave\nwith business signals (requests, errors, revenue) without dominating\nthe timeline, and they have their own retention/storage constraints\n(TimescaleDB hypertable + chunked file/S3 store) that don't compose\nwith the merge service's per-kind LIMIT strategy."},"ObservabilityRetentionSettings":{"type":"object","description":"Retention policy configuration for raw observability tables. Values are in\ndays. The Settings API applies them to TimescaleDB; ClickHouse-backed proxy\nlogs and spans retain their storage-level per-row TTL behavior.","properties":{"otel_logs_days":{"type":"integer","format":"int32","description":"Retain OpenTelemetry log events for this many days.","default":90,"example":90,"maximum":3650,"minimum":1},"otel_metrics_days":{"type":"integer","format":"int32","description":"Retain OpenTelemetry metric points for this many days.","default":90,"example":90,"maximum":3650,"minimum":1},"otel_spans_days":{"type":"integer","format":"int32","description":"Retain OpenTelemetry spans (traces) for this many days.","default":90,"example":90,"maximum":3650,"minimum":1},"proxy_logs_days":{"type":"integer","format":"int32","description":"Retain proxy request logs for this many days.","default":30,"example":30,"maximum":3650,"minimum":1}}},"OidcProviderResponse":{"type":"object","required":["id","name","issuer_url","client_id","client_secret","scopes","jit_provisioning","enabled","template","group_claim","role_claim","default_role","trust_idp_email"],"properties":{"client_id":{"type":"string"},"client_secret":{"type":"string","description":"Always masked — the secret is never returned after creation."},"default_role":{"type":"string"},"enabled":{"type":"boolean"},"group_claim":{"type":"string"},"id":{"type":"integer","format":"int32"},"issuer_url":{"type":"string"},"jit_provisioning":{"type":"boolean"},"name":{"type":"string"},"role_claim":{"type":"string"},"scopes":{"type":"string"},"template":{"type":"string"},"trust_idp_email":{"type":"boolean","description":"When true, the resolver skips the `email_verified` claim gate\nduring SSO login. Only safe for IdPs where an admin controls\nuser provisioning — see `oidc_providers::Model::trust_idp_email`."}}},"OidcProviderSummary":{"type":"object","required":["slug","name","template"],"properties":{"name":{"type":"string"},"slug":{"type":"string","description":"Stable opaque slug — use this as the path parameter when initiating\nOIDC login (`/auth/oidc/login/{slug}`). The integer database ID is\nintentionally omitted from this public endpoint to prevent provider\nenumeration."},"template":{"type":"string","description":"The template the provider was created from — e.g. `keycloak`,\n`okta`, `auth0`, `google`, `azure-ad`, or `generic`. Surfaced on\nthe public login endpoint so the unauthenticated login page can\nrender the right brand logo on the \"Sign in with X\" button.\nNever sensitive — the template name is part of the provider's\npublic identity, not configuration."}}},"OidcProviderUserResponse":{"type":"object","description":"A user that has logged in via a given OIDC provider. Used by the\nadmin \"Users for provider\" panel — the `oidc_subject` is the\nIdP-side identifier we matched on, useful when diagnosing why a\nuser can or can't log in.","required":["id","name","email","email_verified","mfa_enabled","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-15T14:30:00Z"},"email":{"type":"string"},"email_verified":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"mfa_enabled":{"type":"boolean"},"name":{"type":"string"},"oidc_subject":{"type":["string","null"]},"updated_at":{"type":"string","format":"date-time","example":"2024-01-15T14:30:00Z"}}},"OidcProvidersListResponse":{"type":"object","required":["providers"],"properties":{"providers":{"type":"array","items":{"$ref":"#/components/schemas/OidcProviderSummary"}}}},"OidcRoleMappingResponse":{"type":"object","required":["id","provider_id","priority","idp_group","role"],"properties":{"id":{"type":"integer","format":"int32"},"idp_group":{"type":"string"},"priority":{"type":"integer","format":"int32"},"provider_id":{"type":"integer","format":"int32"},"role":{"type":"string"}}},"OidcTestConnectionResponse":{"type":"object","required":["success","message"],"properties":{"message":{"type":"string"},"success":{"type":"boolean"}}},"OnDemandCertAttemptResponse":{"type":"object","description":"A single on-demand HTTP-01 issuance attempt from the append-only\n`on_demand_cert_attempts` audit log. Carries the full forensic detail for one\nattempt; the current cert state lives on the enclosing row's domain fields.\n\nContains no private-key or certificate material — only audit metadata — so it\nis safe to return without masking.","required":["id","hostname","trigger","outcome","created_at"],"properties":{"acme_request_sent":{"type":["boolean","null"],"description":"Did we reach the Let's Encrypt API?"},"acme_response_status":{"type":["string","null"],"description":"HTTP status or ACME error type returned by Let's Encrypt, when known."},"challenge_served":{"type":["boolean","null"],"description":"Did the proxy serve the `/.well-known/acme-challenge/` request?"},"created_at":{"type":"integer","format":"int64","description":"When the attempt was recorded (epoch millis)."},"duration_ms":{"type":["integer","null"],"format":"int32","description":"End-to-end issuance duration in milliseconds (0/None for skipped)."},"error_category":{"type":["string","null"],"description":"Coarse error category for UI labelling: `\"rate_limited\"`, `\"dns_failure\"`,\n`\"acme_order_expired\"`, `\"challenge_mismatch\"`, `\"timeout\"`, `\"internal\"`."},"error_chain":{"type":["string","null"],"description":"Full `Display` chain of the error (all `source()` levels), when failed."},"hostname":{"type":"string","description":"SNI hostname that triggered the attempt."},"id":{"type":"integer","format":"int32"},"outcome":{"type":"string","description":"Final outcome: `\"issued\"`, `\"failed\"`, `\"skipped_duplicate\"`,\n`\"skipped_gate\"`, `\"skipped_rate_limit\"`, or `\"skipped_no_route\"`."},"trigger":{"type":"string","description":"What triggered the attempt (always `\"tls_callback\"` today)."}}},"OnDemandCertRow":{"type":"object","description":"One row of the on-demand certificates list: the most-recent attempt for a\nhostname plus the current authoritative cert state from its `domains` row.","required":["hostname","attempt"],"properties":{"attempt":{"$ref":"#/components/schemas/OnDemandCertAttemptResponse","description":"The audit record for the attempt this row represents (newest first in\nthe list)."},"backoff_until":{"type":["integer","null"],"format":"int64","description":"On-demand negative-cache deadline (epoch millis), when in backoff."},"expiration_time":{"type":["integer","null"],"format":"int64","description":"Certificate expiration (epoch millis), when an active cert exists."},"hostname":{"type":"string","description":"SNI hostname."},"status":{"type":["string","null"],"description":"Current cert lifecycle status from the `domains` row, when one exists:\n`on_demand_pending`, `on_demand_issuing`, `active`, `on_demand_failed`,\netc. `None` when no `domains` row exists yet for this hostname."}}},"OnDemandTlsSettings":{"type":"object","description":"On-demand (lazy) HTTP-01 TLS issuance settings (ADR-018).\n\nWhen `enabled`, the proxy's `certificate_callback` triggers ACME HTTP-01\nissuance for allowlisted, STABLE hostnames (per-environment aliases and the\nconsole host) that have no active cert, rather than silently failing the\nhandshake. Ephemeral per-deployment hostnames are NEVER certed (ADR §2).\n\nOff by default — operators opt in explicitly, except QuickStart (`sslip.io`)\ninstalls where `temps setup` auto-enables it and derives `zone`.","properties":{"deployment_url_mode":{"type":"string","description":"How ephemeral per-deployment hostnames behave when they have no cert\n(they are NEVER certed — see ADR §2). One of:\n - `\"http\"` (default): serve plain HTTP on :80.\n - `\"redirect_to_env\"`: 308-redirect to the stable per-environment URL,\n which IS certed.","default":"http","example":"http"},"enabled":{"type":"boolean","description":"Master switch. When `false` (default) the proxy's on-demand cert gate\nrejects every SNI and no issuance is ever triggered.","default":false,"example":false},"hourly_cap":{"type":"integer","format":"int32","description":"Global cap on total on-demand issuances per hour across all hostnames\n(ADR §4 Layer 3). The operator's self-imposed safety net, separate from\nthe Let's Encrypt rate limit.","default":10,"example":10,"minimum":1},"max_concurrent":{"type":"integer","format":"int32","description":"Maximum number of ACME issuance flows allowed to run simultaneously\n(the concurrent-issuance semaphore, ADR §4 Layer 1). Min 1.","default":3,"example":3,"minimum":1},"zone":{"type":["string","null"],"description":"Zone suffix for the allowlist gate. A hostname passes the gate only if\nit is a direct subdomain of this zone (e.g. zone `1.2.3.4.sslip.io`\nadmits `myapp.1.2.3.4.sslip.io` but not `deep.sub.1.2.3.4.sslip.io`).\n`None` (default) means \"auto-derive from `external_url`\"; if no zone can\nbe derived the gate rejects all SNI, disabling the feature.","default":null,"example":"1.2.3.4.sslip.io"}}},"OpenAiError":{"type":"object","required":["message","type"],"properties":{"code":{"type":["string","null"]},"message":{"type":"string"},"type":{"type":"string"}}},"OpenAiErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"$ref":"#/components/schemas/OpenAiError"}}},"OperatingSystemCount":{"type":"object","required":["operating_system","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"operating_system":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"OperationResultResponse":{"type":"object","required":["operation","success","message","executed_at"],"properties":{"data":{},"executed_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"message":{"type":"string"},"operation":{"type":"string"},"success":{"type":"boolean"}}},"OperationResultsResponse":{"type":"object","required":["deployment_id","operations"],"properties":{"deployment_id":{"type":"string"},"operations":{"type":"array","items":{"$ref":"#/components/schemas/OperationResultResponse"}}}},"OtelDashboardResponse":{"type":"object","required":["id","project_id","name","layout","created_at","updated_at"],"properties":{"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"id":{"type":"integer","format":"int32"},"layout":{"$ref":"#/components/schemas/DashboardLayout"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"}}},"OtelDashboardsResponse":{"type":"object","required":["data","total"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OtelDashboardResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"OtelMetricAlertRuleResponse":{"type":"object","required":["id","project_id","name","metric_name","aggregation","detection_kind","detection_config","window_secs","for_duration_secs","severity","enabled","last_state","label_filters","group_by","dynamic_alerts","max_series","grouped_notification_threshold","last_dropped_series_count","series_states","created_at","updated_at"],"properties":{"aggregation":{"type":"string"},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"detection_config":{"$ref":"#/components/schemas/DetectionConfig","description":"The typed detector definition (discriminated union keyed by `kind`)."},"detection_kind":{"type":"string","description":"Coarse detector discriminator: `static|anomaly|forecast|outlier|auto_watch`."},"dynamic_alerts":{"type":"boolean","description":"Whether per-series (\"dynamic\") alerting is enabled for this rule."},"enabled":{"type":"boolean"},"firing_series":{"type":"array","items":{"$ref":"#/components/schemas/FiringSeriesEntry"},"description":"Currently-firing series for a dynamic rule, snapshotted from the evaluator's\nin-memory firing map at read time. Empty for static/aggregate rules or when\nnothing is firing."},"for_duration_secs":{"type":"integer","format":"int32"},"group_by":{"type":"array","items":{"type":"string"},"description":"Label keys the rule breaks the metric down by. Empty = one aggregate stream."},"grouped_notification_threshold":{"type":"integer","format":"int32","description":"Notification-grouping threshold: when more than this many series fire in the\nsame tick, only the first gets chart/AI enrichment (1–1000)."},"id":{"type":"integer","format":"int32"},"label_filters":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"AND-combined label equality filters applied when evaluating this rule.\nEmpty = no filtering (matches all series)."},"last_dropped_series_count":{"type":"integer","format":"int32","description":"Number of series dropped by the cardinality cap on the latest dynamic tick\n(0 when nothing was dropped or for static/aggregate rules). Lets a UI warn\n\"N series were dropped this tick\" without reading server logs."},"last_evaluated_at":{"type":["string","null"],"example":"2025-10-12T12:15:47.609192Z"},"last_state":{"type":"string","description":"One of `ok|firing|unknown`."},"last_value":{"type":["number","null"],"format":"double"},"max_series":{"type":"integer","format":"int32","description":"Cardinality cap for dynamic alerting (1–100)."},"metric_name":{"type":"string"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"series_states":{"type":"object","description":"Full per-series state snapshot persisted after the latest dynamic-rule tick,\nkeyed by the human-readable series label (`endpoint=/checkout`). Empty for\nstatic/aggregate rules. Unlike `firing_series` (a live in-memory snapshot),\nthis is decoded from the persisted `series_states` jsonb column, so an\nexternal consumer that only reads the rule row still sees per-series detail.","additionalProperties":{"$ref":"#/components/schemas/SeriesStateEntry"},"propertyNames":{"type":"string"}},"severity":{"type":"string"},"updated_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"window_secs":{"type":"integer","format":"int32"}}},"OtelMetricAlertsResponse":{"type":"object","required":["data","total"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OtelMetricAlertRuleResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"OtelMetricLabelKeysResponse":{"type":"object","required":["keys"],"properties":{"keys":{"type":"array","items":{"type":"string"}}}},"OtelMetricLabelValuesResponse":{"type":"object","required":["values"],"properties":{"values":{"type":"array","items":{"type":"string"}}}},"OtelMetricNamesResponse":{"type":"object","required":["names"],"properties":{"names":{"type":"array","items":{"type":"string"}}}},"OtelMetricsResponse":{"type":"object","required":["data","count"],"properties":{"count":{"type":"integer","minimum":0},"data":{"type":"array","items":{"$ref":"#/components/schemas/MetricBucket"}}}},"OutlierAlgorithm":{"type":"string","description":"Outlier detection algorithm.","enum":["dbscan","scaled_dbscan","mad","scaled_mad"]},"OutlierParams":{"type":"object","description":"Outlier (cross-series population) detector parameters (stub — not evaluated).","required":["peer_group_key"],"properties":{"algorithm":{"$ref":"#/components/schemas/OutlierAlgorithm"},"peer_group_key":{"type":"string","description":"Label key defining the peer population compared across series (e.g. `host`)."},"tolerance":{"type":"number","format":"double","description":"Sensitivity; higher tolerates larger spread before flagging."}}},"OverprovisioningAssessment":{"type":"object","description":"Requests-vs-capacity-vs-usage assessment","required":["verdict","explanation"],"properties":{"cpu_request_inflation_ratio":{"type":["number","null"],"format":"double","description":"Ratio of requested CPU to measured CPU usage (e.g. 40.0 = requests\nreserve 40× what the workloads actually use). `None` without metrics."},"cpu_requested_pct":{"type":["number","null"],"format":"double","description":"Requested CPU as % of cluster capacity"},"cpu_utilization_pct":{"type":["number","null"],"format":"double","description":"Measured CPU usage as % of cluster capacity (`None` without metrics)"},"explanation":{"type":"string","description":"Human-readable explanation of the verdict, e.g. \"Cluster capacity is\n8 vCPU but measured usage is 0.3 vCPU (3.7%) — severely overprovisioned\""},"memory_request_inflation_ratio":{"type":["number","null"],"format":"double","description":"Ratio of requested memory to measured memory usage"},"memory_requested_pct":{"type":["number","null"],"format":"double","description":"Requested memory as % of cluster capacity"},"memory_utilization_pct":{"type":["number","null"],"format":"double","description":"Measured memory usage as % of cluster capacity (`None` without metrics)"},"verdict":{"$ref":"#/components/schemas/OverprovisioningVerdict","description":"Overall verdict"}}},"OverprovisioningVerdict":{"type":"string","description":"Overall overprovisioning verdict","enum":["severe","moderate","reasonable","unknown"]},"PageActivityBucket":{"type":"object","description":"Time bucket data point for page activity graph","required":["timestamp","visitors","page_views","avg_time_seconds"],"properties":{"avg_time_seconds":{"type":"number","format":"double","description":"Average time on page in seconds"},"page_views":{"type":"integer","format":"int64","description":"Number of page views in this bucket"},"timestamp":{"type":"string","description":"Timestamp for this bucket (ISO 8601)"},"visitors":{"type":"integer","format":"int64","description":"Number of unique visitors in this bucket"}}},"PageCountryStats":{"type":"object","description":"Geographic distribution of visitors for a page","required":["country","visitors","page_views","percentage"],"properties":{"country":{"type":"string","description":"Country name"},"country_code":{"type":["string","null"],"description":"ISO country code (2-letter)"},"page_views":{"type":"integer","format":"int64","description":"Number of page views from this country"},"percentage":{"type":"number","format":"double","description":"Percentage of total visitors"},"visitors":{"type":"integer","format":"int64","description":"Number of unique visitors from this country"}}},"PageFlowEntry":{"type":"object","description":"A single page with its entry/exit/bounce statistics","required":["page_path","entry_count","exit_count","bounce_count","total_views","entry_rate","exit_rate","bounce_rate"],"properties":{"avg_time_on_page":{"type":["number","null"],"format":"double","description":"Average time spent on this page in seconds"},"bounce_count":{"type":"integer","format":"int64","description":"Number of times visitors bounced on this page"},"bounce_rate":{"type":"number","format":"double","description":"Bounce rate: bounce_count / entry_count (only meaningful for entry pages)"},"entry_count":{"type":"integer","format":"int64","description":"Number of times this page was the entry page of a session"},"entry_rate":{"type":"number","format":"double","description":"Entry rate: entry_count / total_views"},"exit_count":{"type":"integer","format":"int64","description":"Number of times this page was the exit page of a session"},"exit_rate":{"type":"number","format":"double","description":"Exit rate: exit_count / total_views"},"page_path":{"type":"string","description":"The page path (e.g. \"/pricing\", \"/docs/getting-started\")"},"total_views":{"type":"integer","format":"int64","description":"Total page views for this page"}}},"PageFlowQuery":{"type":"object","description":"Query parameters for page flow analytics","required":["project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of entry/exit pages to return (default: 20)"},"min_views_for_dropoff":{"type":["integer","null"],"format":"int32","description":"Minimum views for drop-off analysis (default: 5)"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"},"transitions_limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of transitions to return (default: 50)"}}},"PageFlowResponse":{"type":"object","description":"Complete page flow analytics response","required":["top_entry_pages","top_exit_pages","drop_off_points","transitions","total_pages","total_sessions"],"properties":{"drop_off_points":{"type":"array","items":{"$ref":"#/components/schemas/DropOffPoint"},"description":"Top drop-off points (highest exit rates with meaningful traffic)"},"top_entry_pages":{"type":"array","items":{"$ref":"#/components/schemas/PageFlowEntry"},"description":"Top entry pages (where visitors land), sorted by entry_count DESC"},"top_exit_pages":{"type":"array","items":{"$ref":"#/components/schemas/PageFlowEntry"},"description":"Top exit pages (where visitors leave), sorted by exit_count DESC"},"total_pages":{"type":"integer","format":"int64","description":"Total unique pages seen in the period"},"total_sessions":{"type":"integer","format":"int64","description":"Total sessions in the period"},"transitions":{"type":"array","items":{"$ref":"#/components/schemas/PageTransition"},"description":"Page-to-page transitions (most common navigation paths)"}}},"PageHourlySessionsQuery":{"type":"object","description":"Query parameters for page hourly sessions endpoint","required":["page_path","project_id","start_time","end_time"],"properties":{"bucket_interval":{"type":["string","null"]},"end_time":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page_path":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"start_time":{"type":"string","format":"date-time"}}},"PageHourlySessionsResponse":{"type":"object","required":["page_path","hourly_data","total_sessions","hours"],"properties":{"hourly_data":{"type":"array","items":{"$ref":"#/components/schemas/HourlyPageSessions"}},"hours":{"type":"integer","format":"int32"},"page_path":{"type":"string"},"total_sessions":{"type":"integer","format":"int64"}}},"PagePathDetailQuery":{"type":"object","description":"Query parameters for page path detail analytics","required":["page_path","project_id","start_date","end_date"],"properties":{"bucket_interval":{"type":["string","null"],"description":"Bucket interval for time series: 'hour', 'day', 'week', 'month' (default: auto)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page_path":{"type":"string","description":"The specific page path to get details for (URL-encoded)"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"PagePathDetailResponse":{"type":"object","description":"Detailed analytics response for a specific page path","required":["page_path","unique_visitors","total_page_views","avg_time_on_page","bounce_rate","entry_rate","exit_rate","activity_over_time","countries","referrers","bucket_interval"],"properties":{"activity_over_time":{"type":"array","items":{"$ref":"#/components/schemas/PageActivityBucket"},"description":"Time series data for activity graph"},"avg_time_on_page":{"type":"number","format":"double","description":"Average time on page in seconds"},"bounce_rate":{"type":"number","format":"double","description":"Bounce rate percentage (0-100)"},"bucket_interval":{"type":"string","description":"Bucket interval used for time series ('hour', 'day', etc.)"},"countries":{"type":"array","items":{"$ref":"#/components/schemas/PageCountryStats"},"description":"Geographic distribution of visitors"},"entry_rate":{"type":"number","format":"double","description":"Entry rate - percentage of sessions that started on this page"},"exit_rate":{"type":"number","format":"double","description":"Exit rate - percentage of sessions that ended on this page"},"page_path":{"type":"string","description":"The page path being analyzed"},"referrers":{"type":"array","items":{"$ref":"#/components/schemas/PageReferrerStats"},"description":"Top referrers to this page"},"total_page_views":{"type":"integer","format":"int64","description":"Total page views in the date range"},"unique_visitors":{"type":"integer","format":"int64","description":"Total unique visitors to this page in the date range"}}},"PagePathInfo":{"type":"object","required":["page_path","session_count","page_view_count","first_seen","last_seen"],"properties":{"avg_time_seconds":{"type":["number","null"],"format":"double"},"first_seen":{"type":"string"},"last_seen":{"type":"string"},"page_path":{"type":"string"},"page_view_count":{"type":"integer","format":"int64"},"session_count":{"type":"integer","format":"int64"}}},"PagePathSparkline":{"type":"object","required":["page_path","points"],"properties":{"page_path":{"type":"string"},"points":{"type":"array","items":{"$ref":"#/components/schemas/PagePathSparklinePoint"}}}},"PagePathSparklinePoint":{"type":"object","required":["timestamp","session_count"],"properties":{"session_count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"}}},"PagePathVisitorsQuery":{"type":"object","description":"Query parameters for page path visitors","required":["page_path","project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page":{"type":["integer","null"],"format":"int64","description":"Page number (1-based, default: 1)","minimum":0},"page_path":{"type":"string","description":"The specific page path to get visitors for"},"per_page":{"type":["integer","null"],"format":"int64","description":"Items per page (default: 50, max: 100)","minimum":0},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"PagePathVisitorsResponse":{"type":"object","description":"Response for page path visitors endpoint","required":["page_path","total_count","page","per_page","sessions"],"properties":{"page":{"type":"integer","format":"int64","description":"Current page number","minimum":0},"page_path":{"type":"string","description":"The page path"},"per_page":{"type":"integer","format":"int64","description":"Items per page","minimum":0},"sessions":{"type":"array","items":{"$ref":"#/components/schemas/PageVisitorSession"},"description":"Individual visitor sessions"},"total_count":{"type":"integer","format":"int64","description":"Total number of visitor sessions matching the query"}}},"PagePathsQuery":{"type":"object","required":["project_id"],"properties":{"end_date":{"type":["string","null"],"format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":["string","null"],"format":"date-time"}}},"PagePathsResponse":{"type":"object","required":["page_paths","total_count"],"properties":{"page_paths":{"type":"array","items":{"$ref":"#/components/schemas/PagePathInfo"}},"total_count":{"type":"integer","minimum":0}}},"PagePathsSparklineQuery":{"type":"object","description":"Query parameters for batch page paths sparkline endpoint","required":["project_id","start_time","end_time","page_paths"],"properties":{"end_time":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page_paths":{"type":"string","description":"Comma-separated list of page paths"},"project_id":{"type":"integer","format":"int32"},"start_time":{"type":"string","format":"date-time"}}},"PagePathsSparklineResponse":{"type":"object","required":["sparklines"],"properties":{"sparklines":{"type":"array","items":{"$ref":"#/components/schemas/PagePathSparkline"}}}},"PageReferrerStats":{"type":"object","description":"Referrer source for the page","required":["referrer","visits","percentage"],"properties":{"percentage":{"type":"number","format":"double","description":"Percentage of total visits"},"referrer":{"type":"string","description":"Referrer URL or domain"},"visits":{"type":"integer","format":"int64","description":"Number of visits from this referrer"}}},"PageSessionComparison":{"type":"object","required":["page_path","date","session_count","event_count","avg_duration_seconds"],"properties":{"avg_duration_seconds":{"type":"number","format":"double"},"date":{"type":"string"},"event_count":{"type":"integer","format":"int64"},"page_path":{"type":"string"},"session_count":{"type":"integer","format":"int64"}}},"PageSessionStats":{"type":"object","required":["page_path","total_sessions","avg_time_seconds","min_time_seconds","max_time_seconds","total_page_views","avg_page_views_per_session"],"properties":{"avg_page_views_per_session":{"type":"number","format":"double"},"avg_time_seconds":{"type":"number","format":"double"},"max_time_seconds":{"type":"number","format":"double"},"min_time_seconds":{"type":"number","format":"double"},"page_path":{"type":"string"},"total_page_views":{"type":"integer","format":"int64"},"total_sessions":{"type":"integer","format":"int64"}}},"PageSessionStatsQuery":{"type":"object","required":["page_path","project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page_path":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"PageTransition":{"type":"object","description":"A page-to-page transition with count","required":["from_page","to_page","transition_count","percentage"],"properties":{"from_page":{"type":"string","description":"The source page path"},"percentage":{"type":"number","format":"double","description":"Percentage of transitions from the source page that go to this destination"},"to_page":{"type":"string","description":"The destination page path"},"transition_count":{"type":"integer","format":"int64","description":"Number of times this transition occurred"}}},"PageVisit":{"type":"object","required":["path","visits"],"properties":{"path":{"type":"string"},"visits":{"type":"integer","format":"int64"}}},"PageVisitorSession":{"type":"object","description":"Individual visitor session that viewed a specific page","required":["visitor_id","visitor_uuid","viewed_at","is_entry","is_exit","is_bounce"],"properties":{"browser":{"type":["string","null"],"description":"Browser name"},"city":{"type":["string","null"],"description":"Visitor's city"},"country":{"type":["string","null"],"description":"Visitor's country"},"country_code":{"type":["string","null"],"description":"Visitor's country code"},"device_type":{"type":["string","null"],"description":"Device type (Desktop, Mobile, Tablet)"},"is_bounce":{"type":"boolean","description":"Whether this was a bounce"},"is_entry":{"type":"boolean","description":"Whether this was the entry page for the session"},"is_exit":{"type":"boolean","description":"Whether this was the exit page for the session"},"operating_system":{"type":["string","null"],"description":"Operating system"},"referrer":{"type":["string","null"],"description":"Referrer URL"},"session_id":{"type":["string","null"],"description":"Session ID"},"session_page_number":{"type":["integer","null"],"format":"int32","description":"Page number in session flow"},"time_on_page":{"type":["integer","null"],"format":"int32","description":"Time spent on this page in seconds"},"viewed_at":{"type":"string","format":"date-time","description":"When the page was viewed"},"visitor_id":{"type":"integer","format":"int32","description":"Visitor numeric ID"},"visitor_uuid":{"type":"string","description":"Visitor UUID"}}},"PagesComparisonResponse":{"type":"object","required":["comparisons","page_paths"],"properties":{"comparisons":{"type":"array","items":{"$ref":"#/components/schemas/PageSessionComparison"}},"page_paths":{"type":"array","items":{"type":"string"}}}},"PaginatedEmailsResponse":{"type":"object","required":["data","total","page","page_size"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/EmailResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"PaginatedEntitiesResponse":{"type":"object","required":["entities","count","limit","has_more"],"properties":{"count":{"type":"integer","description":"Number of entities returned","minimum":0},"entities":{"type":"array","items":{"$ref":"#/components/schemas/EntityResponse"},"description":"List of entities"},"has_more":{"type":"boolean","description":"Whether there are more entities available"},"limit":{"type":"integer","description":"Limit used for this request","minimum":0},"next_token":{"type":["string","null"],"description":"Continuation token for next page (S3, etc.)"},"total":{"type":["integer","null"],"description":"Total number of entities (if available)","minimum":0}}},"PaginatedErrorEventsResponse":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ErrorEventResponse"}},"pagination":{"$ref":"#/components/schemas/PaginationMeta"}}},"PaginatedErrorGroupsResponse":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ErrorGroupResponse"}},"pagination":{"$ref":"#/components/schemas/PaginationMeta"}}},"PaginatedEventsResponse":{"type":"object","required":["events","total","page","page_size"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/TrackingEventResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"PaginatedExternalImagesResponse":{"type":"object","required":["data","total","page","page_size"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ExternalImageResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"PaginatedProjectList":{"type":"object","required":["projects","total","page","per_page"],"properties":{"page":{"type":"integer","format":"int64"},"per_page":{"type":"integer","format":"int64"},"projects":{"type":"array","items":{"$ref":"#/components/schemas/ProjectResponse"}},"total":{"type":"integer","format":"int64"}}},"PaginatedStaticBundlesResponse":{"type":"object","required":["data","total","page","page_size"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/StaticBundleResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"Pagination":{"type":"object","description":"SDK pagination cursor. We use opaque page numbers internally but\nexpose `count`/`next`/`prev` the way `@vercel/sandbox` expects.","required":["count"],"properties":{"count":{"type":"integer","format":"int64","minimum":0},"next":{"type":["integer","null"],"format":"int64","minimum":0},"prev":{"type":["integer","null"],"format":"int64","minimum":0}}},"PaginationMeta":{"type":"object","required":["page","page_size","total_count","total_pages"],"properties":{"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total_count":{"type":"integer","format":"int64","minimum":0},"total_pages":{"type":"integer","format":"int64","minimum":0}}},"PaginationParams":{"type":"object","properties":{"page":{"type":"integer","format":"int64"},"per_page":{"type":"integer","format":"int64"}}},"PasswordProtectionConfig":{"type":"object","description":"Password protection configuration\n\nWhen enabled, the proxy shows an HTML password form before allowing access.\nAfter the user enters the correct password, an HMAC-signed cookie is set\nso subsequent requests pass through without re-entering the password.","required":["enabled","passwordHash"],"properties":{"enabled":{"type":"boolean","description":"Whether password protection is enabled"},"passwordHash":{"type":"string","description":"The bcrypt-hashed password (never stored or returned in plaintext)"}}},"PatchSettingsRequest":{"type":"object","properties":{"auto_upgrade":{"type":["boolean","null"]},"host_port":{"type":["integer","null"],"format":"int32","minimum":0},"image":{"type":["string","null"]}}},"PathVisitors":{"type":"object","required":["name","visitors","percentage"],"properties":{"name":{"type":"string"},"percentage":{"type":"number","format":"double"},"visitors":{"type":"integer","format":"int64"}}},"PathVisitorsAnalyticsQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"PathVisitorsResponse":{"type":"object","required":["results"],"properties":{"results":{"type":"array","items":{"$ref":"#/components/schemas/PathVisitors"}}}},"PeerEntry":{"type":"object","description":"Wire-format peer entry. Matches `temps_network::config::Peer` but\nuses strings on the wire to keep the API stable across underlying\ntype evolution.","required":["node_id","compute_cidr","underlay_address"],"properties":{"compute_cidr":{"type":"string","description":"Per-node CIDR (e.g. `\"172.20.5.0/24\"`)."},"node_id":{"type":"string","description":"Stable v5 UUID derived from the database node id. Workers use\nthis as the kernel-layer identifier when calling\n`NetworkManager::reconcile_peers`."},"underlay_address":{"type":"string","description":"Address the local node should use to reach this peer over the\nunderlay (private VPC IP for same-DC, public IP for cross-DC)."}}},"PeerListResponse":{"type":"object","description":"Response body for `GET /internal/nodes/{node_id}/network/peers`.","required":["peers","cluster_dns_enabled"],"properties":{"alloc":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AllocEntry","description":"Caller's own allocation, or `null` if multi-host networking has\nnot been enabled for this node yet."}]},"cluster_dns_enabled":{"type":"boolean","description":"Whether the cluster-DNS resolver is enabled on this control plane\n(`AppSettings.cluster_dns.enabled`). Workers should start their\nper-node resolver and write `overlay_bridge_address` only when this\nis `true`. Always serialized (never `skip_serializing_if`) so older\nand newer version skew degrades to the safe default of `false`."},"peers":{"type":"array","items":{"$ref":"#/components/schemas/PeerEntry"},"description":"All other nodes with a `compute_cidr` set, excluding the caller."}}},"PendingActionResponse":{"type":"object","description":"A proposed AI write action awaiting human confirmation.","required":["public_id","operation_id","method","summary","status","step_index","params","created_at"],"properties":{"confirmed_at":{"type":["string","null"]},"created_at":{"type":"string"},"error":{"type":["string","null"]},"executed_at":{"type":["string","null"]},"method":{"type":"string"},"operation_id":{"type":"string"},"params":{"description":"The flat params to be replayed at execute time (shown pre-execution for review)."},"plan_public_id":{"type":["string","null"],"description":"Set when this action is one step of a multi-step plan (chained actions);\nall steps of the plan share this id. Absent for standalone single actions."},"public_id":{"type":"string"},"required_permission":{"type":["string","null"]},"result":{},"status":{"type":"string"},"step_index":{"type":"integer","format":"int32","description":"0-based order of this step within its plan (0 for standalone actions)."},"summary":{"type":"string"}}},"PerformanceMetricsQuery":{"allOf":[{"$ref":"#/components/schemas/SpeedSegmentFilters","description":"Segment filters (filter_path, filter_country, filter_region,\nfilter_city, filter_browser, filter_operating_system) — flattened so\neach remains a top-level query string param."},{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"device_type":{"type":["string","null"],"description":"Device type filter: \"desktop\" or \"mobile\""},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"include_bots":{"type":["boolean","null"],"description":"Include crawler/datacenter (bot) samples. Defaults to false — bots\nare excluded from the read view but always stored at ingest."},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}}]},"PerformanceMetricsResponse":{"type":"object","properties":{"cls":{"type":["number","null"],"format":"float"},"cls_p75":{"type":["number","null"],"format":"float"},"cls_p90":{"type":["number","null"],"format":"float"},"cls_p95":{"type":["number","null"],"format":"float"},"cls_p99":{"type":["number","null"],"format":"float"},"fcp":{"type":["number","null"],"format":"float"},"fcp_p75":{"type":["number","null"],"format":"float"},"fcp_p90":{"type":["number","null"],"format":"float"},"fcp_p95":{"type":["number","null"],"format":"float"},"fcp_p99":{"type":["number","null"],"format":"float"},"fid":{"type":["number","null"],"format":"float"},"fid_p75":{"type":["number","null"],"format":"float"},"fid_p90":{"type":["number","null"],"format":"float"},"fid_p95":{"type":["number","null"],"format":"float"},"fid_p99":{"type":["number","null"],"format":"float"},"inp":{"type":["number","null"],"format":"float"},"inp_p75":{"type":["number","null"],"format":"float"},"inp_p90":{"type":["number","null"],"format":"float"},"inp_p95":{"type":["number","null"],"format":"float"},"inp_p99":{"type":["number","null"],"format":"float"},"lcp":{"type":["number","null"],"format":"float"},"lcp_p75":{"type":["number","null"],"format":"float"},"lcp_p90":{"type":["number","null"],"format":"float"},"lcp_p95":{"type":["number","null"],"format":"float"},"lcp_p99":{"type":["number","null"],"format":"float"},"ttfb":{"type":["number","null"],"format":"float"},"ttfb_p75":{"type":["number","null"],"format":"float"},"ttfb_p90":{"type":["number","null"],"format":"float"},"ttfb_p95":{"type":["number","null"],"format":"float"},"ttfb_p99":{"type":["number","null"],"format":"float"}}},"PermissionInfo":{"type":"object","description":"Information about a single permission","required":["name","description","category"],"properties":{"category":{"type":"string","description":"Category of the permission (e.g., \"Projects\", \"Deployments\")"},"description":{"type":"string","description":"Human-readable description of the permission"},"name":{"type":"string","description":"The permission identifier (e.g., \"projects:read\")"}}},"PgUpgradeLogResponse":{"type":"object","required":["log_id","content"],"properties":{"content":{"type":"string"},"log_id":{"type":"string"}}},"PgUpgradeResponse":{"type":"object","required":["id","service_id","from_version","to_version","from_image","to_image","status","phase","log_id","attempt","created_at"],"properties":{"attempt":{"type":"integer","format":"int32"},"created_at":{"type":"string"},"error_message":{"type":["string","null"]},"finished_at":{"type":["string","null"]},"from_image":{"type":"string"},"from_version":{"type":"string"},"id":{"type":"integer","format":"int32"},"log_id":{"type":"string"},"phase":{"type":"string"},"pre_upgrade_backup_id":{"type":["integer","null"],"format":"int32"},"rollback_volume_name":{"type":["string","null"]},"service_id":{"type":"integer","format":"int32"},"started_at":{"type":["string","null"]},"status":{"type":"string"},"to_image":{"type":"string"},"to_version":{"type":"string"}}},"PipelineStats":{"type":"object","description":"Internal pipeline statistics for self-observability.","required":["metrics_received","metrics_stored","metrics_dropped","spans_received","spans_stored","spans_dropped","logs_received","logs_stored_db","logs_stored_s3","logs_dropped","ingest_errors"],"properties":{"ingest_errors":{"type":"integer","format":"int64","minimum":0},"logs_dropped":{"type":"integer","format":"int64","minimum":0},"logs_received":{"type":"integer","format":"int64","minimum":0},"logs_stored_db":{"type":"integer","format":"int64","minimum":0},"logs_stored_s3":{"type":"integer","format":"int64","minimum":0},"metrics_dropped":{"type":"integer","format":"int64","minimum":0},"metrics_received":{"type":"integer","format":"int64","minimum":0},"metrics_stored":{"type":"integer","format":"int64","minimum":0},"spans_dropped":{"type":"integer","format":"int64","minimum":0},"spans_received":{"type":"integer","format":"int64","minimum":0},"spans_stored":{"type":"integer","format":"int64","minimum":0}}},"PipelineStatsResponse":{"type":"object","required":["stats"],"properties":{"stats":{"$ref":"#/components/schemas/PipelineStats"}}},"PlanComplexity":{"type":"string","description":"Plan complexity indicator","enum":["low","medium","high"]},"PlanMetadata":{"type":"object","description":"Plan metadata","required":["generated_at","generator_version","complexity","warnings"],"properties":{"complexity":{"$ref":"#/components/schemas/PlanComplexity","description":"Estimated complexity (low, medium, high)"},"generated_at":{"type":"string","format":"date-time","description":"When the plan was generated"},"generator_version":{"type":"string","description":"Generator (importer) version"},"warnings":{"type":"array","items":{"type":"string"},"description":"Warnings detected during planning"}}},"PlanSourceBackup":{"type":"object","required":["location","location_was_resolved","format"],"properties":{"created_at":{"type":["string","null"]},"format":{"type":"string","description":"\"walg\", \"pg_dump\", \"unknown\"."},"id":{"type":["integer","null"],"format":"int32","description":"DB id, absent for orphan (S3-scan) backups."},"location":{"type":"string","description":"Resolved S3 location the orchestrator will actually use."},"location_was_resolved":{"type":"boolean","description":"True when the original row's `s3_location` was empty and we resolved\na location by probing S3. The UI shows this as a warning."},"origin_service_name":{"type":["string","null"],"description":"Service that originally produced the backup, if known."},"size_bytes":{"type":["integer","null"],"format":"int64"}}},"PlanTarget":{"type":"object","required":["id","name","container"],"properties":{"container":{"type":"string","description":"Expected Docker container name."},"id":{"type":"integer","format":"int32"},"name":{"type":"string"}}},"PlatformInfo":{"type":"object","description":"Platform compatibility information","required":["os_type","architecture","platforms"],"properties":{"architecture":{"type":"string","description":"System architecture (e.g., \"x86_64\", \"aarch64\")"},"os_type":{"type":"string","description":"Operating system type (e.g., \"linux\", \"windows\", \"darwin\")"},"platforms":{"type":"array","items":{"type":"string"},"description":"List of supported platforms in \"os/arch\" format (e.g., [\"linux/amd64\"])"}}},"PluginManifest":{"type":"object","description":"The complete plugin manifest — the handshake contract.","required":["name","version"],"properties":{"description":{"type":["string","null"],"description":"Short description of what the plugin does"},"display_name":{"type":["string","null"],"description":"Human-readable display name"},"events":{"type":"array","items":{"type":"string"},"description":"Platform event types the plugin subscribes to.\n\nWhen specified, Temps will POST matching events to the plugin's\n`/_events` endpoint. Uses dot-notation event names matching the\nwebhook event types (e.g., \"deployment.succeeded\", \"project.created\").\n\nAvailable events:\n- `deployment.created`, `deployment.succeeded`, `deployment.failed`,\n `deployment.cancelled`, `deployment.ready`\n- `project.created`, `project.deleted`\n- `domain.created`, `domain.provisioned`"},"health_path":{"type":"string","description":"Health check endpoint path (relative to plugin root)"},"name":{"type":"string","description":"Unique plugin identifier (kebab-case, e.g., \"backup-manager\")"},"nav":{"type":"array","items":{"$ref":"#/components/schemas/NavEntry"},"description":"Navigation entries for the UI sidebar"},"requires_db":{"type":"boolean","description":"Whether the plugin needs database access"},"ui":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/UiManifest","description":"UI bundle manifest (if the plugin has a UI)"}]},"version":{"type":"string","description":"SemVer version string"}}},"PortMapping":{"type":"object","description":"Port mapping","required":["container_port","protocol","is_primary"],"properties":{"container_port":{"type":"integer","format":"int32","description":"Container port","minimum":0},"host_port":{"type":["integer","null"],"format":"int32","description":"Host port (optional - can be assigned dynamically)","minimum":0},"is_primary":{"type":"boolean","description":"Whether this is the primary HTTP port"},"protocol":{"$ref":"#/components/schemas/Protocol","description":"Protocol (tcp, udp)"}}},"PostgresWalHealth":{"type":"object","required":["probed_at","pg_wal_bytes","max_wal_size_bytes","archive_mode","archive_backlog","stale_slots","oldest_wal_age_secs","warnings"],"properties":{"archive_backlog":{"type":"integer","format":"int64","description":"Number of `archive_status/*.ready` files — un-shipped WAL segments."},"archive_command":{"type":["string","null"],"description":"The literal `archive_command` setting. May be empty or `/bin/true`\nwhen archiving is effectively disabled despite `archive_mode = on`."},"archive_mode":{"$ref":"#/components/schemas/ArchiveMode"},"archiver_failed_count":{"type":["integer","null"],"format":"int64"},"archiver_last_failed_at":{"type":["string","null"],"format":"date-time"},"max_wal_size_bytes":{"type":"integer","format":"int64","description":"`max_wal_size` setting in bytes (parsed from `pg_settings`)."},"oldest_wal_age_secs":{"type":"integer","format":"int64","description":"Age of the oldest WAL file in `pg_wal/` (seconds)."},"pg_wal_bytes":{"type":"integer","format":"int64","description":"Total size of files under `pg_wal/`, from `pg_ls_waldir()`."},"probed_at":{"type":"string","format":"date-time","description":"When the snapshot was taken."},"stale_slots":{"type":"array","items":{"$ref":"#/components/schemas/StaleSlot"}},"warnings":{"type":"array","items":{"$ref":"#/components/schemas/WalWarning"},"description":"Computed warnings, ordered by severity (critical first)."}}},"PresetConfigSchema":{"oneOf":[{"$ref":"#/components/schemas/DockerfilePresetConfig","description":"Configuration for Dockerfile preset"},{"$ref":"#/components/schemas/DockerComposePresetConfig","description":"Configuration for Docker Compose"},{"$ref":"#/components/schemas/NixpacksPresetConfig","description":"Configuration for Nixpacks provider selection and inline build plan"},{"$ref":"#/components/schemas/StaticPresetConfig","description":"Configuration for static site presets (Vite, Next.js, etc.)"}],"description":"Union type for preset configurations\nUse the appropriate configuration type based on your preset"},"PresetInfo":{"type":"object","description":"Detected preset information","required":["path","preset","preset_label","project_type"],"properties":{"compose_files":{"type":["array","null"],"items":{"type":"string"},"description":"Compose file paths found in the repository (only for docker-compose preset)"},"exposed_port":{"type":["integer","null"],"format":"int32","description":"Default exposed port for this preset"},"icon_url":{"type":["string","null"],"description":"Icon URL for this preset"},"path":{"type":"string","description":"Path where preset was detected (empty for root)"},"preset":{"type":"string","description":"Preset slug (e.g., \"nextjs\", \"fastapi\")"},"preset_label":{"type":"string","description":"Human-readable preset label"},"project_type":{"type":"string","description":"Project type (e.g., \"frontend\", \"backend\", \"fullstack\")"}}},"PresetResponse":{"type":"object","required":["slug","label","icon_url","project_type","description"],"properties":{"default_port":{"type":["integer","null"],"format":"int32","description":"Default port the application listens on (None for static sites)","example":3000,"minimum":0},"description":{"type":"string","description":"Description of what this preset does"},"icon_url":{"type":"string","description":"Icon URL for the preset"},"label":{"type":"string","description":"Display name/label for the preset"},"project_type":{"type":"string","description":"Project type (server or static)"},"slug":{"type":"string","description":"Unique identifier slug for the preset"}}},"PreviewGatewaySettings":{"type":"object","description":"Workspace preview gateway settings.\n\nThe preview gateway is a single shared Docker container that lives on the\n`temps-sandbox-net` network and routes requests to workspace sandbox dev\nservers based on the `Host` header (`ws--.`).\n`temps serve` reconciles this container on startup; these settings let an\noperator override the image, host port, and auto-upgrade behavior.","properties":{"auto_upgrade":{"type":"boolean","description":"When true (default), the supervisor will pull and apply the image\npinned in the Temps binary on every startup. When false, the\ncurrently-running image is left alone — operators upgrade manually\nfrom the settings UI.","default":true,"example":true},"host_port":{"type":"integer","format":"int32","description":"Host port to publish the gateway on (always bound to 127.0.0.1).\nPingora forwards `ws-*` traffic to this port after authenticating.","default":8090,"example":8090,"minimum":0},"image":{"type":"string","description":"Docker image reference for the gateway. Pinned per Temps release.\nOperators can override this to test a custom build.","default":"ghcr.io/gotempsh/temps-preview-gateway:latest","example":"ghcr.io/gotempsh/temps-preview-gateway:latest"},"shared_secret":{"type":"string","description":"Shared secret the host-side Pingora sends on every forwarded preview\nrequest via `X-Temps-Preview-Token`; the gateway rejects requests\nwithout it. Auto-generated on first boot, persisted in DB so the\nsecret is stable across `temps serve` restarts regardless of cwd,\n`TEMPS_DATA_DIR`, or data-dir changes. MUST be masked (`***`) in any\nAPI response — never expose it over HTTP.","default":"","example":""}}},"PreviewGatewaySettingsMasked":{"type":"object","description":"Preview gateway settings with `shared_secret` elided.","required":["image","host_port","auto_upgrade","shared_secret_set"],"properties":{"auto_upgrade":{"type":"boolean"},"host_port":{"type":"integer","format":"int32","minimum":0},"image":{"type":"string"},"shared_secret_set":{"type":"boolean"}}},"PreviewGatewaySettingsResponse":{"type":"object","required":["image","host_port","auto_upgrade","default_image","default_host_port"],"properties":{"auto_upgrade":{"type":"boolean"},"default_host_port":{"type":"integer","format":"int32","description":"The compile-time default host port.","minimum":0},"default_image":{"type":"string","description":"The compile-time default image — exposed so the UI can offer a\n\"Reset to default\" link without round-tripping."},"host_port":{"type":"integer","format":"int32","minimum":0},"image":{"type":"string"}}},"PreviewShareLinkBody":{"type":"object","description":"Request body for minting a preview share link.","required":["port"],"properties":{"path":{"type":["string","null"],"description":"Path the recipient lands on. Must be same-origin (start with a single\n`/`); anything else is replaced with `/` so a share link can never be\nturned into an open redirect."},"port":{"type":"integer","format":"int32","description":"Port inside the sandbox the preview serves on.","minimum":0},"ttl_seconds":{"type":["integer","null"],"format":"int64","description":"How long the link stays usable, in seconds. Clamped to 24 hours.\nDefaults to one hour — long enough to send to a reviewer, short enough\nthat a link pasted in a ticket does not stay live indefinitely.","minimum":0}}},"PreviewShareLinkResponse":{"type":"object","required":["url","expires_at"],"properties":{"expires_at":{"type":"integer","format":"int64","description":"Unix seconds after which the link stops working.","minimum":0},"url":{"type":"string","description":"The full link. Its fragment contains the grant and must be treated as a\ncredential; URL fragments are not sent to servers or in Referer headers."}}},"PricingResponse":{"type":"object","required":["models"],"properties":{"models":{"type":"array","items":{"$ref":"#/components/schemas/ModelPricing"}}}},"ProblemDetails":{"type":"object","description":"Representation of a Problem error to return to the client.\nFollows RFC 7807 - Problem Details for HTTP APIs","required":["title","extensions"],"properties":{"detail":{"type":["string","null"],"description":"A human-readable explanation specific to this occurrence of the problem","example":"The server encountered an unexpected condition"},"extensions":{"type":"object","description":"Additional properties of the problem","additionalProperties":true},"instance":{"type":["string","null"],"description":"A URI reference that identifies the specific occurrence of the problem","example":"/account/12345/msgs/abc"},"title":{"type":"string","description":"A short, human-readable summary of the problem type","example":"Internal Server Error"},"type":{"type":["string","null"],"description":"A URI reference that identifies the problem type","example":"https://example.com/probs/out-of-memory"}},"example":{"type":"https://example.com/probs/out-of-memory","title":"Internal Server Error","detail":"The server encountered an unexpected condition","instance":"/account/12345/msgs/abc","additional_info":"Custom field with additional details"}},"ProjectAccessResponse":{"type":"object","required":["id","project_id","team_id","role","granted_by","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"},"granted_by":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"role":{"$ref":"#/components/schemas/TeamRole"},"team_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"}}},"ProjectConfiguration":{"type":"object","description":"Project-level configuration","required":["name","slug","project_type","is_web_app"],"properties":{"is_web_app":{"type":"boolean","description":"Whether this is a web application"},"name":{"type":"string","description":"Proposed project name"},"project_type":{"$ref":"#/components/schemas/ProjectType","description":"Project type"},"slug":{"type":"string","description":"Proposed slug (URL-safe identifier)"}}},"ProjectDSNResponse":{"type":"object","required":["id","project_id","name","public_key","dsn","created_at","is_active","event_count"],"properties":{"created_at":{"type":"string"},"deployment_id":{"type":["integer","null"],"format":"int32"},"dsn":{"type":"string"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_count":{"type":"integer","format":"int64"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"public_key":{"type":"string"}}},"ProjectDashboardAnalytics":{"type":"object","description":"Analytics data for a single project in the dashboard batch response","required":["project_id","unique_visitors","previous_unique_visitors","hourly_visits"],"properties":{"hourly_visits":{"type":"array","items":{"$ref":"#/components/schemas/EventTimeline"},"description":"Hourly sparkline data points"},"previous_unique_visitors":{"type":"integer","format":"int64","description":"Unique visitor count in the previous period (same duration, shifted back)"},"project_id":{"type":"integer","format":"int32"},"trend_percentage":{"type":["number","null"],"format":"double","description":"Percentage change from previous period (positive = growth, negative = decline)\nNull when previous period had zero visitors (no baseline to compare)"},"unique_visitors":{"type":"integer","format":"int64","description":"Unique visitor count in the current time range"}}},"ProjectHealthSummary":{"type":"object","description":"Health summary for a single project (last 1 hour)","required":["project_id","total_requests","total_errors","avg_response_time_ms","error_rate","status"],"properties":{"avg_response_time_ms":{"type":"number","format":"double","description":"Average response time in ms"},"error_rate":{"type":"number","format":"double","description":"Error rate as a percentage (0-100)"},"project_id":{"type":"integer","format":"int32"},"status":{"type":"string","description":"Health status: \"healthy\", \"degraded\", \"down\", \"unknown\""},"total_errors":{"type":"integer","format":"int64","description":"Total server errors (status >= 500) in the period"},"total_requests":{"type":"integer","format":"int64","description":"Total requests in the period"}}},"ProjectInfo":{"type":"object","required":["id","slug","created_at"],"properties":{"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"id":{"type":"integer","format":"int32"},"slug":{"type":"string"}}},"ProjectMonitorHealth":{"type":"object","description":"Health summary for a single project based on its production monitors","required":["project_id","status"],"properties":{"project_id":{"type":"integer","format":"int32"},"status":{"type":"string","description":"Overall status: \"operational\", \"degraded\", \"down\", or \"no_monitors\""}}},"ProjectPresetResponse":{"type":"object","required":["path","preset","presetLabel","projectType"],"properties":{"composeFiles":{"type":["array","null"],"items":{"type":"string"},"description":"Compose file paths found in the repository (only for docker-compose preset)"},"exposedPort":{"type":["integer","null"],"format":"int32","description":"Default exposed port for this preset (e.g., 3000 for Next.js, 8000 for FastAPI)"},"iconUrl":{"type":["string","null"],"description":"Icon URL for the preset"},"path":{"type":"string"},"preset":{"type":"string"},"presetLabel":{"type":"string"},"projectType":{"type":"string","description":"Project type category (e.g., \"frontend\", \"backend\", \"fullstack\")"}}},"ProjectQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"ProjectRef":{"type":"object","description":"A lightweight project descriptor included in `UnifiedTrace`.","required":["project_id","project_name","project_slug"],"properties":{"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"project_slug":{"type":"string","description":"URL slug used to link a span back into its owning project's trace view."}}},"ProjectResponse":{"type":"object","required":["id","slug","name","directory","main_branch","created_at","updated_at","deployment_config","attack_mode","ai_write_actions_enabled","error_source_context_enabled","enable_preview_environments","preview_envs_on_demand","preview_envs_idle_timeout_seconds","preview_envs_wake_timeout_seconds","source_type","cross_project_trace_sharing"],"properties":{"ai_alert_summaries_enabled":{"type":["boolean","null"],"description":"Opt-in to AI summarization of metric alert notifications (NULL/false = off)."},"ai_debug_chat_enabled":{"type":["boolean","null"],"description":"Opt-in to AI debugging chat, e.g. on deployment failures (NULL/false = off)."},"ai_write_actions_enabled":{"type":"boolean","description":"Opt-in to AI propose-then-confirm write capability (false = off)."},"attack_mode":{"type":"boolean","description":"Attack mode - when enabled, requires CAPTCHA verification for all project environments"},"created_at":{"type":"integer","format":"int64"},"cross_project_trace_sharing":{"type":"boolean","description":"ADR-027 Phase 3 opt-out: when false, this project's traces are suppressed\nfrom cross-project discovery results. Default true (consistent with the\nOSS global-observability model where any OtelRead holder can query any\nproject's telemetry)."},"deployment_config":{"$ref":"#/components/schemas/DeploymentConfig","description":"Deployment configuration (resources, autoscaling, features)"},"directory":{"type":"string"},"enable_preview_environments":{"type":"boolean","description":"Enable automatic preview environment creation for each branch"},"error_source_context_enabled":{"type":"boolean","description":"Opt-in to native error-tracking source context (false = off). When on,\nTemps stores uploaded source files and shows source code in stack traces."},"error_source_root":{"type":["string","null"],"description":"Where auto-capture reads source from (relative to the checkout). Null =\nthe deployment's Docker build context."},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"git_url":{"type":["string","null"],"description":"Git clone URL for the repository (used for public repos without a provider connection)"},"gitlab_webhook_id":{"type":["integer","null"],"format":"int32","description":"GitLab webhook ID installed on the connected repository.\n`null` when no GitLab webhook is installed (not connected to GitLab,\nor webhook was removed / never created).","example":42},"id":{"type":"integer","format":"int32"},"last_deployment":{"type":["integer","null"],"format":"int64"},"main_branch":{"type":"string"},"name":{"type":"string"},"preset":{"type":["string","null"]},"preset_config":{"description":"Preset-specific configuration (Dockerfile path, build context, etc.)"},"preview_envs_idle_timeout_seconds":{"type":"integer","format":"int32","description":"Idle timeout (seconds) for on-demand preview environments."},"preview_envs_on_demand":{"type":"boolean","description":"When true, newly-created preview environments default to on-demand mode\n(containers stop after the configured idle timeout to save resources)."},"preview_envs_wake_timeout_seconds":{"type":"integer","format":"int32","description":"Wake timeout (seconds) for on-demand preview environments."},"repo_name":{"type":["string","null"]},"repo_owner":{"type":["string","null"]},"slug":{"type":"string"},"source_type":{"$ref":"#/components/schemas/SourceType","description":"Source type for deployments (git, docker_image, or static_files)"},"updated_at":{"type":"integer","format":"int64"}}},"ProjectSecretEnvironmentInfo":{"type":"object","required":["id","name","main_url"],"properties":{"id":{"type":"integer","format":"int32"},"main_url":{"type":"string"},"name":{"type":"string"}}},"ProjectSecretResponse":{"type":"object","description":"Project secret metadata. There is deliberately no `value` field — secret\nplaintext is never returned after creation. Callers that need the value\nmust read it from the mounted file inside the container.","required":["id","project_id","key","include_in_preview","created_at","updated_at","environments"],"properties":{"created_at":{"type":"integer","format":"int64"},"environments":{"type":"array","items":{"$ref":"#/components/schemas/ProjectSecretEnvironmentInfo"}},"id":{"type":"integer","format":"int32"},"include_in_preview":{"type":"boolean"},"key":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"updated_at":{"type":"integer","format":"int64"}}},"ProjectServiceInfo":{"type":"object","required":["id","project","service"],"properties":{"id":{"type":"integer","format":"int32"},"project":{"$ref":"#/components/schemas/ProjectInfo"},"service":{"$ref":"#/components/schemas/ExternalServiceInfo"}}},"ProjectStatisticsResponse":{"type":"object","required":["total_count"],"properties":{"total_count":{"type":"integer","format":"int64"}}},"ProjectStatsBreakdown":{"type":"object","required":["project_id","unique_visitors","total_visits","total_page_views","bounce_rate","engagement_rate"],"properties":{"bounce_rate":{"type":"number","format":"double"},"engagement_rate":{"type":"number","format":"double"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":["string","null"]},"total_page_views":{"type":"integer","format":"int64"},"total_visits":{"type":"integer","format":"int64"},"unique_visitors":{"type":"integer","format":"int64"}}},"ProjectType":{"type":"string","description":"Project type enumeration","enum":["static","docker","buildpack","git"]},"ProjectUsageInfoResponse":{"type":"object","required":["id","name","slug","connection_id","connection_name"],"properties":{"connection_id":{"type":"integer","format":"int32"},"connection_name":{"type":"string"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"slug":{"type":"string"}}},"ProjectsHealthResponse":{"type":"object","description":"Batch health summary response","required":["projects"],"properties":{"projects":{"type":"object","description":"Health summaries keyed by project ID","additionalProperties":{"$ref":"#/components/schemas/ProjectHealthSummary"},"propertyNames":{"type":"string"}}}},"ProjectsMonitorHealthResponse":{"type":"object","description":"Batch response for projects health","required":["projects"],"properties":{"projects":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/ProjectMonitorHealth"},"propertyNames":{"type":"string"}}}},"PromoteDeploymentRequest":{"type":"object","required":["target_environment_id"],"properties":{"target_environment_id":{"type":"integer","format":"int32","description":"Target environment ID to promote the deployment to"}}},"PropertyBreakdownItem":{"type":"object","required":["value","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"percentage":{"type":"number","format":"double"},"value":{"type":"string"}}},"PropertyBreakdownQuery":{"type":"object","description":"Query parameters for property breakdown (group by column)","required":["start_date","end_date","group_by"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level"},"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment filter"},"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment filter"},"event_name":{"type":["string","null"],"description":"Optional event name filter (e.g., \"page_view\", \"click\")"},"filter_browser":{"type":["string","null"],"description":"Filter by browser name (for browser version drill-downs)"},"filter_channel":{"type":["string","null"],"description":"Filter by channel name (for channel -> referrer drill-downs)"},"filter_country":{"type":["string","null"],"description":"Filter by country (for region/city drill-downs). Requires geolocation join."},"filter_os":{"type":["string","null"],"description":"Filter by operating system name (for OS version drill-downs)"},"filter_referrer":{"type":["string","null"],"description":"Filter by referrer hostname (for referrer -> pages drill-downs)"},"filter_region":{"type":["string","null"],"description":"Filter by region (for city drill-downs). Requires geolocation join."},"group_by":{"$ref":"#/components/schemas/PropertyColumn","description":"Property column to group by"},"include_crawlers":{"type":["boolean","null"],"description":"Include crawler/bot traffic (default: false). Off by default so the\nbreakdown percentages share a denominator with the headline counts,\nwhich always exclude crawlers."},"limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of results to return (default: 20, max: 100)"},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"PropertyBreakdownResponse":{"type":"object","required":["property","items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/PropertyBreakdownItem"}},"property":{"type":"string"},"total":{"type":"integer","format":"int64"}}},"PropertyColumn":{"type":"string","enum":["channel","device_type","browser","browser_version","operating_system","operating_system_version","utm_source","utm_medium","utm_campaign","utm_term","utm_content","referrer_hostname","language","event_type","event_name","page_path","pathname","country","region","city"]},"PropertyTimelineItem":{"type":"object","required":["timestamp","value","count"],"properties":{"count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"},"value":{"type":"string"}}},"PropertyTimelineQuery":{"type":"object","description":"Query parameters for property timeline (group by column over time)","required":["start_date","end_date","group_by"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level"},"bucket_size":{"type":["string","null"],"description":"Time bucket size: \"hour\", \"day\", \"week\", \"month\" (default: auto-detect)"},"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment filter"},"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment filter"},"event_name":{"type":["string","null"],"description":"Optional event name filter"},"group_by":{"$ref":"#/components/schemas/PropertyColumn","description":"Property column to group by"},"include_crawlers":{"type":["boolean","null"],"description":"Include crawler/bot traffic (default: false). See\n[`PropertyBreakdownQuery::include_crawlers`]."},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"PropertyTimelineResponse":{"type":"object","required":["property","bucket_size","items"],"properties":{"bucket_size":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/PropertyTimelineItem"}},"property":{"type":"string"}}},"Protocol":{"type":"string","description":"Network protocol","enum":["tcp","udp"]},"ProviderCatalogDto":{"type":"object","description":"One catalog entry rendered for the settings UI.","required":["id","name","install_command","auth_command","auth_flavors","models","credential_saved","supports_max_turns"],"properties":{"auth_command":{"type":"string"},"auth_flavors":{"type":"array","items":{"$ref":"#/components/schemas/AuthFlavorDto"}},"credential_saved":{"type":"boolean","description":"True when a credential is currently saved for this provider in the\nsettings JSON. Lets the UI render \"Configured\" badges without the\nfrontend having to inspect the encrypted blob."},"current_auth_type":{"type":["string","null"],"description":"Currently saved auth flavor id (when `credential_saved` is true).\n`None` when no credential is saved yet."},"default_model":{"type":["string","null"],"description":"Currently saved default model id for this provider, if one was\npicked. `None` means \"use the CLI's own default\" — the UI renders\nthat as \"Use provider default\"."},"id":{"type":"string"},"install_command":{"type":"string"},"max_turns_analysis":{"type":["integer","null"],"format":"int32","description":"Default max turns for the autofixer analysis phase. `None` = built-in\ndefault (10). Only enforced for CLIs with a turn flag (Claude Code)."},"max_turns_feedback":{"type":["integer","null"],"format":"int32","description":"Default max turns for autofixer feedback rounds. `None` = built-in\ndefault (10)."},"max_turns_fix":{"type":["integer","null"],"format":"int32","description":"Default max turns for the autofixer fix phase. `None` = built-in\ndefault (20)."},"models":{"type":"array","items":{"type":"string"},"description":"Model ids this provider accepts, in display order. The first entry is\nthe recommended default. Empty when the provider doesn't expose model\nselection (e.g. OpenCode), which the UI uses to hide the dropdown."},"name":{"type":"string"},"supports_max_turns":{"type":"boolean","description":"True when this provider's CLI supports enforcing a turn cap. False\nfor Codex/OpenCode, which run to completion — the UI labels their\nmax-turns inputs accordingly."}}},"ProviderCatalogResponse":{"type":"object","required":["default_provider","providers"],"properties":{"default_provider":{"type":"string","description":"Active provider id from `agent_sandbox.default_provider`. The settings\nUI uses this to highlight which card is the active one."},"providers":{"type":"array","items":{"$ref":"#/components/schemas/ProviderCatalogDto"}}}},"ProviderConfig":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/StripeConfig"},{"type":"object","required":["provider"],"properties":{"provider":{"type":"string","enum":["stripe"]}}}]},{"allOf":[{"$ref":"#/components/schemas/LemonSqueezyConfig"},{"type":"object","required":["provider"],"properties":{"provider":{"type":"string","enum":["lemon_squeezy"]}}}]}],"description":"Provider-specific integration settings persisted in\n`revenue_integrations.config`.\n\nThe tag is the lowercase provider name, so adding a new provider\nmeans adding a new variant and the existing rows are untouched.\nOld rows (pre-config) and rows with `NULL` config are treated as\n\"accept all events, no filtering\" via [`ProviderConfig::default_for`]."},"ProviderConfigMasked":{"type":"object","required":["auth_type","credential_saved","extra"],"properties":{"auth_type":{"type":"string"},"credential_saved":{"type":"boolean","description":"True if a credential is stored for this provider. The encrypted blob\nis never returned over HTTP."},"default_model":{"type":["string","null"]},"extra":{}}},"ProviderDeletionCheckResponse":{"type":"object","required":["can_delete","projects_in_use","message"],"properties":{"can_delete":{"type":"boolean"},"message":{"type":"string"},"projects_in_use":{"type":"array","items":{"$ref":"#/components/schemas/ProjectUsageInfoResponse"}}}},"ProviderDescriptor":{"type":"object","required":["name","display_name","recommended_events"],"properties":{"display_name":{"type":"string"},"name":{"type":"string"},"recommended_events":{"type":"array","items":{"type":"string"}}}},"ProviderKeyResponse":{"type":"object","required":["id","provider","display_name","api_key_masked","is_active","created_at","updated_at"],"properties":{"api_key_masked":{"type":"string","description":"Masked API key (only last 4 chars visible)"},"base_url":{"type":["string","null"]},"created_at":{"type":"string"},"default_model":{"type":["string","null"],"description":"Model id this provider serves (NULL → per-provider default)."},"display_name":{"type":"string"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"provider":{"type":"string"},"updated_at":{"type":"string"}}},"ProviderMetadata":{"type":"object","required":["service_type","display_name","description","icon_url","color"],"properties":{"color":{"type":"string","example":"#336791"},"description":{"type":"string","example":"Relational database management system"},"display_name":{"type":"string","example":"PostgreSQL"},"icon_url":{"type":"string","example":"https://cdn.simpleicons.org/postgresql"},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute"}}},"ProviderResponse":{"type":"object","required":["id","name","provider_type","auth_method","is_active","is_default","created_at","updated_at"],"properties":{"auth_method":{"type":"string"},"base_url":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"is_default":{"type":"boolean"},"name":{"type":"string"},"provider_type":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}},"ProviderUsage":{"type":"object","required":["provider","request_count","input_tokens","output_tokens","avg_latency_ms","error_count"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"error_count":{"type":"integer","format":"int64"},"input_tokens":{"type":"integer","format":"int64"},"output_tokens":{"type":"integer","format":"int64"},"provider":{"type":"string"},"request_count":{"type":"integer","format":"int64"}}},"ProvisionResponse":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/DomainError"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["error"]}}}]},{"allOf":[{"$ref":"#/components/schemas/DomainResponse"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["complete"]}}}]},{"allOf":[{"$ref":"#/components/schemas/DomainChallengeResponse"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["pending"]}}}]}]},"ProxyLogResponse":{"type":"object","description":"Response model for proxy logs","required":["id","timestamp","method","path","host","status_code","request_source","is_system_request","routing_status","request_id"],"properties":{"bot_name":{"type":["string","null"]},"browser":{"type":["string","null"]},"browser_version":{"type":["string","null"]},"cache_status":{"type":["string","null"]},"client_ip":{"type":["string","null"]},"container_id":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"device_type":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"error_message":{"type":["string","null"]},"host":{"type":"string"},"id":{"type":"integer","format":"int32"},"ip_geolocation_id":{"type":["integer","null"],"format":"int32"},"is_bot":{"type":["boolean","null"]},"is_system_request":{"type":"boolean"},"method":{"type":"string"},"operating_system":{"type":["string","null"]},"path":{"type":"string"},"project_id":{"type":["integer","null"],"format":"int32"},"query_string":{"type":["string","null"]},"referrer":{"type":["string","null"]},"request_id":{"type":"string"},"request_size_bytes":{"type":["integer","null"],"format":"int64"},"request_source":{"type":"string"},"response_size_bytes":{"type":["integer","null"],"format":"int64"},"response_time_ms":{"type":["integer","null"],"format":"int32"},"routing_status":{"type":"string"},"session_id":{"type":["integer","null"],"format":"int32"},"status_code":{"type":"integer","format":"int32"},"timestamp":{"type":"string"},"upstream_host":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":["integer","null"],"format":"int32"}}},"ProxyLogsPaginatedResponse":{"type":"object","description":"Paginated response for proxy logs","required":["logs","total","page","page_size","total_pages"],"properties":{"logs":{"type":"array","items":{"$ref":"#/components/schemas/ProxyLogResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0},"total_pages":{"type":"integer","format":"int64","minimum":0}}},"PublicHostnameStrategy":{"type":"string","description":"Public hostname generation mode for Temps-managed preview routes.\n\nThe mode is stored per managed domain (`dns_managed_domains.generated_hostname_mode`)\nrather than globally, so a provider such as Cloudflare can offer the flat layout\nrequired by its Universal SSL wildcard cert without changing every domain's behaviour.","enum":["standard","flat"]},"PublicPresetResponse":{"type":"object","description":"Response for preset detection","required":["branch","presets"],"properties":{"branch":{"type":"string","description":"Branch name where presets were detected"},"presets":{"type":"array","items":{"$ref":"#/components/schemas/PresetInfo"},"description":"List of detected presets"}}},"PublicRepositoryInfo":{"type":"object","description":"Public repository information","required":["owner","name","full_name","default_branch","stars","forks"],"properties":{"default_branch":{"type":"string","description":"Default branch name"},"description":{"type":["string","null"],"description":"Repository description"},"forks":{"type":"integer","format":"int32","description":"Fork count"},"full_name":{"type":"string","description":"Full repository name (owner/repo)"},"language":{"type":["string","null"],"description":"Primary programming language"},"name":{"type":"string","description":"Repository name"},"owner":{"type":"string","description":"Repository owner"},"stars":{"type":"integer","format":"int32","description":"Star count"}}},"PurgeLogsRequest":{"type":"object","required":["before"],"properties":{"before":{"type":"string","description":"Delete all logs before this timestamp (ISO 8601)"}}},"PushImageRequest":{"type":"object","description":"Request to push an external image","required":["image_ref"],"properties":{"image_ref":{"type":"string"},"metadata":{}}},"PushedExternalImageResponse":{"type":"object","description":"Response for in-memory external image operations (legacy push flow).\n\nRenamed to avoid shadowing the richer database-backed `ExternalImageResponse`\nin `handlers/remote_deployments.rs`. The two types serve different routes\n(`/images` ephemeral push vs `/external-images` registered images).","required":["id","image_ref","pushed_at"],"properties":{"digest":{"type":["string","null"]},"id":{"type":"string"},"image_ref":{"type":"string"},"pushed_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"size":{"type":["integer","null"],"format":"int64","minimum":0}}},"QueryDataRequest":{"type":"object","properties":{"filters":{"description":"JSON filters (backend-specific format)"},"limit":{"type":"integer","description":"Maximum number of rows to return","example":100,"minimum":0},"offset":{"type":"integer","description":"Number of rows to skip","example":0,"minimum":0},"sort_by":{"type":["string","null"],"description":"Sort by field name"},"sort_order":{"type":["string","null"],"description":"Sort order (asc/desc)"}}},"QueryDataResponse":{"type":"object","required":["fields","rows","total_count","returned_count","execution_time_ms","truncated"],"properties":{"execution_time_ms":{"type":"integer","format":"int64","description":"Query execution time in milliseconds","example":45,"minimum":0},"fields":{"type":"array","items":{"$ref":"#/components/schemas/FieldResponse"},"description":"Field definitions"},"returned_count":{"type":"integer","description":"Number of rows returned in this response","example":100,"minimum":0},"rows":{"type":"array","items":{},"description":"Data rows (array of JSON objects)"},"total_count":{"type":"integer","format":"int64","description":"Total number of rows matching the query (before limit/offset)","example":1234,"minimum":0},"truncated":{"type":"boolean","description":"Whether rows were dropped from this response to stay inside the byte\nbudget.\n\n`returned_count` is always the number of rows actually present, so a\ntruncated page is still internally consistent — but a caller comparing\nit against the requested limit would otherwise conclude the table simply\nended. Reported explicitly so a partial page is never mistaken for a\ncomplete one, by a human, a script, or a model reading a tool result.","example":false}}},"QuotaResponse":{"type":"object","required":["quota"],"properties":{"quota":{"$ref":"#/components/schemas/StorageQuota"}}},"RateLimitConfig":{"type":"object","description":"Rate limiting configuration (subset of global RateLimitSettings)","properties":{"blacklistIps":{"type":"array","items":{"type":"string"},"description":"Blacklist specific IPs for this project/environment"},"maxRequestsPerHour":{"type":["integer","null"],"format":"int32","description":"Override rate limit per hour","minimum":0},"maxRequestsPerMinute":{"type":["integer","null"],"format":"int32","description":"Override rate limit per minute","minimum":0},"whitelistIps":{"type":"array","items":{"type":"string"},"description":"Whitelist specific IPs for this project/environment"}}},"RateLimitSettings":{"type":"object","properties":{"blacklist_ips":{"type":"array","items":{"type":"string"},"default":[]},"enabled":{"type":"boolean","default":false},"max_requests_per_hour":{"type":"integer","format":"int32","default":1000,"minimum":0},"max_requests_per_minute":{"type":"integer","format":"int32","default":60,"minimum":0},"whitelist_ips":{"type":"array","items":{"type":"string"},"default":[]}}},"ReachabilityStatus":{"type":"string","description":"Email reachability status","enum":["safe","risky","invalid","unknown"]},"ReadFileResponse":{"type":"object","required":["path","contents_b64","size"],"properties":{"contents_b64":{"type":"string","description":"File contents, base64-encoded. Symmetric with `WriteFileBody`."},"path":{"type":"string"},"size":{"type":"integer","format":"int64","minimum":0}}},"ReadRowsQuery":{"type":"object","description":"Query-string form of [`QueryDataRequest`] for the read-only `GET` rows\nendpoint.\n\nThe `POST` variant exists because filters are arbitrary backend-specific\nJSON. Reading rows is nonetheless a *read*, and the AI agent's tool index\nis GET-only by construction, so the same capability has to be reachable\nwithout a body. `filter` therefore carries the JSON as a string.","properties":{"filter":{"type":["string","null"],"description":"Backend-specific filter, JSON-encoded. Fetch the expected shape from\nthe `filter_schema` field of the explorer-support endpoint — e.g.\n`{\"where\":\"created_at > now() - interval '7 days'\"}` for SQL sources."},"limit":{"type":"integer","description":"Maximum number of rows to return","example":100,"minimum":0},"offset":{"type":"integer","description":"Number of rows to skip","example":0,"minimum":0},"sort_by":{"type":["string","null"],"description":"Sort by field name"},"sort_order":{"type":["string","null"],"description":"Sort order (asc/desc)"}}},"RecentActivityQuery":{"type":"object","description":"Query parameters for recent activity endpoint","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32","description":"Environment ID (optional)"},"limit":{"type":["integer","null"],"format":"int32","description":"Max number of events to return (default: 50, max: 100)"},"project_id":{"type":"integer","format":"int32","description":"Project ID"},"since_id":{"type":["integer","null"],"format":"int64","description":"Return events with ID greater than this (for cursor-based polling)"}}},"RecentActivityResponse":{"type":"object","description":"Response for recent activity events endpoint","required":["events","count"],"properties":{"count":{"type":"integer","description":"Total events returned","minimum":0},"events":{"type":"array","items":{"$ref":"#/components/schemas/ActivityEvent"},"description":"Recent events, newest first"}}},"RecentEventResponse":{"type":"object","required":["occurred_at","event_type"],"properties":{"amount_minor":{"type":["integer","null"],"format":"int64"},"currency":{"type":["string","null"]},"customer_ref":{"type":["string","null"]},"event_type":{"type":"string"},"mrr_minor":{"type":["integer","null"],"format":"int64"},"occurred_at":{"type":"string","format":"date-time"}}},"RecentQueryParams":{"type":"object","properties":{"conversation_id":{"type":["string","null"],"description":"Filter by conversation ID"},"cost_gt":{"type":["integer","null"],"format":"int64","description":"Cost strictly greater-than, in microcents"},"cost_gte":{"type":["integer","null"],"format":"int64","description":"Cost greater-than-or-equal, in microcents"},"cost_lt":{"type":["integer","null"],"format":"int64","description":"Cost strictly less-than, in microcents"},"cost_lte":{"type":["integer","null"],"format":"int64","description":"Cost less-than-or-equal, in microcents"},"limit":{"type":["integer","null"],"format":"int64","description":"Page size (defaults to 20, max 50)","minimum":0},"model":{"type":["string","null"],"description":"Filter by model name"},"offset":{"type":["integer","null"],"format":"int64","description":"Number of results to skip for pagination (defaults to 0)","minimum":0},"provider":{"type":["string","null"],"description":"Filter by provider name"},"status":{"type":["integer","null"],"format":"int32","description":"Filter by HTTP status code (exact match)"},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"tokens_gt":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) strictly greater-than"},"tokens_gte":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) greater-than-or-equal"},"tokens_lt":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) strictly less-than"},"tokens_lte":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) less-than-or-equal"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"RecordExposureRequest":{"type":"object","description":"Keys a running app actually evaluated since its last report.","required":["keys"],"properties":{"keys":{"type":"array","items":{"type":"string"},"description":"Flag keys evaluated since the last report. Unknown keys are ignored.","example":["checkout.v2","api.rate_limit"]}}},"RecordExposureResponse":{"type":"object","required":["recorded"],"properties":{"recorded":{"type":"integer","format":"int64","description":"How many keys were accepted for processing.\n\nDeliberately not the number of rows updated: echoing that back would\nlet a caller post a single candidate key and read the result as \"this\nflag exists\", turning the endpoint into an existence oracle.","minimum":0}}},"RecordListResponse":{"type":"object","description":"Record list response","required":["records"],"properties":{"records":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecord"}}}},"RecoveryTarget":{"oneOf":[{"type":"object","description":"Recover to a specific timestamp.","required":["time","kind"],"properties":{"kind":{"type":"string","enum":["time"]},"time":{"type":"string","format":"date-time"}}},{"type":"object","description":"Recover to a specific transaction id (Postgres).","required":["xid","kind"],"properties":{"kind":{"type":"string","enum":["xid"]},"xid":{"type":"string"}}},{"type":"object","description":"Recover to a specific log sequence number (Postgres).","required":["lsn","kind"],"properties":{"kind":{"type":"string","enum":["lsn"]},"lsn":{"type":"string"}}},{"type":"object","description":"Recover to a named restore point created via `pg_create_restore_point` (Postgres).","required":["name","kind"],"properties":{"kind":{"type":"string","enum":["name"]},"name":{"type":"string"}}}],"description":"Engine-specific recovery target for PITR.\n\nPostgres honors all variants; Redis/Mongo/S3 will likely reject non-Time\nvariants or define their own semantics when they grow PITR support."},"ReferrerCount":{"type":"object","required":["referrer","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"percentage":{"type":"number","format":"double"},"referrer":{"type":"string"}}},"ReferrersAnalyticsQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"RegenerateDSNRequest":{"type":"object","properties":{"base_url":{"type":["string","null"]}}},"RegisterImageRequest":{"type":"object","required":["image_ref"],"properties":{"digest":{"type":["string","null"],"description":"Image digest (sha256:...)","example":"sha256:abc123def456"},"image_ref":{"type":"string","description":"Docker image reference (e.g., \"ghcr.io/org/app:v1.0\")","example":"ghcr.io/myorg/myapp:v1.0"},"metadata":{"description":"Additional metadata"},"tag":{"type":["string","null"],"description":"Image tag","example":"v1.0"}}},"RegisterNodeApiRequest":{"type":"object","required":["name","token","address","private_address"],"properties":{"address":{"type":"string","description":"Node's reachable address (e.g., \"10.100.0.2\" or \"192.168.1.50\")"},"architecture":{"type":["string","null"],"description":"Container platform of this node's Docker daemon (`linux/amd64`,\n`linux/arm64`). Optional: agents older than multi-arch support omit it\nand the value is learned from the first heartbeat instead."},"csr_pem":{"type":["string","null"],"description":"Node-generated certificate signing request (PEM) for multi-node mTLS\n(ADR-020 WS-2.1). When present, the control plane signs it with the\ncluster CA and returns the leaf + CA cert. Optional — token-only nodes\n(legacy / edge) still register without one."},"edge_public_key":{"type":["string","null"],"description":"X25519 public key for ECIES certificate encryption (base64-encoded, edge nodes only)"},"join_token":{"type":["string","null"],"description":"Join token to authorize this registration (must match the token generated in Settings)"},"labels":{"description":"Labels for scheduling (e.g., {\"region\": \"us-east\", \"gpu\": \"true\"})"},"name":{"type":"string","description":"Unique name for this node"},"prior_token":{"type":["string","null"],"description":"The node's *current* token, supplied to prove possession when\nre-registering (changing the identity of) a node that already exists.\nOptional; only needed to rebind a still-live node. (ADR-020 WS-1.2.)"},"private_address":{"type":"string","description":"Private/WireGuard address for inter-node communication"},"public_endpoint":{"type":["string","null"],"description":"Public endpoint for WireGuard (e.g., \"203.0.113.1:51820\")"},"role":{"type":["string","null"],"description":"Node role (default: \"worker\")"},"token":{"type":"string","description":"Registration token (plaintext, will be hashed before storage)"},"wg_public_key":{"type":["string","null"],"description":"WireGuard public key"}}},"RegisterNodeResponse":{"type":"object","required":["id","name","status","message"],"properties":{"ca_cert_pem":{"type":["string","null"],"description":"The cluster CA certificate (PEM) the node pins as its trust root.\nPresent only when a `csr_pem` was supplied. (ADR-020 WS-2.1.)"},"cert_pem":{"type":["string","null"],"description":"The signed per-node leaf certificate (PEM) the agent serves as its TLS\nserver cert. Present only when a `csr_pem` was supplied. (ADR-020 WS-2.1.)"},"id":{"type":"integer","format":"int32"},"message":{"type":"string"},"name":{"type":"string"},"status":{"type":"string"}}},"RegisterRequest":{"type":"object","required":["email","password","name"],"properties":{"email":{"type":"string"},"name":{"type":"string"},"password":{"type":"string"}}},"ReinstallWebhookResponse":{"type":"object","description":"Response for `POST /projects/{project_id}/gitlab/reinstall-webhook`","required":["hook_id","message"],"properties":{"hook_id":{"type":"integer","format":"int32","description":"The new GitLab hook ID that was installed."},"message":{"type":"string","description":"Human-readable status message."}}},"ReleaseListResponse":{"type":"object","required":["releases"],"properties":{"releases":{"type":"array","items":{"type":"string"}}}},"ReloadResponse":{"type":"object","description":"Response from the reload endpoint.","required":["loaded","plugins","message"],"properties":{"loaded":{"type":"integer","description":"Number of plugins successfully loaded after reload","minimum":0},"message":{"type":"string","description":"Human-readable status message"},"plugins":{"type":"array","items":{"type":"string"},"description":"Names of loaded plugins"}}},"RemoteDeploymentResponse":{"type":"object","required":["id","project_id","environment_id","slug","state","source_type","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"environment_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"slug":{"type":"string"},"source_type":{"type":"string"},"state":{"type":"string"}}},"RemoveNodeResponse":{"type":"object","required":["id","message"],"properties":{"id":{"type":"integer","format":"int32"},"message":{"type":"string"}}},"RenameConversationRequest":{"type":"object","required":["title"],"properties":{"title":{"type":"string","description":"New human-facing title. Trimmed; must be non-empty after trimming."}}},"RepositoryListQuery":{"type":"object","properties":{"direction":{"type":["string","null"]},"language":{"type":["string","null"]},"owner":{"type":["string","null"]},"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0},"private":{"type":["boolean","null"]},"search":{"type":["string","null"]},"sort":{"type":["string","null"]}}},"RepositoryListResponse":{"type":"object","required":["repositories","total_count"],"properties":{"repositories":{"type":"array","items":{"$ref":"#/components/schemas/RepositoryResponse"}},"total_count":{"type":"integer","minimum":0}}},"RepositoryPresetResponse":{"type":"object","required":["repository_id","owner","name","presets","calculated_at"],"properties":{"calculated_at":{"type":"string","format":"date-time"},"name":{"type":"string"},"owner":{"type":"string"},"presets":{"type":"array","items":{"$ref":"#/components/schemas/ProjectPresetResponse"}},"repository_id":{"type":"integer","format":"int32"}}},"RepositoryResponse":{"type":"object","required":["id","owner","name","full_name","private","default_branch","created_at","updated_at","pushed_at","git_provider_connection_id"],"properties":{"clone_url":{"type":["string","null"],"description":"HTTPS clone URL (e.g., https://github.com/owner/repo.git)"},"created_at":{"type":"string","format":"date-time"},"default_branch":{"type":"string"},"description":{"type":["string","null"]},"full_name":{"type":"string"},"git_provider_connection_id":{"type":"integer","format":"int32","description":"ID of the git provider connection this repository was synced from."},"id":{"type":"integer","format":"int32"},"language":{"type":["string","null"]},"name":{"type":"string"},"owner":{"type":"string"},"preset":{"type":["array","null"],"items":{"$ref":"#/components/schemas/ProjectPresetResponse"}},"private":{"type":"boolean"},"pushed_at":{"type":"string","format":"date-time"},"ssh_url":{"type":["string","null"],"description":"SSH clone URL (e.g., git@github.com:owner/repo.git)"},"updated_at":{"type":"string","format":"date-time"}}},"RepositorySyncStartedResponse":{"type":"object","description":"Returned by `POST /git-connections/{id}/sync` to acknowledge that a\nsync has been kicked off in the background. Clients should poll the\nconnection's `syncing` and `synced_repository_count` fields to track\nprogress rather than waiting on this response.","required":["connection_id","syncing","started_at"],"properties":{"connection_id":{"type":"integer","format":"int32"},"started_at":{"type":"string","format":"date-time"},"syncing":{"type":"boolean"}}},"RequestRow":{"type":"object","required":["id","ts","method","host","path","status","request_headers","response_headers","headers_truncated"],"properties":{"client_ip":{"type":["string","null"]},"country":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_group_id":{"type":["integer","null"],"format":"int32"},"headers_truncated":{"type":"boolean"},"host":{"type":"string"},"id":{"type":"string","description":"The request's unique `request_id` (assigned by the proxy). Used as the\nrow identity instead of the storage PK because the ClickHouse backend\nhas no serial id (rows come back with `id = 0`) while `request_id` is\nunique and present on both backends."},"latency_ms":{"type":["integer","null"],"format":"int32"},"method":{"type":"string"},"path":{"type":"string"},"query_string":{"type":["string","null"]},"referrer":{"type":["string","null"]},"request_headers":{},"response_headers":{},"status":{"type":"integer","format":"int32"},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"},"user_agent":{"type":["string","null"]}}},"RequiredPasswordChangeRequest":{"type":"object","required":["new_password"],"properties":{"new_password":{"type":"string"}}},"RequiredPasswordChangeResponse":{"type":"object","required":["success","message","user_id","mfa_enrollment_required"],"properties":{"message":{"type":"string"},"mfa_enrollment_required":{"type":"boolean"},"mfa_setup":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MfaSetupResponse"}]},"success":{"type":"boolean"},"user_id":{"type":"integer","format":"int32"}}},"ResetPasswordRequest":{"type":"object","required":["token","new_password"],"properties":{"new_password":{"type":"string"},"token":{"type":"string"}}},"ResetPgStatStatementsRequest":{"type":"object","description":"Explicit confirmation required for the destructive statistics reset.\n\nRequiring JSON makes the endpoint non-simple for browsers, preventing a\ndeployed same-site application from triggering it with a plain HTML form.","required":["confirm"],"properties":{"confirm":{"type":"boolean","description":"Must be `true` to acknowledge the global, irreversible reset."}}},"ResetPgStatStatementsResponse":{"type":"object","description":"Response for the pg_stat_statements reset endpoint.","required":["message"],"properties":{"message":{"type":"string","description":"Human-readable message confirming the destructive action."}}},"ResizeSandboxBody":{"type":"object","required":["disk_size_mb"],"properties":{"disk_size_mb":{"type":"integer","format":"int64","description":"New root disk size in MB. Grow-only; must exceed the current size.","minimum":0}},"additionalProperties":false},"ResolvedEnvVarResponse":{"type":"object","description":"One entry in the computed env-var view that merges manual and integration\nsources and tags each result with its origin. `value_preview` is always\nmasked — plaintext must be fetched per-key via the existing reveal endpoint,\nwhich is audit-logged.","required":["key","value_preview","source","environments","include_in_preview"],"properties":{"environments":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentInfo"},"description":"Environments this var applies to. For integration-sourced vars this\nreflects every environment of the project (integrations are global)."},"include_in_preview":{"type":"boolean","description":"Whether the var would be auto-applied to preview environments.\nIntegration vars always surface in preview; manual vars follow the flag."},"key":{"type":"string"},"source":{"$ref":"#/components/schemas/ResolvedEnvVarSource"},"value_preview":{"type":"string","description":"Masked or truncated preview. Never the raw value."}}},"ResolvedEnvVarSource":{"oneOf":[{"type":"object","description":"Manually-defined env var. If `overrides_service` is set, this key would\notherwise have been supplied by an integration — the UI should show the\nintegration icon plus an \"overridden\" indicator.","required":["var_id","type"],"properties":{"overrides_service":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/EnvVarIntegrationInfo"}]},"type":{"type":"string","enum":["manual"]},"var_id":{"type":"integer","format":"int32"}}},{"type":"object","description":"Supplied by a linked external service (Postgres, Redis, S3, etc.).","required":["service","type"],"properties":{"service":{"$ref":"#/components/schemas/EnvVarIntegrationInfo"},"type":{"type":"string","enum":["integration"]}}}],"description":"Where a resolved env var comes from. Integration-sourced vars may be\n\"shadowed\" by a manual entry with the same key, in which case the response\ncarries `Manual` with `overrides_service` populated so the UI can still show\nthe integration icon."},"ResourceCounts":{"type":"object","description":"Quick count of resources involved in the migration","required":["projects","environments","deployments","environment_variables","services","domains"],"properties":{"deployments":{"type":"integer","minimum":0},"domains":{"type":"integer","minimum":0},"environment_variables":{"type":"integer","minimum":0},"environments":{"type":"integer","minimum":0},"projects":{"type":"integer","minimum":0},"services":{"type":"integer","minimum":0}}},"ResourceFootprint":{"type":"object","description":"A CPU + memory footprint (requests or measured usage)","required":["cpu_millis","memory_mb"],"properties":{"cpu_millis":{"type":"integer","format":"int64","description":"CPU in millicores"},"memory_mb":{"type":"integer","format":"int64","description":"Memory in MB"}}},"ResourceInfo":{"type":"object","description":"Resource attributes extracted from OTel resource descriptors.","required":["service_name","attributes"],"properties":{"attributes":{"type":"object"},"deployment_environment":{"type":["string","null"]},"service_name":{"type":"string"},"service_version":{"type":["string","null"]}}},"ResourceLimitApplyResult":{"type":"object","description":"Per-container outcome of a live `docker update` call. Surfaced from the\nPATCH /resources endpoint so the UI can tell the operator whether the\nnew caps are already in effect or whether they only apply on next\nrecreate (e.g., container was missing).","required":["role","container_name","outcome"],"properties":{"container_name":{"type":"string"},"error":{"type":["string","null"],"description":"Populated only when `outcome == \"failed\"`."},"outcome":{"type":"string","description":"One of:\n- \"applied\" — Docker accepted the update; caps are live now.\n- \"missing\" — container does not exist; caps stored, will apply on next start.\n- \"stopped\" — container exists but isn't running; Docker still\n accepts the update (the new caps apply on next start).\n- \"failed\" — `docker update` returned an error (see `error`)."},"role":{"type":"string","description":"`service_members.role` for cluster members; \"standalone\" otherwise."}}},"ResourceLimits":{"type":"object","description":"Resource limits and requests","properties":{"cpu_limit":{"type":["integer","null"],"format":"int32","description":"CPU limit (millicores)"},"cpu_request":{"type":["integer","null"],"format":"int32","description":"CPU request (millicores)"},"memory_limit":{"type":["integer","null"],"format":"int32","description":"Memory limit (MB)"},"memory_request":{"type":["integer","null"],"format":"int32","description":"Memory request (MB)"}}},"ResourceLimitsResponse":{"type":"object","description":"Container resource limits","properties":{"cpu_limit":{"type":["integer","null"],"format":"int32"},"cpu_request":{"type":["integer","null"],"format":"int32"},"memory_limit":{"type":["integer","null"],"format":"int32"},"memory_request":{"type":["integer","null"],"format":"int32"}}},"ResourceLimitsUpdateResponse":{"type":"object","description":"Response from PATCH /external-services/{id}/resources.","required":["limits","applied"],"properties":{"applied":{"type":"array","items":{"$ref":"#/components/schemas/ResourceLimitApplyResult"},"description":"Per-container result of trying to apply the limits live."},"limits":{"$ref":"#/components/schemas/ServiceResourceLimits","description":"The limits that were persisted to the encrypted config."}}},"ResourcesBody":{"type":"object","description":"Nested `resources: { memory, vcpus }` as sent by `@vercel/sandbox`.\n`memory` is in MB, `vcpus` is fractional CPU count.","properties":{"memory":{"type":["integer","null"],"format":"int64","minimum":0},"vcpus":{"type":["number","null"],"format":"double"}}},"RestoreCapabilities":{"type":"object","description":"Capabilities a service exposes for the generic restore framework.\n\nEach engine overrides `ExternalService::restore_capabilities` to declare\nwhat it supports. The handler layer uses this to validate requests and\nthe UI uses it to conditionally show options (e.g., PITR picker).","required":["restore_in_place","restore_to_new_service","pitr"],"properties":{"earliest_pitr_time":{"type":["string","null"],"format":"date-time","description":"Earliest recoverable timestamp, if `pitr` is true. Derived from\nengine-specific archive metadata (e.g., `pg_stat_archiver`)."},"latest_pitr_time":{"type":["string","null"],"format":"date-time","description":"Latest recoverable timestamp, if `pitr` is true."},"pitr":{"type":"boolean","description":"Point-in-time recovery using engine-specific continuous archives\n(WAL for Postgres, AOF for Redis, oplog for MongoDB, object versions for S3)."},"restore_in_place":{"type":"boolean","description":"Restore a backup onto the same running service (destructive)."},"restore_to_new_service":{"type":"boolean","description":"Restore a backup into a freshly provisioned service."}}},"RestoreCapabilitiesResponse":{"allOf":[{"$ref":"#/components/schemas/RestoreCapabilities","description":"Trait-declared capabilities."},{"type":"object","required":["suggested_new_service_name"],"properties":{"suggested_new_service_name":{"type":"string","description":"Suggested name for the new service when creating a clone. Safe to\npre-fill into the UI dialog; the user can edit before submitting."}}}]},"RestorePlan":{"type":"object","description":"Preview of a restore operation. Answers \"what will happen if I click\nstart?\" with engine-level specificity so the user can confirm before\ncommitting to a destructive action.","required":["engine","target_service","source_backup","strategy","steps","warnings","errors","destructive","mode"],"properties":{"destructive":{"type":"boolean","description":"Whether any step overwrites existing data on the target service."},"engine":{"type":"string","description":"Target engine (\"postgres\", etc.)."},"errors":{"type":"array","items":{"type":"string"},"description":"Blocking problems. The UI disables the Start button when non-empty."},"mode":{"type":"string","description":"Echo of the requested mode for the UI."},"source_backup":{"$ref":"#/components/schemas/PlanSourceBackup","description":"Backup we'll read from."},"steps":{"type":"array","items":{"type":"string"},"description":"Ordered list of human-readable actions the orchestrator will take."},"strategy":{"type":"string","description":"How the restore will be performed: \"walg_restore\", \"pg_dump_restore\",\nor \"unsupported\"."},"target_service":{"$ref":"#/components/schemas/PlanTarget","description":"Service we'll operate on (or provision a sibling of)."},"warnings":{"type":"array","items":{"type":"string"},"description":"Non-blocking caveats the user should see (cross-service, empty\nlocation that will be auto-resolved, missing engine metadata, ...)."}}},"RestoreRequestMode":{"oneOf":[{"type":"object","description":"Restore the backup onto the existing service (destructive).","required":["mode"],"properties":{"mode":{"type":"string","enum":["in_place"]}}},{"type":"object","description":"Provision a new service and restore into it.","required":["name","mode"],"properties":{"mode":{"type":"string","enum":["new_service"]},"name":{"type":"string","description":"Name for the new service. Orchestrator auto-suggests\n`{source}-restore-{yyyymmdd-hhmm}` if caller omits, but we require\nan explicit value at the API boundary."},"parameter_overrides":{"description":"Optional parameter overrides (port, docker_image, database)."}}},{"type":"object","description":"Point-in-time recovery. Only valid on WAL-G backups (Postgres).","required":["to_new_service","target","mode"],"properties":{"mode":{"type":"string","enum":["pitr"]},"new_service_name":{"type":["string","null"],"description":"Required when `to_new_service` is true."},"target":{"$ref":"#/components/schemas/RecoveryTarget","description":"Recovery target kind + value."},"to_new_service":{"type":"boolean","description":"Whether PITR restores in place or creates a new service."}}}],"description":"What the caller wants to do. Mirrors `externalsvc::RestoreMode` but\nflattened for JSON over the wire."},"RestoreRunView":{"type":"object","required":["id","source_backup_id","source_service_id","mode","status","phase","created_at"],"properties":{"created_at":{"type":"string"},"error_message":{"type":["string","null"]},"finished_at":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"mode":{"type":"string"},"phase":{"type":"string"},"recovery_target":{},"source_backup_id":{"type":"integer","format":"int32"},"source_service_id":{"type":"integer","format":"int32"},"started_at":{"type":["string","null"]},"status":{"type":"string"},"target_service_id":{"type":["integer","null"],"format":"int32"},"target_service_name":{"type":["string","null"]}}},"RetentionCleanupFailure":{"type":"object","required":["backup_id","reason","partial","deleted_objects"],"properties":{"backup_id":{"type":"string"},"deleted_objects":{"type":"integer","format":"int64","minimum":0},"partial":{"type":"boolean"},"reason":{"type":"string"}}},"RetentionCleanupReport":{"type":"object","required":["dry_run","expired","deleted","failed","failures","deleted_backup_ids","deleted_backup_ids_truncated","partially_deleted_backup_ids","partially_deleted_backup_ids_truncated","candidate_backup_ids","candidate_backup_ids_truncated"],"properties":{"candidate_backup_ids":{"type":"array","items":{"type":"string"},"description":"Capped sample of backups selected by the retention policy."},"candidate_backup_ids_truncated":{"type":"boolean"},"deleted":{"type":"integer","format":"int64","minimum":0},"deleted_backup_ids":{"type":"array","items":{"type":"string"},"description":"Capped sample of deleted backup UUIDs for audit attribution."},"deleted_backup_ids_truncated":{"type":"boolean"},"dry_run":{"type":"boolean","description":"True when this report is a non-destructive preview."},"expired":{"type":"integer","format":"int64","minimum":0},"failed":{"type":"integer","format":"int64","minimum":0},"failures":{"type":"array","items":{"$ref":"#/components/schemas/RetentionCleanupFailure"},"description":"Capped diagnostic sample; `failed` remains the authoritative total."},"partially_deleted_backup_ids":{"type":"array","items":{"type":"string"}},"partially_deleted_backup_ids_truncated":{"type":"boolean"},"schedule_id":{"type":["integer","null"],"format":"int32","description":"Schedule scope, or `None` when every schedule was considered."}}},"RetryClusterRequest":{"type":"object","description":"Request body for retrying a failed cluster initialization.","properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/ClusterMemberRequest"},"description":"Cluster member specifications (same format as create).\nIf omitted, the original member configuration is reconstructed from\nthe preserved service_members records."}}},"RevenueRow":{"type":"object","required":["id","ts","provider","event_type"],"properties":{"amount_minor":{"type":["integer","null"],"format":"int64"},"currency":{"type":["string","null"]},"customer_ref":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_type":{"type":"string"},"id":{"type":"integer","format":"int64"},"provider":{"type":"string"},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"}}},"RiskLevel":{"type":"string","description":"Risk level for a migration step","enum":["none","low","medium","high","critical"]},"RoleInfo":{"type":"object","description":"Information about a role","required":["name","description","permissions"],"properties":{"description":{"type":"string","description":"Human-readable description of the role"},"name":{"type":"string","description":"The role identifier (e.g., \"admin\")"},"permissions":{"type":"array","items":{"type":"string"},"description":"Permissions included in this role"}}},"RootfsCacheEntry":{"type":"object","description":"A cached rootfs image (Firecracker backend). Digest-keyed build artifact\nshared by all VMs created from the same image.","required":["digest","bytes","referenced_by"],"properties":{"bytes":{"type":"integer","format":"int64","description":"Actual on-disk size in bytes (sparse-aware).","minimum":0},"digest":{"type":"string","description":"Image digest this rootfs was built from (the cache key)."},"referenced_by":{"type":"array","items":{"type":"string"},"description":"IDs of live sandboxes whose per-VM disk was cloned from this entry.\nEmpty means the entry is reclaimable — no sandbox needs it."}}},"RootfsGcReport":{"type":"object","description":"Outcome of a rootfs garbage-collection pass.","required":["removed_digests","freed_bytes"],"properties":{"freed_bytes":{"type":"integer","format":"int64","minimum":0},"removed_digests":{"type":"array","items":{"type":"string"},"description":"Digests of cache entries removed because no sandbox referenced them."}}},"RootfsReport":{"type":"object","description":"Snapshot of a backend's rootfs storage for the management API. Backends\nwithout a rootfs concept (Docker, local) return an empty report.","required":["cache_bytes","cache","vm_bytes","vms"],"properties":{"cache":{"type":"array","items":{"$ref":"#/components/schemas/RootfsCacheEntry"}},"cache_bytes":{"type":"integer","format":"int64","minimum":0},"vm_bytes":{"type":"integer","format":"int64","minimum":0},"vms":{"type":"array","items":{"$ref":"#/components/schemas/RootfsVmEntry"}}}},"RootfsVmEntry":{"type":"object","description":"A per-sandbox rootfs disk (Firecracker backend). One per non-destroyed\nsandbox — the authoritative storage, independent of the cache.","required":["sandbox_name","bytes","running"],"properties":{"bytes":{"type":"integer","format":"int64","minimum":0},"running":{"type":"boolean"},"sandbox_name":{"type":"string"}}},"RouteRefreshResponse":{"type":"object","required":["route_count","message"],"properties":{"message":{"type":"string","description":"Human-readable message"},"route_count":{"type":"integer","description":"Number of routes loaded","minimum":0}}},"RouteResponse":{"type":"object","required":["id","domain","host","port","enabled","route_type","created_at","updated_at"],"properties":{"created_at":{"type":"integer","format":"int64"},"domain":{"type":"string"},"enabled":{"type":"boolean"},"host":{"type":"string"},"id":{"type":"integer","format":"int32"},"port":{"type":"integer","format":"int32"},"route_type":{"type":"string","description":"Route type: \"http\" or \"tls\""},"updated_at":{"type":"integer","format":"int64"}}},"RouteRole":{"type":"object","required":["id","name","created_at","updated_at"],"properties":{"created_at":{"type":"integer","format":"int64","example":"1683900000000"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"updated_at":{"type":"integer","format":"int64","example":"1683900000000"}}},"RouteUser":{"type":"object","required":["id","name","username","email","image","mfa_enabled","email_verified","must_change_password","created_at","updated_at"],"properties":{"created_at":{"type":"integer","format":"int64","example":"1683900000000"},"deleted_at":{"type":["integer","null"],"format":"int64"},"email":{"type":"string"},"email_verified":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"image":{"type":"string"},"mfa_enabled":{"type":"boolean"},"must_change_password":{"type":"boolean"},"name":{"type":"string"},"updated_at":{"type":"integer","format":"int64","example":"1683900000000"},"username":{"type":"string"}}},"RouteUserWithRoles":{"type":"object","required":["user","roles"],"properties":{"roles":{"type":"array","items":{"$ref":"#/components/schemas/RouteRole"}},"user":{"$ref":"#/components/schemas/RouteUser"}}},"RunBackupRequest":{"type":"object","required":["backup_type"],"properties":{"backup_type":{"type":"string","description":"Type of backup to perform","example":"full"}}},"RunExternalServiceBackupRequest":{"type":"object","properties":{"backup_type":{"type":["string","null"],"description":"Type of backup to perform (e.g., \"full\", \"incremental\")","example":"full"},"s3_source_id":{"type":["integer","null"],"format":"int32","description":"ID of the S3 source to store the backup. If omitted, the current default S3 source is used.","example":1}}},"S3ConnectionTestResponse":{"type":"object","description":"Response body for an S3 connection test.","required":["ok","message"],"properties":{"message":{"type":"string","description":"Human-readable message (success confirmation or error detail)."},"ok":{"type":"boolean","description":"Whether the connection and credentials worked."}}},"S3CredentialsResponse":{"type":"object","description":"S3 credentials distributed to agents for backup/restore operations.","required":["access_key_id","secret_key","region","bucket_name","force_path_style"],"properties":{"access_key_id":{"type":"string"},"bucket_name":{"type":"string"},"endpoint":{"type":["string","null"]},"force_path_style":{"type":"boolean"},"region":{"type":"string"},"secret_key":{"type":"string"}}},"S3SourceResponse":{"type":"object","description":"Response type for S3 source","required":["id","name","bucket_name","bucket_path","access_key_id","secret_key","region","is_default","created_at","updated_at"],"properties":{"access_key_id":{"type":"string","example":"AKIAXXXXXXXXXXXXXXXX"},"bucket_name":{"type":"string"},"bucket_path":{"type":"string"},"created_at":{"type":"integer","format":"int64"},"endpoint":{"type":["string","null"],"example":"http://minio.example.com:9000"},"force_path_style":{"type":["boolean","null"]},"id":{"type":"integer","format":"int32"},"is_default":{"type":"boolean"},"name":{"type":"string"},"region":{"type":"string"},"secret_key":{"type":"string","writeOnly":true},"updated_at":{"type":"integer","format":"int64"}}},"SandboxDomainResponse":{"type":"object","required":["url"],"properties":{"url":{"type":"string"}}},"SandboxEvent":{"type":"object","description":"One entry in a sandbox's operations timeline.","required":["event_type","at"],"properties":{"at":{"type":"integer","format":"int64","description":"Unix epoch milliseconds."},"detail":{"description":"Optional structured context (shape depends on `event_type`)."},"event_type":{"type":"string","description":"Machine-readable operation (`created`, `stopped`, `resumed`,\n`restarted`, `timeout_extended`, `resized`, `preview_password_set`,\n`preview_password_cleared`, `preview_share_link_created`, `source_seeded`,\n`destroyed`)."}}},"SandboxEventsResponse":{"type":"object","required":["events"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/SandboxEvent"}}}},"SandboxInner":{"type":"object","description":"Inner `sandbox` object in `@vercel/sandbox` responses. Strict shape —\nthe SDK's zod validator rejects missing required fields.","required":["id","memory","vcpus","region","runtime","timeout","status","requestedAt","createdAt","updatedAt","cwd","name","preview_url_template"],"properties":{"agent_run_id":{"type":["integer","null"],"format":"int32","description":"Agent run this sandbox executes (autofixer / workflow agent).\n`None` for sandboxes created via this API."},"backend":{"type":["string","null"],"description":"Isolation backend: \"docker\" | \"firecracker\". `None` on legacy rows\ncreated before the backend was recorded."},"createdAt":{"type":"integer","format":"int64"},"cwd":{"type":"string"},"disk_size_mb":{"type":["integer","null"],"format":"int64","description":"Configured root disk size in MB (Firecracker). `None` when unknown or\nthe default.","minimum":0},"id":{"type":"string"},"image":{"type":["string","null"]},"memory":{"type":"integer","format":"int64","minimum":0},"name":{"type":"string"},"preview_password_hint":{"type":["string","null"]},"preview_url_template":{"type":"string"},"region":{"type":"string"},"requestedAt":{"type":"integer","format":"int64","description":"Creation time as Unix epoch milliseconds."},"runtime":{"type":"string"},"status":{"type":"string"},"timeout":{"type":"integer","format":"int64","description":"Idle timeout in milliseconds (SDK convention).","minimum":0},"updatedAt":{"type":"integer","format":"int64"},"vcpus":{"type":"number","format":"double"}}},"SandboxResponse":{"type":"object","description":"`@vercel/sandbox` wraps every single-sandbox response as\n`{ sandbox: {...}, routes: [...] }`. The SDK reads both.","required":["sandbox","routes"],"properties":{"routes":{"type":"array","items":{"$ref":"#/components/schemas/SandboxRoute"}},"sandbox":{"$ref":"#/components/schemas/SandboxInner"}}},"SandboxRoute":{"type":"object","description":"A single preview route, one per declared port. We don't know ports\nupfront, so we surface an empty array by default — SDK clients use\ntheir own port when calling `sandbox.domain(port)`.","required":["url","subdomain","port"],"properties":{"port":{"type":"integer","format":"int32","minimum":0},"subdomain":{"type":"string"},"url":{"type":"string"}}},"SandboxStatusResponse":{"type":"object","required":["docker_available","image_ready","image_name","firecracker_available"],"properties":{"docker_available":{"type":"boolean"},"error":{"type":["string","null"]},"firecracker_available":{"type":"boolean"},"image_name":{"type":"string"},"image_ready":{"type":"boolean"}}},"SaveAgentTokenRequest":{"type":"object","required":["token"],"properties":{"token":{"type":"string","description":"The OAuth token from `claude setup-token` or an API key.\nWill be encrypted before storage."}}},"SaveAgentTokenResponse":{"type":"object","required":["saved"],"properties":{"saved":{"type":"boolean"}}},"SaveCredentialRequest":{"type":"object","required":["auth_type","credential"],"properties":{"auth_type":{"type":"string","description":"Auth flavor id (must match one of the provider's catalog entries)."},"credential":{"type":"string","description":"Plaintext credential body (API key, OAuth token, or full config file\ncontents). Encrypted with `EncryptionService` before being persisted\ninside the `agent_sandbox.providers` JSON map."}}},"SaveCredentialResponse":{"type":"object","required":["saved","provider_id","auth_type"],"properties":{"auth_type":{"type":"string"},"provider_id":{"type":"string"},"saved":{"type":"boolean"}}},"ScalewayCredentialsRequest":{"type":"object","required":["api_key","project_id"],"properties":{"api_key":{"type":"string","example":"scw-secret-key-12345"},"project_id":{"type":"string","example":"12345678-1234-1234-1234-123456789012"}}},"ScanResponse":{"type":"object","required":["id","project_id","scanner_type","status","total_count","critical_count","high_count","medium_count","low_count","unknown_count","started_at","created_at","updated_at"],"properties":{"branch":{"type":["string","null"]},"commit_hash":{"type":["string","null"]},"completed_at":{"type":["string","null"],"example":"2025-12-08T12:15:47.609192Z"},"created_at":{"type":"string","example":"2025-12-08T12:15:47.609192Z"},"critical_count":{"type":"integer","format":"int32"},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_message":{"type":["string","null"]},"high_count":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"low_count":{"type":"integer","format":"int32"},"medium_count":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"scanner_type":{"type":"string"},"scanner_version":{"type":["string","null"]},"started_at":{"type":"string","example":"2025-12-08T12:15:47.609192Z"},"status":{"type":"string"},"total_count":{"type":"integer","format":"int32"},"unknown_count":{"type":"integer","format":"int32"},"updated_at":{"type":"string","example":"2025-12-08T12:15:47.609192Z"}}},"ScheduleRunEntry":{"type":"object","description":"A single run-history entry for the schedule detail page (deliverable 1).\n\nCombines one `backups` row with the most-recent `backup_jobs` row for that\nbackup via a lateral JOIN. Fields from `backup_jobs` are `None` for legacy\nbackup rows that pre-date ADR-014.","required":["backup_id","backup_uuid","state","started_at","s3_location"],"properties":{"attempts":{"type":["integer","null"],"format":"int32","description":"Number of claim-and-run attempts so far. `None` for legacy rows."},"backup_id":{"type":"integer","format":"int32","description":"DB id of the `backups` row."},"backup_uuid":{"type":"string","description":"UUID string (`backups.backup_id`)."},"current_step":{"type":["string","null"],"description":"Last completed step reported by the engine (e.g. `\"upload\"`).\n`None` when no step has been persisted yet."},"error_message":{"type":["string","null"],"description":"Engine-reported error message when `state = \"failed\"`."},"finished_at":{"type":["string","null"],"description":"When the backup finished, if known."},"job_id":{"type":["integer","null"],"format":"int64","description":"Most recent `backup_jobs.id` for this backup. `None` for legacy rows."},"s3_location":{"type":"string","description":"S3 object key or URL where the backup data lives."},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Final size in bytes once completed. `None` while running."},"started_at":{"type":"string","description":"When the backup was started (ISO 8601 / RFC 3339)."},"state":{"type":"string","description":"Current state: `\"pending\"`, `\"running\"`, `\"completed\"`, `\"failed\"`."}}},"ScheduleRunJobEntry":{"type":"object","description":"A single job entry inside an expanded schedule run, returned by\n[`BackupService::list_schedule_run_jobs`].","required":["backup_id","backup_uuid","engine","service_name","state","started_at","s3_source_id"],"properties":{"backup_id":{"type":"integer","format":"int32","description":"`backups.id` for this job."},"backup_uuid":{"type":"string","description":"`backups.backup_id` UUID string."},"engine":{"type":"string","description":"Engine key (e.g. `\"control_plane\"`, `\"redis\"`)."},"error_message":{"type":["string","null"],"description":"Engine-reported error message when `state = \"failed\"`."},"finished_at":{"type":["string","null"],"description":"When this child backup finished, if known."},"s3_source_id":{"type":"integer","format":"int32","description":"FK to `s3_sources.id` — needed for the backup detail link."},"service_id":{"type":["integer","null"],"format":"int32","description":"`external_services.id` — `NULL` for the control-plane job."},"service_name":{"type":"string","description":"Name of the external service, or `\"control plane\"` for the\ncontrol-plane job."},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size in bytes once completed; `None` while running."},"started_at":{"type":"string","description":"When this child backup started (ISO 8601 / RFC 3339)."},"state":{"type":"string","description":"Current state of this child backup."}}},"ScheduleRunListResponse":{"type":"object","description":"Paginated run-history response for a backup schedule (deliverable 1).","required":["runs","total","page","page_size"],"properties":{"page":{"type":"integer","format":"int64","description":"Current page (1-based)."},"page_size":{"type":"integer","format":"int64","description":"Number of items per page (clamped to 1–100)."},"runs":{"type":"array","items":{"$ref":"#/components/schemas/ScheduleRunEntry"},"description":"Run entries, newest first."},"total":{"type":"integer","format":"int64","description":"Total number of runs across all pages."}}},"ScheduleRunResponse":{"type":"object","description":"HTTP response body for `POST /api/backups/schedules/{id}/run` (fan-out).","required":["schedule_run_id","jobs"],"properties":{"jobs":{"type":"array","items":{"$ref":"#/components/schemas/EnqueuedJob"},"description":"All jobs that were enqueued in this fan-out."},"schedule_run_id":{"type":"integer","format":"int64","description":"The `schedule_runs.id` of the newly created run."}}},"ScheduleRunSummary":{"type":"object","description":"Summary of one scheduler tick (or one \"Run now\" click), returned by\n[`BackupService::list_schedule_runs`].\n\nThe `aggregate_state` is computed at read time from child backup counts:\n- `\"running\"` — at least one child is `\"pending\"` or `\"running\"`.\n- `\"failed\"` — at least one child is `\"failed\"` and none are running.\n- `\"completed\"` — all children are `\"completed\"`.","required":["run_id","schedule_id","triggered_by","started_at","aggregate_state","total_jobs","completed_jobs","failed_jobs","running_jobs","pending_jobs"],"properties":{"aggregate_state":{"type":"string","description":"Aggregate state computed from child counts (see struct docs)."},"completed_jobs":{"type":"integer","format":"int64","description":"Number of children in `state = \"completed\"`."},"failed_jobs":{"type":"integer","format":"int64","description":"Number of children in `state = \"failed\"`."},"finished_at":{"type":["string","null"],"description":"When all children reached a terminal state. `None` while any child is\nstill `\"pending\"` or `\"running\"`."},"pending_jobs":{"type":"integer","format":"int64","description":"Number of children in `state = \"pending\"`."},"run_id":{"type":"integer","format":"int64","description":"`schedule_runs.id` for this tick."},"running_jobs":{"type":"integer","format":"int64","description":"Number of children in `state = \"running\"`."},"schedule_id":{"type":"integer","format":"int32","description":"FK to `backup_schedules.id`."},"started_at":{"type":"string","description":"When the fan-out started (ISO 8601 / RFC 3339)."},"total_jobs":{"type":"integer","format":"int64","description":"Total number of child backup jobs in this run."},"triggered_by":{"type":"string","description":"How the run was triggered: `\"cron\"` or `\"manual\"`."}}},"ScheduleRunSummaryList":{"type":"object","description":"Paginated list of schedule run summaries returned by the new\n[`BackupService::list_schedule_runs`].","required":["runs","total","page","page_size"],"properties":{"page":{"type":"integer","format":"int64","description":"Current page (1-based)."},"page_size":{"type":"integer","format":"int64","description":"Number of items per page."},"runs":{"type":"array","items":{"$ref":"#/components/schemas/ScheduleRunSummary"},"description":"Run summaries, newest first. Includes synthetic single-job rows for\nlegacy `backups` rows that have `schedule_id` set but no\n`schedule_run_id` (pre-fan-out history)."},"total":{"type":"integer","format":"int64","description":"Total number of run entries across all pages."}}},"ScreenshotSettings":{"type":"object","properties":{"enabled":{"type":"boolean","default":false},"provider":{"type":"string","default":"local"},"url":{"type":"string","default":""}}},"SearchLogsRequest":{"type":"object","required":["project_id"],"properties":{"container_ids":{"type":"array","items":{"type":"string"},"description":"Filter to specific containers (Docker container IDs). Empty = all\ncontainers. Drives \"filter by container / show all\" in a project's\nhistory, which spans multiple deployments and containers."},"context_lines":{"type":["integer","null"],"format":"int32","description":"grep -C: number of raw context lines to include before and after each\nmatch (0 = none, default). Clamped to 50 server-side. The surrounding\nlines ignore the level/text filters — they are the actual adjacent log\nlines, merged across overlapping matches.","minimum":0},"cursor":{"type":["string","null"],"description":"Pagination cursor"},"deploy_id":{"type":["integer","null"],"format":"int32","description":"Filter by deployment ID (deployments.id)"},"end_time":{"type":["string","null"],"description":"End of time range (ISO 8601). Defaults to now."},"envs":{"type":"array","items":{"type":"string"},"description":"Filter by environments"},"external_service_id":{"type":["integer","null"],"format":"int32","description":"When set, search an imported/managed external service's logs instead\nof a project's. `project_id` is ignored in this mode."},"levels":{"type":"array","items":{"type":"string"},"description":"Filter by log levels"},"node_ids":{"type":"array","items":{"type":"integer","format":"int32"},"description":"Filter to specific worker nodes (node_id). Empty = all nodes, including\ncontrol-plane-local logs."},"page_size":{"type":["integer","null"],"format":"int32","description":"Page size (default: 100, max: 500)","minimum":0},"project_id":{"type":"integer","format":"int32","description":"Project ID (integer, as used by the rest of the platform)"},"services":{"type":"array","items":{"type":"string"},"description":"Filter by services"},"start_time":{"type":["string","null"],"description":"Start of time range (ISO 8601). Defaults to 1 hour ago."},"text":{"type":["string","null"],"description":"Full text search query"}}},"SearchLogsResponse":{"type":"object","required":["lines","search_mode","total_scanned"],"properties":{"available_sources":{"type":"array","items":{"$ref":"#/components/schemas/LogSource"},"description":"Distinct containers/nodes/services available in the queried scope, for\nthe filter dropdowns. Populated on the first page (no cursor)."},"lines":{"type":"array","items":{"$ref":"#/components/schemas/LogSearchLine"}},"next_cursor":{"type":["string","null"]},"search_mode":{"$ref":"#/components/schemas/SearchMode"},"total_scanned":{"type":"integer","format":"int64","minimum":0}}},"SearchMode":{"type":"string","description":"Search execution mode","enum":["index","archive"]},"Seasonality":{"type":"string","description":"Seasonality model for an anomaly baseline.","enum":["none","hourly","daily","weekly"]},"SecretResponse":{"type":"object","required":["id","name","secret_type","value","created_at","updated_at"],"properties":{"created_at":{"type":"string"},"description":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"mount_path":{"type":["string","null"]},"name":{"type":"string"},"secret_type":{"type":"string"},"updated_at":{"type":"string"},"value":{"type":"string","description":"Always masked in responses"}}},"SecurityConfig":{"type":"object","description":"Security configuration for projects and environments\n\nThis configuration can be set at three levels:\n1. Global (in settings table) - applies to all projects\n2. Project level - overrides global settings for specific project\n3. Environment level - overrides project settings for specific environment\n\nThe inheritance chain: Environment > Project > Global","properties":{"attackMode":{"type":["string","null"],"description":"Attack mode configuration (future: \"off\", \"challenge\", \"block\")\nPlaceholder for DDoS protection, bot detection, etc."},"challengeConfig":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ChallengeConfig","description":"Challenge configuration (future: CAPTCHA, JS challenge, etc.)"}]},"enabled":{"type":["boolean","null"],"description":"Enable/disable security features at this level\nIf None, inherits from parent level"},"geoRestrictions":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/GeoRestrictionsConfig","description":"Geographic restrictions (future: country blocking, etc.)"}]},"headers":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SecurityHeadersConfig","description":"Security headers configuration"}]},"passwordProtection":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PasswordProtectionConfig","description":"Password protection: shows an HTML password form before allowing access"}]},"rateLimiting":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/RateLimitConfig","description":"Rate limiting configuration"}]}}},"SecurityHeadersConfig":{"type":"object","description":"Security headers configuration (subset of global SecurityHeadersSettings)","properties":{"contentSecurityPolicy":{"type":["string","null"],"description":"Custom CSP (only used if preset is \"custom\")"},"preset":{"type":["string","null"],"description":"Use a preset: \"strict\", \"moderate\", \"permissive\", \"disabled\", \"custom\""},"referrerPolicy":{"type":["string","null"],"description":"Referrer-Policy override"},"strictTransportSecurity":{"type":["string","null"],"description":"HSTS override"},"xFrameOptions":{"type":["string","null"],"description":"X-Frame-Options override"}}},"SecurityHeadersSettings":{"type":"object","properties":{"content_security_policy":{"type":["string","null"],"default":"default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'self'"},"enabled":{"type":"boolean","default":false},"permissions_policy":{"type":["string","null"],"default":"geolocation=(), microphone=(), camera=()"},"preset":{"type":"string","default":"moderate"},"referrer_policy":{"type":"string","default":"strict-origin-when-cross-origin"},"strict_transport_security":{"type":"string","default":"max-age=31536000; includeSubDomains"},"x_content_type_options":{"type":"string","default":"nosniff"},"x_frame_options":{"type":"string","default":"SAMEORIGIN"},"x_xss_protection":{"type":"string","default":"1; mode=block"}}},"SendEmailRequestBody":{"type":"object","required":["from","to","subject"],"properties":{"bcc":{"type":["array","null"],"items":{"type":"string"},"description":"BCC recipients"},"cc":{"type":["array","null"],"items":{"type":"string"},"description":"CC recipients"},"from":{"type":"string","description":"Sender email address (domain will be auto-extracted for lookup)","example":"hello@updates.example.com"},"from_name":{"type":["string","null"],"description":"Sender display name","example":"My App"},"headers":{"type":["object","null"],"description":"Custom headers","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"html":{"type":["string","null"],"description":"HTML body content","example":"

    Hello World

    "},"reply_to":{"type":["string","null"],"description":"Reply-to address"},"subject":{"type":"string","description":"Email subject","example":"Welcome to our platform!"},"tags":{"type":["array","null"],"items":{"type":"string"},"description":"Tags for categorization","example":["welcome","onboarding"]},"text":{"type":["string","null"],"description":"Plain text body content","example":"Hello World"},"to":{"type":"array","items":{"type":"string"},"description":"Recipient email addresses","example":["user@example.com"]},"track_clicks":{"type":["boolean","null"],"description":"Enable click tracking (link rewriting). Defaults to false."},"track_opens":{"type":["boolean","null"],"description":"Enable open tracking (tracking pixel injection). Defaults to false."}}},"SendEmailResponseBody":{"type":"object","required":["id","status"],"properties":{"id":{"type":"string","description":"Email ID","example":"550e8400-e29b-41d4-a716-446655440000"},"provider_message_id":{"type":["string","null"],"description":"Provider message ID"},"status":{"type":"string","description":"Email status","example":"sent"}}},"SendMessageRequest":{"type":"object","required":["content"],"properties":{"content":{"type":"string"},"page_context":{"type":["string","null"],"description":"Optional, client-supplied description of the page/entity the user is\ncurrently viewing (e.g. a trace in a project). Injected into the model's\nview of this turn only — never stored or shown in history. Capped server\nside; oversized values are ignored rather than rejected."}}},"SensitiveConfigValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"SensitiveMcpConfigValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"SensitiveValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"SentryChunkUploadResponse":{"type":"object","required":["url","chunkSize","chunksPerRequest","maxFileSize","maxRequestSize","concurrency","hashAlgorithm","compression","accept"],"properties":{"accept":{"type":"array","items":{"type":"string"}},"chunkSize":{"type":"integer","format":"int64","minimum":0},"chunksPerRequest":{"type":"integer","format":"int32","minimum":0},"compression":{"type":"array","items":{"type":"string"}},"concurrency":{"type":"integer","format":"int32","minimum":0},"hashAlgorithm":{"type":"string"},"maxFileSize":{"type":"integer","format":"int64","minimum":0},"maxRequestSize":{"type":"integer","format":"int64","minimum":0},"url":{"type":"string"}}},"SentryCreateReleaseRequest":{"type":"object","required":["version"],"properties":{"projects":{"type":"array","items":{"type":"string"},"description":"Project slugs this release belongs to"},"version":{"type":"string","description":"Release version identifier"}}},"SentryEventRequest":{"type":"object","properties":{"event_id":{"type":["string","null"]},"message":{"type":["string","null"]},"platform":{"type":["string","null"]},"timestamp":{"type":["string","null"]}}},"SentryEventResponse":{"type":"object","required":["id"],"properties":{"id":{"type":"string"}}},"SentryReleaseFileResponse":{"type":"object","required":["id","name","headers","size","sha1","dateCreated"],"properties":{"dateCreated":{"type":"string"},"dist":{"type":["string","null"]},"headers":{},"id":{"type":"string"},"name":{"type":"string"},"sha1":{"type":"string"},"size":{"type":"integer","format":"int64"}}},"SentryReleaseProjectRef":{"type":"object","required":["name","slug"],"properties":{"name":{"type":"string"},"slug":{"type":"string"}}},"SentryReleaseResponse":{"type":"object","required":["version","dateCreated","shortVersion","projects"],"properties":{"dateCreated":{"type":"string"},"dateReleased":{"type":["string","null"]},"projects":{"type":"array","items":{"$ref":"#/components/schemas/SentryReleaseProjectRef"}},"shortVersion":{"type":"string"},"version":{"type":"string"}}},"SeriesStateEntry":{"type":"object","description":"One series' persisted state snapshot for a dynamic rule (ADR-026 follow-up):\nthe state after the latest tick, the value evaluated this tick, and the open\nalarm id (when firing). Serialized into the `series_states` jsonb column keyed\nby the human-readable [`series_label`]; the alert response decodes it back.","required":["state","value"],"properties":{"alarm_id":{"type":["integer","null"],"format":"int32","description":"The open alarm's id when the series is firing; `null` when ok."},"state":{"type":"string","description":"`firing` or `ok` for this series after the latest tick."},"value":{"type":"number","format":"double","description":"The value the rule evaluated for this series this tick."}}},"ServiceAccessInfo":{"type":"object","description":"Response containing information about how the service is being accessed","required":["access_mode","can_create_domains"],"properties":{"access_mode":{"type":"string","description":"Mode of access: \"local\", \"direct\", \"nat\", or \"cloudflare_tunnel\""},"can_create_domains":{"type":"boolean","description":"Whether domain creation is allowed in this mode"},"domain_creation_error":{"type":["string","null"],"description":"Error message if domain creation is not allowed"},"private_ip":{"type":["string","null"],"description":"Server's private/local IP address (always returned if available)"},"public_ip":{"type":["string","null"],"description":"Server's public IP address (always returned if available)"}}},"ServiceAction":{"type":"string","description":"What to do with a service during migration","enum":["create","link-external","skip"]},"ServiceAlertRuleResponse":{"type":"object","description":"Wire representation of a monitoring alert rule.\n\nRegistered under a domain-prefixed OpenAPI schema name to avoid colliding\nwith `temps-error-tracking`'s unrelated `AlertRuleResponse` (utoipa keys\nschemas by their bare struct name, so without `as = ...` the last crate to\nregister would silently shadow this one in the merged spec / generated SDK).","required":["id","name","metric_name","threshold","comparator","severity","for_duration_secs","enabled"],"properties":{"comparator":{"type":"string"},"deployment_id":{"type":["integer","null"],"format":"int32"},"enabled":{"type":"boolean"},"for_duration_secs":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"metric_name":{"type":"string"},"name":{"type":"string"},"service_id":{"type":["integer","null"],"format":"int32"},"severity":{"type":"string"},"silenced_until":{"type":["string","null"]},"threshold":{"type":"number","format":"double"}}},"ServiceBackupEntryResponse":{"type":"object","description":"A single backup entry in the per-service backup list.","required":["id","backup_id","name","state","backup_type","started_at","s3_location","compression_type","s3_source_id","s3_source_name","external_service_backup_id"],"properties":{"backup_id":{"type":"string","description":"UUID string assigned at backup creation time."},"backup_type":{"type":"string","description":"Backup variant (e.g. \"full\", \"incremental\")."},"compression_type":{"type":"string","description":"Compression algorithm used (e.g. \"gzip\")."},"error_message":{"type":["string","null"],"description":"Engine-reported error message, populated when `state = \"failed\"`."},"external_service_backup_id":{"type":"integer","format":"int32","description":"Row ID from `external_service_backups`."},"finished_at":{"type":["string","null"],"description":"ISO 8601 timestamp when the backup finished, if known.","example":"2025-01-15T14:35:00Z"},"id":{"type":"integer","format":"int32","description":"Row ID from the `backups` table."},"name":{"type":"string","description":"Human-friendly display name."},"s3_location":{"type":"string","description":"Object key or `s3://` URL for the backup data."},"s3_source_id":{"type":"integer","format":"int32","description":"FK to `s3_sources.id`."},"s3_source_name":{"type":"string","description":"Human-readable name of the S3 source."},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size of the backup in bytes, if available."},"started_at":{"type":"string","description":"ISO 8601 timestamp when the backup started.","example":"2025-01-15T14:30:00Z"},"state":{"type":"string","description":"Current state: \"completed\", \"running\", \"failed\"."}}},"ServiceBackupListResponse":{"type":"object","description":"Paginated list of backups for a specific external service.\n\nReturned by `GET /backups/external-services/{service_id}/backups`.","required":["backups","total","page","page_size"],"properties":{"backups":{"type":"array","items":{"$ref":"#/components/schemas/ServiceBackupEntryResponse"},"description":"Backups belonging to this service, newest first."},"page":{"type":"integer","format":"int64","description":"Current page (1-based)."},"page_size":{"type":"integer","format":"int64","description":"Number of items per page."},"total":{"type":"integer","format":"int64","description":"Total number of backups for this service across all pages."}}},"ServiceCreateAlertRuleRequest":{"type":"object","description":"Request body for creating an alert rule on an external service.\n\nDomain-prefixed schema name — see [`AlertRuleResponse`] for why.","required":["name","metric_name","threshold","comparator","severity"],"properties":{"comparator":{"type":"string","description":"One of `>`, `<`, `>=`, `<=`."},"enabled":{"type":"boolean"},"for_duration_secs":{"type":"integer","format":"int32","description":"Seconds the breach must persist before the alarm fires (0 = immediate)."},"metric_name":{"type":"string"},"name":{"type":"string"},"severity":{"type":"string","description":"`\"warning\"` or `\"critical\"`."},"threshold":{"type":"number","format":"double"}}},"ServiceHealthResponse":{"type":"object","required":["service_id","consecutive_failures","recent_checks"],"properties":{"consecutive_failures":{"type":"integer","format":"int32","description":"Consecutive failed probes. Alert fires at 3."},"last_checked_at":{"type":["string","null"]},"last_error":{"type":["string","null"]},"recent_checks":{"type":"array","items":{"$ref":"#/components/schemas/HealthCheckEntryResponse"},"description":"Most recent checks, newest-first (capped at `limit`)."},"response_time_ms":{"type":["integer","null"],"format":"int32"},"service_id":{"type":"integer","format":"int32"},"status":{"type":["string","null"],"description":"Current health. `null` if the service has not been probed yet.","example":"operational"},"uptime_24h_percent":{"type":["number","null"],"format":"double","description":"Uptime percentage over the last 24 hours (0.0 — 100.0).\n`null` when there is not enough history."}}},"ServiceHealthStatusBatchResponse":{"type":"object","required":["statuses"],"properties":{"statuses":{"type":"array","items":{"$ref":"#/components/schemas/ServiceHealthStatusEntryResponse"}}}},"ServiceHealthStatusEntryResponse":{"type":"object","required":["service_id","consecutive_failures"],"properties":{"consecutive_failures":{"type":"integer","format":"int32"},"last_checked_at":{"type":["string","null"]},"service_id":{"type":"integer","format":"int32"},"status":{"type":["string","null"],"description":"\"operational\" | \"degraded\" | \"down\". `null` when the service has not\nbeen probed yet.","example":"operational"}}},"ServiceMemberInfo":{"type":"object","description":"Public info about a cluster member.","required":["id","role","container_name","status","ordinal"],"properties":{"compute_ip":{"type":["string","null"],"description":"Container's IP on the `temps-overlay` multi-host network. Populated\nby the lifecycle hook (ADR-011 Phase 3); `None` on single-host\nclusters where the overlay isn't attached."},"container_name":{"type":"string"},"hostname":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"live_state":{"type":["string","null"],"description":"Live FSM state from the pg_auto_failover monitor (`primary`,\n`secondary`, `catchingup`, `report_lsn`, …). `None` when the\nmonitor is unreachable, the service is not a cluster, or the row\nis the monitor itself.\n\n**The UI must render the role badge from this field**, falling\nback to `role` only when `live_state` is null. `role` is now\nconfig-only (`monitor` or `replica`); flipping the badge to\n\"primary\" when the monitor elects a new one used to require a\nreconciler that lagged ~5s behind real failovers — and during\nthat window the UI showed two primaries. `live_state` is read\ndirectly from the monitor on every list, so it can never lag."},"node_id":{"type":["integer","null"],"format":"int32"},"ordinal":{"type":"integer","format":"int32"},"port":{"type":["integer","null"],"format":"int32"},"provisioning_error":{"type":["string","null"],"description":"Most recent provisioning failure message, when `status='failed'`.\nSet by the background task so the UI can show *why* the new\nreplica didn't come up."},"provisioning_step":{"type":["string","null"],"description":"Last-attempted phase of the async `add_cluster_member` background\ntask (e.g. `validating`, `provisioning_container`, `done`,\n`failed`). `None` for members not created through that flow —\nthe UI falls back to the `status` column for those."},"role":{"type":"string"},"status":{"type":"string"}}},"ServiceParameter":{"type":"object","required":["name","required","encrypted","description"],"properties":{"choices":{"type":["array","null"],"items":{"type":"string"}},"default_value":{"type":["string","null"]},"description":{"type":"string"},"encrypted":{"type":"boolean"},"name":{"type":"string"},"required":{"type":"boolean"},"validation_pattern":{"type":["string","null"]}}},"ServicePlan":{"type":"object","description":"Plan for migrating a single service (database, cache, etc.)","required":["name","service_type","action","action_description"],"properties":{"action":{"$ref":"#/components/schemas/ServiceAction","description":"What to do with this service"},"action_description":{"type":"string","description":"Human-readable explanation of what this action means"},"data_implications":{"type":"array","items":{"$ref":"#/components/schemas/DataImplication"},"description":"Data implications specific to this service"},"env_var_mappings":{"type":"object","description":"Environment variable key mappings: source_key -> temps_key\n\nFor example, Vercel's `POSTGRES_URL` might map to Temps' `DATABASE_URL`.\nBoth keys will be set during migration so the app works with either.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":"string","description":"Human-readable service name"},"parameters":{"type":"object","description":"Parameters for creating the service in Temps","additionalProperties":{},"propertyNames":{"type":"string"}},"service_type":{"type":"string","description":"Service type (maps to temps-providers ServiceType)"},"version":{"type":["string","null"],"description":"Service version to create (e.g., \"16\" for Postgres 16)"}}},"ServiceResourceLimits":{"type":"object","description":"Optional cgroup resource limits applied to a service container.\n\nAll fields are `Option`: `None` means \"no limit\" (the kernel default),\nmatching Docker's behavior when the corresponding `HostConfig` field is\nleft at zero. Operators opt in to limits explicitly through the\n`PATCH /external-services/{id}/resources` endpoint or by writing the\n`resources` block into `ServiceConfig::parameters` at create time.\n\nThese map directly onto bollard fields:\n- `memory_mb` → `HostConfig.memory` (bytes)\n- `memory_swap_mb`→ `HostConfig.memory_swap` (bytes; ≥ memory)\n- `nano_cpus` → `HostConfig.nano_cpus` (1e9 = 1 full CPU)\n- `cpu_shares` → `HostConfig.cpu_shares` (relative weight, default 1024)\n- `shm_size_mb` → `HostConfig.shm_size` (bytes; default 64 MiB)\n\nIMPORTANT: enabling hard memory limits causes the kernel OOM killer to\nterminate the container when the working set exceeds the limit. The\ncontainer will restart (RestartPolicy::ALWAYS) but in-flight queries\nfail. Surface this clearly in any UI that lets users set limits.","properties":{"cpu_shares":{"type":["integer","null"],"format":"int64","description":"Relative CPU weight (default 1024). Only used when `nano_cpus` is None."},"memory_mb":{"type":["integer","null"],"format":"int64","description":"Hard memory limit in MiB. None = unlimited."},"memory_swap_mb":{"type":["integer","null"],"format":"int64","description":"Memory + swap limit in MiB. None = unlimited.\nMUST be >= memory_mb when both are set; Docker rejects the request otherwise.\nSet equal to `memory_mb` to disable swap entirely."},"nano_cpus":{"type":["integer","null"],"format":"int64","description":"CPU quota in nano-cpus. 1_000_000_000 = 1 full CPU core. None = unlimited."},"shm_size_mb":{"type":["integer","null"],"format":"int64","description":"Shared memory (/dev/shm) size in MiB. None = Docker default (64 MiB).\nMaps to HostConfig.shm_size (bytes). PostgreSQL uses /dev/shm for parallel\nquery workers and large work_mem; the 64 MiB default causes \"could not\nresize shared memory segment ... No space left on device\" under load.\nNOTE: shm_size is fixed at container-create time — Docker's live update\nAPI cannot change it, so changing this value recreates the container."}}},"ServiceRuntimeReport":{"type":"object","description":"Aggregate runtime info for an external service. For standalone services,\n`members` has exactly one entry. For clusters, one entry per member.","required":["service_id","topology","members"],"properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/ContainerRuntimeInfo"}},"service_id":{"type":"integer","format":"int32"},"topology":{"type":"string"}}},"ServiceStatsReport":{"type":"object","required":["service_id","topology","members"],"properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/ContainerStatsSample"}},"service_id":{"type":"integer","format":"int32"},"topology":{"type":"string"}}},"ServiceTypeInfo":{"type":"object","required":["service_type","parameters"],"properties":{"parameters":{"type":"array","items":{"$ref":"#/components/schemas/ServiceParameter"},"example":"[{\"name\": \"host\", \"required\": true, \"encrypted\": false, \"description\": \"Database host\"}]"},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute"}}},"ServiceTypeRoute":{"type":"string","enum":["mariadb","mongodb","postgres","redis","s3","kv","blob","rustfs","minio"]},"ServiceUpdateAlertRuleRequest":{"type":"object","description":"Request body for updating an existing alert rule.\n\nDomain-prefixed schema name — see [`AlertRuleResponse`] for why.","properties":{"comparator":{"type":["string","null"]},"enabled":{"type":["boolean","null"]},"for_duration_secs":{"type":["integer","null"],"format":"int32"},"metric_name":{"type":["string","null"]},"name":{"type":["string","null"]},"severity":{"type":["string","null"]},"threshold":{"type":["number","null"],"format":"double"}}},"SesCredentialsRequest":{"type":"object","required":["access_key_id","secret_access_key"],"properties":{"access_key_id":{"type":"string","example":"AKIAIOSFODNN7EXAMPLE"},"secret_access_key":{"type":"string","example":"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"}}},"SessionDetails":{"type":"object","required":["session_id","visitor_id","started_at","duration_seconds","is_bounced","is_engaged","page_views"],"properties":{"duration_seconds":{"type":"integer","format":"int64"},"ended_at":{"type":["string","null"],"format":"date-time","example":"2024-01-01T00:00:00"},"entry_path":{"type":["string","null"]},"exit_path":{"type":["string","null"]},"is_bounced":{"type":"boolean"},"is_engaged":{"type":"boolean"},"page_views":{"type":"integer","format":"int64"},"referrer":{"type":["string","null"]},"session_id":{"type":"integer","format":"int32"},"started_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"visitor_id":{"type":"string"}}},"SessionDetailsQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"SessionEvent":{"type":"object","required":["id","timestamp"],"properties":{"event_data":{},"event_name":{"type":["string","null"]},"event_type":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"page_title":{"type":["string","null"]},"page_url":{"type":["string","null"]},"timestamp":{"type":"string"}}},"SessionEventDto":{"type":"object","required":["id","session_id","data","timestamp"],"properties":{"data":{},"event_type":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"session_id":{"type":"integer","format":"int32"},"timestamp":{"type":"integer","format":"int64"}}},"SessionEventsQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"SessionEventsResponse":{"type":"object","required":["session_id","events","total_count","offset","limit"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/SessionEvent"}},"limit":{"type":"integer","format":"int32"},"offset":{"type":"integer","format":"int32"},"session_id":{"type":"integer","format":"int32"},"total_count":{"type":"integer","format":"int64"}}},"SessionLogsQuery":{"type":"object","required":["project_id"],"properties":{"end_date":{"type":["string","null"],"format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"offset":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"sort_order":{"type":["string","null"]},"start_date":{"type":["string","null"],"format":"date-time"},"visitor_id":{"type":["integer","null"],"format":"int32"}}},"SessionLogsResponse":{"type":"object","required":["session_id","logs","total_count","offset","limit"],"properties":{"limit":{"type":"integer","format":"int32"},"logs":{"type":"array","items":{"$ref":"#/components/schemas/SessionRequestLog"}},"offset":{"type":"integer","format":"int32"},"session_id":{"type":"integer","format":"int32"},"total_count":{"type":"integer","format":"int64"}}},"SessionReplayEventsRequest":{"type":"object","required":["sessionId","events"],"properties":{"events":{"type":"string"},"sessionId":{"type":"string"}}},"SessionReplayInfoDto":{"type":"object","required":["id","visitor_id"],"properties":{"created_at":{"type":["string","null"]},"duration":{"type":["integer","null"],"format":"int32"},"id":{"type":"string"},"language":{"type":["string","null"]},"screen_height":{"type":["integer","null"],"format":"int32"},"screen_width":{"type":["integer","null"],"format":"int32"},"timezone":{"type":["string","null"]},"url":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"viewport_height":{"type":["integer","null"],"format":"int32"},"viewport_width":{"type":["integer","null"],"format":"int32"},"visitor_id":{"type":"integer","format":"int32"}}},"SessionReplayInitRequest":{"type":"object","required":["sessionId"],"properties":{"colorDepth":{"type":["integer","null"],"format":"int32","minimum":0},"language":{"type":["string","null"]},"screenHeight":{"type":["integer","null"],"format":"int32","minimum":0},"screenWidth":{"type":["integer","null"],"format":"int32","minimum":0},"sessionId":{"type":"string"},"timestamp":{"type":["string","null"]},"timezone":{"type":["string","null"]},"url":{"type":["string","null"]},"userAgent":{"type":["string","null"]},"viewportHeight":{"type":["integer","null"],"format":"int32","minimum":0},"viewportWidth":{"type":["integer","null"],"format":"int32","minimum":0}}},"SessionReplayInitResponse":{"type":"object","required":["session_id","message"],"properties":{"message":{"type":"string"},"session_id":{"type":"string"}}},"SessionReplayWithEventsDto":{"type":"object","required":["session","events"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/SessionEventDto"}},"session":{"$ref":"#/components/schemas/SessionReplayWithVisitorDto"}}},"SessionReplayWithVisitorDto":{"type":"object","required":["id","session_replay_id","visitor_id","visitor_uuid","visitor_project_id","visitor_environment_id","visitor_first_seen","visitor_last_seen","visitor_is_crawler"],"properties":{"browser":{"type":["string","null"]},"browser_version":{"type":["string","null"]},"created_at":{"type":["string","null"]},"device_type":{"type":["string","null"]},"duration":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"language":{"type":["string","null"]},"operating_system":{"type":["string","null"]},"operating_system_version":{"type":["string","null"]},"screen_height":{"type":["integer","null"],"format":"int32"},"screen_width":{"type":["integer","null"],"format":"int32"},"session_replay_id":{"type":"string"},"timezone":{"type":["string","null"]},"url":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"viewport_height":{"type":["integer","null"],"format":"int32"},"viewport_width":{"type":["integer","null"],"format":"int32"},"visitor_city":{"type":["string","null"]},"visitor_country":{"type":["string","null"]},"visitor_country_code":{"type":["string","null"]},"visitor_crawler_name":{"type":["string","null"]},"visitor_custom_data":{},"visitor_environment_id":{"type":"integer","format":"int32"},"visitor_first_seen":{"type":"string"},"visitor_id":{"type":"integer","format":"int32"},"visitor_is_crawler":{"type":"boolean"},"visitor_last_seen":{"type":"string"},"visitor_project_id":{"type":"integer","format":"int32"},"visitor_region":{"type":["string","null"]},"visitor_uuid":{"type":"string"}}},"SessionRequestLog":{"type":"object","required":["id","method","path","status_code","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"method":{"type":"string"},"path":{"type":"string"},"referrer":{"type":["string","null"]},"request_headers":{"type":["string","null"]},"response_headers":{"type":["string","null"]},"response_time_ms":{"type":["integer","null"],"format":"int32"},"status_code":{"type":"integer","format":"int32"},"user_agent":{"type":["string","null"]}}},"SessionSummary":{"type":"object","required":["session_id","started_at","duration_seconds","page_views","events_count","requests_count","is_bounced","is_engaged"],"properties":{"duration_seconds":{"type":"integer","format":"int64"},"ended_at":{"type":["string","null"],"format":"date-time","example":"2024-01-01T00:00:00"},"entry_path":{"type":["string","null"]},"events_count":{"type":"integer","format":"int64"},"exit_path":{"type":["string","null"]},"is_bounced":{"type":"boolean"},"is_engaged":{"type":"boolean"},"page_views":{"type":"integer","format":"int64"},"referrer":{"type":["string","null"]},"requests_count":{"type":"integer","format":"int64"},"session_id":{"type":"integer","format":"int32"},"started_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"}}},"SetFlagEnvironmentRequest":{"type":"object","properties":{"enabled":{"type":["boolean","null"],"description":"The kill switch. `false` makes the flag serve its default regardless of\nany override — and, once targeting exists, regardless of any rule."},"value":{"description":"Tri-state: absent leaves the override, `null` clears it (inherit the\nflag default), anything else sets it. Must match `value_type`."}}},"SetPreviewPasswordBody":{"type":"object","required":["password"],"properties":{"password":{"type":"string","description":"Plaintext password to protect the sandbox's preview URLs. Hashed\nserver-side with argon2id — we never persist or echo this back.\nMust be between 8 and 256 characters."}}},"SetPreviewPasswordResponse":{"type":"object","required":["preview_password_hint"],"properties":{"preview_password_hint":{"type":"string","description":"Last 4 chars of the password we just stored. Surface in the UI so\nusers can confirm which password is live without re-entering it."}}},"SetRequest":{"type":"object","description":"Request to set a value","required":["key","value"],"properties":{"ex":{"type":["integer","null"],"format":"int64","description":"Expire in seconds","example":3600},"key":{"type":"string","description":"The key to set","example":"user:123"},"nx":{"type":"boolean","description":"Only set if key does not exist"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1},"px":{"type":["integer","null"],"format":"int64","description":"Expire in milliseconds"},"value":{"description":"The value to store (can be any JSON value)"},"xx":{"type":"boolean","description":"Only set if key exists"}}},"SetResponse":{"type":"object","description":"Response for set operation","required":["result"],"properties":{"result":{"type":"string","description":"Always \"OK\" on success","example":"OK"}}},"SettingsUpdateResponse":{"type":"object","description":"Response for successful settings update","required":["message"],"properties":{"message":{"type":"string"}}},"SetupDnsChallengeRequest":{"type":"object","description":"Request to setup DNS challenge records using a configured DNS provider","required":["dns_provider_id"],"properties":{"dns_provider_id":{"type":"integer","format":"int32","description":"The ID of the DNS provider to use for creating the TXT records"}}},"SetupDnsChallengeResponse":{"type":"object","description":"Response from DNS challenge setup operation","required":["success","records_created","total_records","results","message"],"properties":{"message":{"type":"string","description":"Human-readable summary message"},"records_created":{"type":"integer","format":"int32","description":"Number of TXT records that were successfully created","minimum":0},"results":{"type":"array","items":{"$ref":"#/components/schemas/DnsChallengeRecordResult"},"description":"Results for each individual TXT record"},"success":{"type":"boolean","description":"Overall success status (true if all records were created)"},"total_records":{"type":"integer","format":"int32","description":"Total number of TXT records required for the challenge","minimum":0}}},"SetupDnsRequest":{"type":"object","description":"Request to setup DNS records using a configured DNS provider","required":["dns_provider_id"],"properties":{"dns_provider_id":{"type":"integer","format":"int32","description":"The ID of the DNS provider to use for creating records"}}},"SetupDnsResponse":{"type":"object","description":"Response from DNS setup operation","required":["success","records_created","total_records","results","message"],"properties":{"message":{"type":"string","description":"Human-readable summary message"},"records_created":{"type":"integer","format":"int32","description":"Number of records that were successfully created","minimum":0},"results":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecordSetupResult"},"description":"Results for each individual record"},"success":{"type":"boolean","description":"Overall success status"},"total_records":{"type":"integer","format":"int32","description":"Total number of records attempted","minimum":0}}},"SiblingRef":{"type":"object","description":"A sibling project that shares the same `trace_id` and has opted in to\ncross-project trace sharing (`cross_project_trace_sharing = TRUE`).\n\nReturned by `CrossProjectTraceService::find_sibling_projects` and exposed\nby the Phase 1 `GET /otel/traces/cross-project/{trace_id}` endpoint.","required":["project_id","project_name","project_slug","first_seen"],"properties":{"first_seen":{"type":"string","format":"date-time"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"project_slug":{"type":"string","description":"URL slug used to link into the sibling project's single-project trace view."}}},"SkillDefinitionResponse":{"type":"object","required":["id","slug","name","content","has_archive","created_at","updated_at"],"properties":{"content":{"type":"string"},"created_at":{"type":"string"},"description":{"type":["string","null"]},"has_archive":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"project_id":{"type":["integer","null"],"format":"int32"},"slug":{"type":"string"},"updated_at":{"type":"string"}}},"SlackConfig":{"type":"object","required":["webhook_url"],"properties":{"channel":{"type":["string","null"]},"webhook_url":{"type":"string"}}},"SlowQueriesResponse":{"type":"object","description":"Response envelope for the slow-queries list endpoint.","required":["queries","page","page_size","total_count"],"properties":{"page":{"type":"integer","format":"int32","description":"Current page number (1-based).","minimum":0},"page_size":{"type":"integer","format":"int32","description":"Number of rows per page used for this request.","minimum":0},"queries":{"type":"array","items":{"$ref":"#/components/schemas/SlowQueryRow"},"description":"Ordered list of query stats, slowest first by mean_exec_time_ms."},"total_count":{"type":"integer","format":"int64","description":"Total number of qualifying rows across all pages.","minimum":0}}},"SlowQueryRow":{"type":"object","description":"A single entry from `pg_stat_statements`, representing one normalized\nquery fingerprint and its aggregate execution stats.","required":["query","database","calls","total_exec_time_ms","mean_exec_time_ms","rows"],"properties":{"cache_hit_ratio":{"type":["number","null"],"format":"double","description":"Shared block cache hit ratio (0.0–1.0).\n`None` when total block accesses are zero (e.g. function-only queries)."},"calls":{"type":"integer","format":"int64","description":"Number of times this query was executed."},"database":{"type":"string","description":"Name of the database this query ran against. `(dropped database)`\nwhen the originating database no longer exists but\n`pg_stat_statements` still holds stats for it."},"mean_exec_time_ms":{"type":"number","format":"double","description":"Average wall-clock time per execution, in milliseconds."},"query":{"type":"string","description":"Normalized query text (parameter literals replaced with `$N`)."},"rows":{"type":"integer","format":"int64","description":"Total number of rows returned or affected."},"total_exec_time_ms":{"type":"number","format":"double","description":"Total wall-clock time spent executing this query, in milliseconds."}}},"SmartFilter":{"oneOf":[{"type":"object","description":"Match specific page path","required":["value","type"],"properties":{"type":{"type":"string","enum":["page_path"]},"value":{"type":"string","description":"Match specific page path"}}},{"type":"object","description":"Match specific hostname","required":["value","type"],"properties":{"type":{"type":"string","enum":["hostname"]},"value":{"type":"string","description":"Match specific hostname"}}},{"type":"object","description":"Match UTM source","required":["value","type"],"properties":{"type":{"type":"string","enum":["utm_source"]},"value":{"type":"string","description":"Match UTM source"}}},{"type":"object","description":"Match UTM campaign","required":["value","type"],"properties":{"type":{"type":"string","enum":["utm_campaign"]},"value":{"type":"string","description":"Match UTM campaign"}}},{"type":"object","description":"Match UTM medium","required":["value","type"],"properties":{"type":{"type":"string","enum":["utm_medium"]},"value":{"type":"string","description":"Match UTM medium"}}},{"type":"object","description":"Match referrer hostname","required":["value","type"],"properties":{"type":{"type":"string","enum":["referrer_hostname"]},"value":{"type":"string","description":"Match referrer hostname"}}},{"type":"object","description":"Match specific channel (organic, paid, direct, referral, etc.)","required":["value","type"],"properties":{"type":{"type":"string","enum":["channel"]},"value":{"type":"string","description":"Match specific channel (organic, paid, direct, referral, etc.)"}}},{"type":"object","description":"Match device type (mobile, desktop, tablet)","required":["value","type"],"properties":{"type":{"type":"string","enum":["device_type"]},"value":{"type":"string","description":"Match device type (mobile, desktop, tablet)"}}},{"type":"object","description":"Match browser","required":["value","type"],"properties":{"type":{"type":"string","enum":["browser"]},"value":{"type":"string","description":"Match browser"}}},{"type":"object","description":"Match operating system","required":["value","type"],"properties":{"type":{"type":"string","enum":["operating_system"]},"value":{"type":"string","description":"Match operating system"}}},{"type":"object","description":"Match language","required":["value","type"],"properties":{"type":{"type":"string","enum":["language"]},"value":{"type":"string","description":"Match language"}}},{"type":"object","description":"Match custom event_data by JSON path\nFormat: {\"path\": \"user.plan\", \"value\": \"premium\"}\nThis will match events where event_data->'user'->>'plan' = 'premium'","required":["value","type"],"properties":{"type":{"type":"string","enum":["custom_data"]},"value":{"type":"object","description":"Match custom event_data by JSON path\nFormat: {\"path\": \"user.plan\", \"value\": \"premium\"}\nThis will match events where event_data->'user'->>'plan' = 'premium'","required":["path","value"],"properties":{"path":{"type":"string"},"value":{"type":"string"}}}}}],"description":"Smart filter presets for common funnel patterns"},"SmokeTestResponse":{"type":"object","required":["passed","environment","cli_installed","cli_authenticated"],"properties":{"auth_info":{"type":["string","null"],"description":"Auth email / method"},"cli_authenticated":{"type":"boolean","description":"Claude CLI authenticated?"},"cli_installed":{"type":"boolean","description":"Claude CLI installed?"},"cli_version":{"type":["string","null"],"description":"Claude CLI version"},"detail":{"type":["string","null"],"description":"Full output for debugging"},"environment":{"type":"string","description":"Where the test ran: \"host\" or \"sandbox\""},"passed":{"type":"boolean","description":"Whether the smoke test passed"},"setup_hint":{"type":["string","null"],"description":"What the user needs to do if the test failed"}}},"SmtpCredentialsRequest":{"type":"object","description":"Generic SMTP credentials request body.\n\nWorks with any SMTP relay — AWS SES SMTP endpoints, Sendgrid, Mailgun,\nPostmark, or a self-hosted Postfix. Use this when you only have SMTP\ncredentials (i.e. you cannot create identities via the upstream API).","required":["host","port"],"properties":{"accept_invalid_certs":{"type":"boolean","description":"Accept self-signed certificates. Only safe for local testing."},"encryption":{"$ref":"#/components/schemas/SmtpEncryptionRoute","description":"TLS mode. Defaults to STARTTLS."},"host":{"type":"string","description":"SMTP host, e.g. `email-smtp.eu-west-1.amazonaws.com`.","example":"email-smtp.eu-west-1.amazonaws.com"},"password":{"type":["string","null"],"description":"SMTP password / API token. Required when `username` is set."},"port":{"type":"integer","format":"int32","description":"SMTP port (587 for STARTTLS, 465 for implicit TLS, 25/1025 for plain).","example":587,"minimum":0},"username":{"type":["string","null"],"description":"SMTP username. Leave empty for unauthenticated relays.","example":"AKIAIOSFODNN7EXAMPLE"}}},"SmtpEncryptionRoute":{"type":"string","description":"TLS mode for the SMTP relay.","enum":["starttls","tls","none"]},"SmtpResult":{"type":"object","description":"SMTP validation result","required":["can_connect_smtp","has_full_inbox","is_catch_all","is_deliverable","is_disabled"],"properties":{"can_connect_smtp":{"type":"boolean","description":"Whether we could connect to the SMTP server"},"error":{"type":["string","null"],"description":"Error message if SMTP check failed"},"has_full_inbox":{"type":"boolean","description":"Whether the mailbox appears to have a full inbox"},"is_catch_all":{"type":"boolean","description":"Whether this is a catch-all domain"},"is_deliverable":{"type":"boolean","description":"Whether the email is deliverable"},"is_disabled":{"type":"boolean","description":"Whether the mailbox is disabled"}}},"SourceArchiveUpload":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary"}}},"SourceBackupEntry":{"type":"object","description":"Entry in the source backup index. Covers both DB-tracked backups\n(have a row in `backups`) and S3-scan discoveries (raw S3 objects with\nno DB row — used for disaster-recovery from another Temps instance).","required":["id","backup_id","name","backup_type","created_at","location","metadata_location","source","state"],"properties":{"backup_id":{"type":"string","description":"UUID identifier from the DB row. Empty for S3-scan entries.","example":"550e8400-e29b-41d4-a716-446655440000"},"backup_type":{"type":"string","description":"Backup variant as recorded by the backup pipeline (e.g. \"full\").","example":"full"},"created_at":{"type":"string","description":"When the backup was created. For S3-scan entries this is the\nobject's LastModified time.","example":"2024-01-15T14:30:00.123Z"},"engine":{"type":["string","null"],"description":"Engine that produced the backup (\"postgres\", \"redis\", \"mongodb\",\n\"s3\", \"rustfs\"). Used by the UI to mark engine-compat with the\ntarget service.","example":"postgres"},"format":{"type":["string","null"],"description":"Storage format: \"walg\" for continuous-archive (PITR-capable),\n\"pg_dump\" for point-in-time dumps, \"\" for non-postgres.","example":"walg"},"id":{"type":"integer","format":"int32","description":"DB row id. Zero for S3-scan entries that have no DB row.","example":1},"location":{"type":"string","description":"Raw S3 URL / key where the backup sits. For Postgres WAL-G backups\nthis starts with `s3://`; for pg_dump-style backups it's the\nrelative object key.","example":"s3://bucket/external_services/postgres/svc-name/walg"},"metadata_location":{"type":"string","description":"Sidecar metadata.json location, if any. Empty when none.","example":""},"name":{"type":"string","description":"Human-friendly display name (\"postgres backup (svc-name)\" for DB\nrows, or a synthesized label derived from the S3 path for scans).","example":"postgres backup (postgres-n4ea)"},"origin_service_name":{"type":["string","null"],"description":"Name of the service that produced the backup. For S3-scan entries\nthis is parsed from the S3 path.","example":"postgres-n4ea"},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size of the backup in bytes, if known.","example":1024000},"source":{"type":"string","description":"Provenance: \"db\" for rows in this Temps, \"s3_scan\" for objects\ndiscovered by the S3 bucket walk (e.g., backups made by another\nTemps instance).","example":"db"},"state":{"type":"string","description":"Observed state (\"completed\", \"running\", \"failed\") — DB only.\nEmpty string for S3-scan entries.","example":"completed"}}},"SourceBackupIndexResponse":{"type":"object","description":"Response type for source backup index","required":["backups","last_updated"],"properties":{"backups":{"type":"array","items":{"$ref":"#/components/schemas/SourceBackupEntry"},"description":"List of backups in the source"},"last_updated":{"type":"string","description":"When the index was last updated","example":"2024-01-15T14:30:00.123Z"}}},"SourceBody":{"oneOf":[{"type":"object","required":["url","type"],"properties":{"depth":{"type":["integer","null"],"format":"int32","minimum":0},"git_connection_id":{"type":["integer","null"],"format":"int32"},"password":{"type":["string","null"]},"revision":{"type":["string","null"]},"type":{"type":"string","enum":["git"]},"url":{"type":"string"},"username":{"type":["string","null"]}}},{"type":"object","required":["url","type"],"properties":{"type":{"type":"string","enum":["tarball"]},"url":{"type":"string"}}}],"description":"Initial content to seed into the sandbox work dir. Mirrors the\n`@vercel/sandbox` `source` option. `type` is one of:\n- `git` — clone `url`; optionally check out `revision`\n- `tarball` — download `url` (must be tar or tar.gz) and extract\n\nFor private git repos, pass credentials one of two ways:\n1. **Inline (SDK-compatible):** `username` + `password`. GitHub\n tokens use `username: \"x-access-token\"`.\n2. **Stored connection (temps-native):** `git_connection_id`\n references a row in the caller's git provider connections. Temps\n resolves the token server-side and injects it safely.\n\n`git_connection_id` is mutually exclusive with `username`/`password`."},"SourceFileListResponse":{"type":"object","required":["source_files","total"],"properties":{"source_files":{"type":"array","items":{"$ref":"#/components/schemas/SourceFileResponse"}},"total":{"type":"integer","minimum":0}}},"SourceFileResponse":{"type":"object","required":["id","project_id","release","file_path","size_bytes","created_at"],"properties":{"checksum":{"type":["string","null"]},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"file_path":{"type":"string"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"release":{"type":"string"},"size_bytes":{"type":"integer","format":"int64"}}},"SourceMapListResponse":{"type":"object","required":["source_maps","total"],"properties":{"source_maps":{"type":"array","items":{"$ref":"#/components/schemas/SourceMapResponse"}},"total":{"type":"integer","minimum":0}}},"SourceMapResponse":{"type":"object","required":["id","project_id","release","file_path","size_bytes","created_at"],"properties":{"checksum":{"type":["string","null"]},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"dist":{"type":["string","null"]},"file_path":{"type":"string"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"release":{"type":"string"},"size_bytes":{"type":"integer","format":"int64"}}},"SourceType":{"type":"string","description":"Source type for project deployments\n\nDetermines where the deployment artifacts come from:\n- `Git`: Source code from a Git repository (traditional flow)\n- `DockerImage`: Pre-built Docker image from external registry\n- `StaticFiles`: Pre-built static files uploaded as a bundle\n- `UploadedSource`: Source archive uploaded without a Git repository\n- `Manual`: Flexible type that accepts any deployment method","enum":["git","docker_image","static_files","uploaded_source","manual"]},"SpanEvent":{"type":"object","description":"A span event (log-like annotation on a span).","required":["timestamp","name","attributes"],"properties":{"attributes":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":"string"},"timestamp":{"type":"string","format":"date-time"}}},"SpanKind":{"type":"string","description":"Span kind.","enum":["UNSPECIFIED","INTERNAL","SERVER","CLIENT","PRODUCER","CONSUMER"]},"SpanRecord":{"type":"object","description":"A single trace span ready for storage.","required":["project_id","resource","trace_id","span_id","name","kind","start_time","end_time","duration_ms","status_code","status_message","attributes","events"],"properties":{"attributes":{"type":"object","description":"Raw key/value pairs exactly as reported by the instrumenting library.\nNumeric values are NOT guaranteed to share `duration_ms`'s unit — they\nmay be seconds, milliseconds, microseconds, or nanoseconds depending on\nthe exporter's own convention, and the unit is not labeled here.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"deployment_id":{"type":["integer","null"],"format":"int32"},"duration_ms":{"type":"number","format":"double","description":"Span duration in milliseconds. The only field on this struct guaranteed\nto be in milliseconds."},"end_time":{"type":"string","format":"date-time"},"events":{"type":"array","items":{"$ref":"#/components/schemas/SpanEvent"}},"kind":{"$ref":"#/components/schemas/SpanKind"},"name":{"type":"string"},"parent_span_id":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"resource":{"$ref":"#/components/schemas/ResourceInfo"},"span_id":{"type":"string"},"start_time":{"type":"string","format":"date-time"},"status_code":{"$ref":"#/components/schemas/SpanStatusCode"},"status_message":{"type":"string"},"trace_id":{"type":"string"}}},"SpanRow":{"type":"object","required":["id","ts","trace_id","span_id","service","operation","attributes","attributes_truncated"],"properties":{"attributes":{},"attributes_truncated":{"type":"boolean"},"deployment_id":{"type":["integer","null"],"format":"int32"},"duration_ms":{"type":["number","null"],"format":"double"},"environment_id":{"type":["integer","null"],"format":"int32"},"id":{"type":"string"},"operation":{"type":"string"},"parent_span_id":{"type":["string","null"]},"service":{"type":"string"},"span_id":{"type":"string"},"status":{"type":["string","null"]},"trace_id":{"type":"string"},"ts":{"type":"string","format":"date-time"}}},"SpanStatusCode":{"type":"string","description":"Span status code.","enum":["UNSET","OK","ERROR"]},"SpeedMetricsPayload":{"type":"object","description":"Speed metrics payload for recording web vitals","properties":{"cls":{"type":["number","null"],"format":"float","description":"Cumulative Layout Shift (score)"},"fcp":{"type":["number","null"],"format":"float","description":"First Contentful Paint (milliseconds)"},"fid":{"type":["number","null"],"format":"float","description":"First Input Delay (milliseconds)"},"inp":{"type":["number","null"],"format":"float","description":"Interaction to Next Paint (milliseconds)"},"language":{"type":["string","null"],"description":"Browser language"},"lcp":{"type":["number","null"],"format":"float","description":"Largest Contentful Paint (milliseconds)"},"pathname":{"type":["string","null"],"description":"Page pathname"},"query":{"type":["string","null"],"description":"Query string"},"screenHeight":{"type":["integer","null"],"format":"int32","description":"Screen height in pixels"},"screenWidth":{"type":["integer","null"],"format":"int32","description":"Screen width in pixels"},"ttfb":{"type":["number","null"],"format":"float","description":"Time to First Byte (milliseconds)"},"viewportHeight":{"type":["integer","null"],"format":"int32","description":"Viewport height in pixels"},"viewportWidth":{"type":["integer","null"],"format":"int32","description":"Viewport width in pixels"}}},"SpeedSegmentFilters":{"type":"object","description":"Optional segment filters for the performance read endpoints, mirroring\nanalytics' `VisitorSegmentFilters`. Each filter narrows results to samples\nmatching the dimension value, so metrics can be scoped to e.g. one page,\none browser, or one country. Geographic filters resolve via\n`ip_geolocations`; the rest live directly on `performance_metrics`.","properties":{"filter_browser":{"type":["string","null"],"description":"Browser name (matches `performance_metrics.browser`)"},"filter_city":{"type":["string","null"],"description":"Geolocation city (matches `ip_geolocations.city`)"},"filter_country":{"type":["string","null"],"description":"Geolocation country (matches `ip_geolocations.country`)"},"filter_operating_system":{"type":["string","null"],"description":"Operating system (matches `performance_metrics.operating_system`)"},"filter_path":{"type":["string","null"],"description":"Page pathname (matches `performance_metrics.pathname`)"},"filter_region":{"type":["string","null"],"description":"Geolocation region (matches `ip_geolocations.region`)"}}},"StaleSlot":{"type":"object","required":["slot_name","active","retained_bytes"],"properties":{"active":{"type":"boolean"},"retained_bytes":{"type":"integer","format":"int64"},"slot_name":{"type":"string"}}},"StartAnalysisRequest":{"type":"object","required":["error_group_id"],"properties":{"branch":{"type":["string","null"],"description":"Branch to clone instead of the project's main branch."},"error_group_id":{"type":"integer","format":"int32"},"max_turns":{"type":["integer","null"],"format":"int32","description":"Per-run turn cap applied to every phase (1–200). Only enforced for\nCLIs with a turn flag (Claude Code). `None` uses the provider's\nconfigured defaults."},"model":{"type":["string","null"],"description":"Model id for the chosen provider. `None` uses the provider's saved\ndefault model."},"provider":{"type":["string","null"],"description":"AI provider id (\"claude_cli\", \"codex_cli\", \"opencode\"). `None` uses\nthe platform default provider."},"user_context":{"type":["string","null"],"description":"Free-text notes for the model (extra context about the error, retry\nguidance, constraints). Included verbatim in the analysis prompt."}}},"StartPgUpgradeRequest":{"type":"object","required":["from_version","to_version","from_image","to_image"],"properties":{"from_image":{"type":"string","example":"postgres:16-bookworm"},"from_version":{"type":"string","example":"16"},"to_image":{"type":"string","example":"postgres:17-bookworm"},"to_version":{"type":"string","example":"17"}}},"StartRestoreRequest":{"allOf":[{"$ref":"#/components/schemas/RestoreRequestMode","description":"Requested restore mode. See `RestoreRequestMode`."},{"type":"object","properties":{"backup_engine":{"type":["string","null"],"description":"Engine of the backup when specified by `backup_location`\n(\"postgres\", \"redis\", \"mongodb\", \"s3\"). Ignored when `backup_id`\nis used — we infer from the DB row."},"backup_id":{"type":["integer","null"],"format":"int32","description":"DB id of the backup to restore from. Either `backup_id` or\n`backup_location` MUST be provided. Use `backup_id` when restoring\na backup this Temps instance recorded."},"backup_location":{"type":["string","null"],"description":"Raw S3 URL / key of the backup — used when restoring a backup\ndiscovered by S3 scan (i.e., produced by another Temps instance).\nRequires `backup_engine` and `s3_source_id` to also be set."},"s3_source_id":{"type":["integer","null"],"format":"int32","description":"S3 source the `backup_location` lives in. Ignored when `backup_id`\nis used."}}}]},"StatResponse":{"type":"object","required":["path","exists","is_dir","is_file","size"],"properties":{"exists":{"type":"boolean"},"is_dir":{"type":"boolean"},"is_file":{"type":"boolean"},"path":{"type":"string"},"size":{"type":"integer","format":"int64","minimum":0}}},"StaticBundleResponse":{"type":"object","required":["id","project_id","blob_path","content_type","size_bytes","uploaded_at","created_at"],"properties":{"blob_path":{"type":"string"},"checksum":{"type":["string","null"]},"content_type":{"type":"string"},"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"format":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"metadata":{},"original_filename":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"size_bytes":{"type":"integer","format":"int64"},"uploaded_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"}}},"StaticParams":{"type":"object","description":"Static threshold detector: compare the aggregated `value` against `threshold`.","required":["comparator","threshold"],"properties":{"comparator":{"$ref":"#/components/schemas/Comparator","description":"How `value` is compared against `threshold`."},"threshold":{"type":"number","format":"double","description":"The threshold the aggregated value is compared against."}}},"StaticPresetConfig":{"type":"object","description":"Configuration for static site presets (Vite, Next.js, Docusaurus, etc.)\nThese presets build static sites that are served via a web server","properties":{"buildCommand":{"type":["string","null"],"description":"Custom build command (overrides preset default)","example":"npm run build:production"},"buildContext":{"type":["string","null"],"description":"Custom build context path (relative to repository root)\nUseful for monorepo setups where the app is in a subdirectory","example":"./apps/frontend"},"installCommand":{"type":["string","null"],"description":"Custom install command (overrides auto-detected package manager)","example":"npm ci"},"outputDir":{"type":["string","null"],"description":"Custom output directory (overrides preset default)\nCommon values: \"dist\", \"build\", \".next\", \"out\"","example":"dist"}}},"StatsFilters":{"type":"object","description":"Filters for statistics queries","properties":{"client_ip":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"device_type":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"has_project":{"type":["boolean","null"],"description":"When true, only count requests that matched a project (project_id IS NOT NULL).\nUsed by the health dashboard so totals match the per-project cards."},"host":{"type":["string","null"]},"is_bot":{"type":["boolean","null"]},"method":{"type":["string","null"]},"project_id":{"type":["integer","null"],"format":"int32"},"request_source":{"type":["string","null"]},"routing_status":{"type":["string","null"]},"status_code":{"type":["integer","null"],"format":"int32"},"status_code_class":{"type":["string","null"],"description":"Filter by status code class (e.g. \"2xx\", \"3xx\", \"4xx\", \"5xx\")"}}},"StatusBucket":{"type":"object","required":["bucket_start","status","total_checks","operational_count","degraded_count","down_count","uptime_percentage"],"properties":{"avg_response_time_ms":{"type":["number","null"],"format":"double"},"bucket_start":{"type":"string","format":"date-time"},"degraded_count":{"type":"integer","format":"int64"},"down_count":{"type":"integer","format":"int64"},"max_response_time_ms":{"type":["number","null"],"format":"double"},"min_response_time_ms":{"type":["number","null"],"format":"double"},"operational_count":{"type":"integer","format":"int64"},"p50_response_time_ms":{"type":["number","null"],"format":"double"},"p95_response_time_ms":{"type":["number","null"],"format":"double"},"p99_response_time_ms":{"type":["number","null"],"format":"double"},"status":{"type":"string"},"total_checks":{"type":"integer","format":"int64"},"uptime_percentage":{"type":"number","format":"double"}}},"StatusBucketedResponse":{"type":"object","required":["monitor_id","interval","buckets"],"properties":{"buckets":{"type":"array","items":{"$ref":"#/components/schemas/StatusBucket"}},"interval":{"type":"string"},"monitor_id":{"type":"integer","format":"int32"}}},"StatusCodeCount":{"type":"object","required":["status_code","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"percentage":{"type":"number","format":"double"},"status_code":{"type":"integer","format":"int32"}}},"StatusCodesQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"StatusPageOverview":{"type":"object","required":["status","monitors","recent_incidents"],"properties":{"monitors":{"type":"array","items":{"$ref":"#/components/schemas/MonitorStatus"}},"recent_incidents":{"type":"array","items":{"$ref":"#/components/schemas/IncidentResponse"}},"status":{"type":"string"}}},"StepConversionResponse":{"type":"object","required":["step_id","step_name","step_order","completions","conversion_rate","drop_off_rate","average_time_to_complete_seconds"],"properties":{"average_time_to_complete_seconds":{"type":"number","format":"double"},"completions":{"type":"integer","format":"int64","minimum":0},"conversion_rate":{"type":"number","format":"double"},"drop_off_rate":{"type":"number","format":"double"},"step_id":{"type":"integer","format":"int32"},"step_name":{"type":"string"},"step_order":{"type":"integer","format":"int32"}}},"StepResourceType":{"type":"string","description":"What kind of resource a migration step operates on","enum":["project","environment","deployment","environment-variable","service","domain","git-link","other"]},"StepResult":{"type":"object","description":"Result of executing a single migration step","required":["step_id","step_title","success","skipped","message","created_resources","duration_seconds"],"properties":{"created_resources":{"type":"array","items":{"$ref":"#/components/schemas/CreatedResource"},"description":"Resources created by this step"},"duration_seconds":{"type":"number","format":"double","description":"Duration of this step"},"message":{"type":"string","description":"Human-readable message about what happened"},"skipped":{"type":"boolean","description":"Whether this step was skipped"},"step_id":{"type":"string","description":"Step ID (matches `MigrationStep.id`)"},"step_title":{"type":"string","description":"Step title (for display)"},"success":{"type":"boolean","description":"Whether this step succeeded"}}},"StepUpResponse":{"type":"object","required":["expires_at"],"properties":{"expires_at":{"type":"string","format":"date-time","description":"ISO 8601 timestamp after which sensitive actions require verification\nagain."}}},"StopSequence":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"StorageQuota":{"type":"object","description":"Quota usage information for a project.","required":["project_id","metrics_bytes","traces_bytes","logs_bytes","total_bytes","limit_bytes","usage_pct"],"properties":{"limit_bytes":{"type":"integer","format":"int64","minimum":0},"logs_bytes":{"type":"integer","format":"int64","minimum":0},"metrics_bytes":{"type":"integer","format":"int64","minimum":0},"project_id":{"type":"integer","format":"int32"},"total_bytes":{"type":"integer","format":"int64","minimum":0},"traces_bytes":{"type":"integer","format":"int64","minimum":0},"usage_pct":{"type":"number","format":"double"}}},"StripeConfig":{"type":"object","properties":{"include_unpriced_charges":{"type":"boolean","description":"When an allowlist is set, should we still ingest charges that\nlack a price reference (e.g. standalone `charge.succeeded` without\na subscription)? Default true — charges don't belong to a SKU."},"metered_mode":{"$ref":"#/components/schemas/MeteredMode","description":"How to compute MRR for metered / tiered / hybrid subscriptions."},"price_allowlist":{"type":"array","items":{"type":"string"},"description":"Only events tagged with one of these Stripe price IDs are ingested.\nEmpty = accept all prices."},"product_allowlist":{"type":"array","items":{"type":"string"},"description":"Only events tagged with one of these Stripe product IDs are\ningested. Empty = accept all products. Combined with\n`price_allowlist` via OR — if either list has a match, accept."}}},"SyncedRepositoryListQuery":{"type":"object","properties":{"direction":{"type":["string","null"]},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"language":{"type":["string","null"]},"owner":{"type":["string","null"]},"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0},"private":{"type":["boolean","null"]},"search":{"type":["string","null"]},"sort":{"type":["string","null"]}}},"SyntaxResult":{"type":"object","description":"Syntax validation result","required":["is_valid_syntax"],"properties":{"domain":{"type":["string","null"],"description":"The domain part of the email","example":"gmail.com"},"is_valid_syntax":{"type":"boolean","description":"Whether the email syntax is valid"},"suggestion":{"type":["string","null"],"description":"Suggested email correction if available"},"username":{"type":["string","null"],"description":"The username part of the email","example":"someone"}}},"TagInfo":{"type":"object","required":["name","commit_sha"],"properties":{"commit_sha":{"type":"string"},"name":{"type":"string"}}},"TagListResponse":{"type":"object","required":["tags"],"properties":{"tags":{"type":"array","items":{"$ref":"#/components/schemas/TagInfo"}}}},"TailLogsRequest":{"type":"object","required":["project_id","service","env"],"properties":{"env":{"type":"string"},"external_service_id":{"type":["integer","null"],"format":"int32","description":"When set, tail an imported/managed external service's logs instead of\na project's (`project_id` is ignored in this mode)."},"levels":{"type":"array","items":{"type":"string"}},"project_id":{"type":"integer","format":"int32","description":"Project ID (integer, as used by the rest of the platform)"},"service":{"type":"string"},"text":{"type":["string","null"]}}},"TargetRecommendation":{"type":"object","description":"The temps/Hetzner target sizing and savings estimate","required":["server_type","vcpus","memory_gb","monthly_eur","fits_single_node","sizing_basis","rationale"],"properties":{"fits_single_node":{"type":"boolean","description":"Whether the workloads fit a single recommended server. When `false`,\nthe rationale explains the multi-node option (temps worker nodes)."},"memory_gb":{"type":"integer","format":"int32","description":"Memory (GB) of the recommended server"},"monthly_eur":{"type":"number","format":"double","description":"Estimated monthly price of the recommended server in EUR"},"monthly_savings_usd":{"type":["number","null"],"format":"double","description":"Estimated monthly savings in USD (current cost minus target cost,\ntreating EUR≈USD for the rough comparison — disclaimed in `notes`).\n`None` when the current cost is unknown."},"rationale":{"type":"string","description":"Human-readable recommendation summary"},"server_type":{"type":"string","description":"Recommended Hetzner server type (e.g. \"cpx32\")"},"sizing_basis":{"type":"string","description":"What the sizing was based on, e.g. \"2× measured usage + temps\nplatform overhead\" or \"resource requests (no metrics available)\""},"vcpus":{"type":"integer","format":"int32","description":"vCPUs of the recommended server"},"yearly_savings_usd":{"type":["number","null"],"format":"double","description":"`monthly_savings_usd × 12`"}}},"TeamListResponse":{"type":"object","required":["teams","total","page","page_size"],"properties":{"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"teams":{"type":"array","items":{"$ref":"#/components/schemas/TeamResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"TeamMemberResponse":{"type":"object","required":["id","team_id","user_id","role","added_by","created_at","updated_at"],"properties":{"added_by":{"type":"integer","format":"int32"},"created_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"},"id":{"type":"integer","format":"int32"},"role":{"$ref":"#/components/schemas/TeamRole","description":"The source of this member's project-scoped permissions, intersected\nwith `project_team_access.role`."},"team_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"},"user_email":{"type":["string","null"],"description":"The member's email, joined from `users`."},"user_id":{"type":"integer","format":"int32"},"user_name":{"type":["string","null"],"description":"The member's display name, joined from `users`. `None` if the\nreferenced user no longer exists."}}},"TeamResponse":{"type":"object","required":["id","name","slug","created_by","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"},"created_by":{"type":"integer","format":"int32"},"description":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"slug":{"type":"string"},"updated_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"}}},"TeamRole":{"type":"string","description":"Role a user holds within a team, or that a team holds on a project.\n\nNamed `TeamRole` rather than `Role` to keep it distinct from\n`temps_auth::permissions::Role`, which is the instance-wide role\n(Admin/User/…) attached to a session. The two are orthogonal: the\ninstance-wide role decides whether you may touch a resource *kind* at\nall, `TeamRole` decides what you may do *within a project* you have\nteam access to. See `temps_teams::fixed_role_permissions` for the\nproject-scoped permission set each variant maps to.\n\nStored as a `varchar(32)` rather than a Postgres enum so the role set\ncan evolve in pure migration code without a schema-level enum\nalteration blocking a downgrade.","enum":["owner","admin","deployer","viewer"]},"TemplateResponse":{"type":"object","description":"Response type for a single template","required":["slug","name","git","preset","tags","features","services","env_vars","is_featured"],"properties":{"description":{"type":["string","null"],"description":"Short description"},"env_vars":{"type":"array","items":{"$ref":"#/components/schemas/EnvVarTemplateResponse"},"description":"Environment variables template"},"exposed_port":{"type":["integer","null"],"format":"int32","description":"Container port the prebuilt image listens on (image deploys only)."},"features":{"type":"array","items":{"type":"string"},"description":"Feature highlights"},"git":{"$ref":"#/components/schemas/GitRefResponse","description":"Git repository reference"},"health_check_path":{"type":["string","null"],"description":"HTTP health-check path probed after the container starts (image deploys)."},"image":{"type":["string","null"],"description":"Prebuilt Docker image reference. When set, the one-click deploy pulls and\nruns this image directly (no build); when absent it builds from `git`."},"image_url":{"type":["string","null"],"description":"URL to template image/icon"},"is_featured":{"type":"boolean","description":"Whether the template is featured/promoted"},"name":{"type":"string","description":"Display name"},"preset":{"type":"string","description":"Framework/preset to use"},"screenshot_url":{"type":["string","null"],"description":"URL to a wide screenshot/banner preview of the deployed template.\nAbsent for templates that don't have one captured yet."},"services":{"type":"array","items":{"type":"string"},"description":"Required external services"},"slug":{"type":"string","description":"Unique identifier for the template (used in URLs)"},"tags":{"type":"array","items":{"type":"string"},"description":"Tags/categories for filtering"}}},"TestEmailRequest":{"type":"object","description":"Request body for testing an email provider","required":["from"],"properties":{"from":{"type":"string","description":"Sender email address (must be verified with the provider)","example":"test@example.com"},"from_name":{"type":["string","null"],"description":"Sender display name","example":"My App"}}},"TestEmailResponse":{"type":"object","description":"Response for test email endpoint","required":["success","sent_to"],"properties":{"error":{"type":["string","null"],"description":"Error message if the test failed"},"provider_message_id":{"type":["string","null"],"description":"Provider message ID if successful"},"sent_to":{"type":"string","description":"The email address the test was sent to","example":"user@example.com"},"success":{"type":"boolean","description":"Whether the test email was sent successfully"}}},"TestProviderKeyRequest":{"type":"object","required":["provider","api_key"],"properties":{"api_key":{"type":"string","description":"The raw API key to test"},"base_url":{"type":["string","null"],"description":"Optional custom base URL"},"provider":{"type":"string","description":"Provider ID: \"openai\", \"anthropic\", \"xai\", \"gemini\""}}},"TestProviderKeyResponse":{"type":"object","required":["success","provider","latency_ms"],"properties":{"error":{"type":["string","null"],"description":"Error message if the test failed"},"latency_ms":{"type":"integer","format":"int64","description":"Response time in milliseconds","minimum":0},"provider":{"type":"string"},"success":{"type":"boolean"}}},"TestProviderResponse":{"type":"object","required":["success"],"properties":{"message":{"type":["string","null"]},"success":{"type":"boolean"}}},"TimeBucketStats":{"type":"object","description":"Time bucket statistics response","required":["bucket","request_count","avg_response_time_ms","error_count","total_request_bytes","total_response_bytes"],"properties":{"avg_response_time_ms":{"type":"number","format":"double","description":"Average response time in milliseconds"},"bucket":{"type":"string","description":"Bucket timestamp in RFC3339 format","example":"2025-10-23T12:00:00Z"},"error_count":{"type":"integer","format":"int64","description":"Number of errors (status >= 400)"},"request_count":{"type":"integer","format":"int64","description":"Total number of requests in this bucket"},"total_request_bytes":{"type":"integer","format":"int64","description":"Total request bytes"},"total_response_bytes":{"type":"integer","format":"int64","description":"Total response bytes"}}},"TimeBucketStatsResponse":{"type":"object","description":"Response for time bucket stats","required":["stats","start_time","end_time","bucket_interval"],"properties":{"bucket_interval":{"type":"string"},"end_time":{"type":"string"},"start_time":{"type":"string"},"stats":{"type":"array","items":{"$ref":"#/components/schemas/TimeBucketStats"}}}},"TimeseriesBucket":{"type":"object","required":["bucket","request_count","input_tokens","output_tokens","avg_latency_ms"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"bucket":{"type":"string","description":"ISO 8601 timestamp"},"input_tokens":{"type":"integer","format":"int64"},"output_tokens":{"type":"integer","format":"int64"},"request_count":{"type":"integer","format":"int64"}}},"TimeseriesQueryParams":{"type":"object","properties":{"bucket":{"type":["string","null"],"description":"Bucket size: \"hour\", \"day\", \"week\" (defaults to \"day\")"},"conversation_id":{"type":["string","null"],"description":"Filter by conversation ID"},"from":{"type":["string","null"],"description":"ISO 8601 start time (defaults to 24h ago)"},"model":{"type":["string","null"],"description":"Filter by model name"},"provider":{"type":["string","null"],"description":"Filter by provider name"},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"to":{"type":["string","null"],"description":"ISO 8601 end time (defaults to now)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"TlsMode":{"type":"string","enum":["None","Starttls","Tls"]},"TodayStatsResponse":{"type":"object","description":"Today's stats response","required":["total_requests","date"],"properties":{"date":{"type":"string","description":"Date for which stats are returned","example":"2025-10-23"},"total_requests":{"type":"integer","format":"int64","description":"Total requests today"}}},"ToggleAiDataAccessRequest":{"type":"object","required":["enabled"],"properties":{"enabled":{"type":"boolean","description":"Whether the AI assistant may read row data from this service.","example":false}}},"ToggleDeploymentMetricsRequest":{"type":"object","description":"Request body to toggle OTLP metric ingestion for a deployment.","required":["enabled"],"properties":{"enabled":{"type":"boolean","description":"Whether to enable (`true`) or disable (`false`) metric ingestion."},"path":{"type":["string","null"],"description":"Prometheus scrape path (optional, defaults to `/metrics`)."},"port":{"type":["integer","null"],"format":"int32","description":"Prometheus scrape port (optional).","minimum":0}}},"ToggleServiceMetricsRequest":{"type":"object","description":"Request body to toggle metric collection for an external service.","required":["enabled"],"properties":{"enabled":{"type":"boolean","description":"Whether to enable (`true`) or disable (`false`) metric collection."}}},"TokenRenewalRequest":{"type":"object","required":["refresh_token"],"properties":{"refresh_token":{"type":"string"}}},"ToolCallEvent":{"type":"object","description":"Payload for the `tool_call` SSE event: the model is about to run a tool.\nSerialized as compact single-line JSON onto one `data:` line.","required":["id","name","arguments"],"properties":{"arguments":{"type":"string","description":"The raw JSON-args string the model emitted."},"id":{"type":"string"},"name":{"type":"string"}}},"ToolInfo":{"type":"object","description":"One persisted tool invocation + its result, attached to an assistant message.","required":["id","name","arguments"],"properties":{"arguments":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"result":{"type":["string","null"]}}},"ToolResultEvent":{"type":"object","description":"Payload for the `tool_result` SSE event: a tool finished running. Serialized\nas compact single-line JSON; `content` is JSON-string-escaped so it stays on\none `data:` line even when long.","required":["id","name","content"],"properties":{"content":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"}}},"TopModelsQueryParams":{"type":"object","properties":{"from":{"type":["string","null"],"description":"ISO 8601 start time (defaults to 24h ago)"},"limit":{"type":["integer","null"],"format":"int64","description":"Max results (defaults to 10)","minimum":0},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"to":{"type":["string","null"],"description":"ISO 8601 end time (defaults to now)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"TraceProjectRef":{"type":"object","description":"All projects that contributed spans to a trace, including their sharing flag.\n\nReturned by `CrossProjectTraceService::find_trace_projects`.","required":["project_id","project_name","project_slug","first_seen","sharing"],"properties":{"first_seen":{"type":"string","format":"date-time"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"project_slug":{"type":"string","description":"URL slug used to link into the project's single-project trace view."},"sharing":{"type":"boolean","description":"Whether this project has `cross_project_trace_sharing = true`."}}},"TraceSummariesResponse":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TraceSummary"}},"total":{"type":["integer","null"],"format":"int64","description":"Total traces matching the filters, ignoring pagination. Omitted when\nthe request passed `include_total=false`, in which case the caller\nasked not to pay for the count — treat its absence as \"unknown\", not\nas zero.","minimum":0}}},"TraceSummary":{"type":"object","description":"A trace summary for the list view — one row per trace, aggregated from spans.","required":["trace_id","root_span_name","service_name","kind","status_code","start_time","duration_ms","span_count","error_count"],"properties":{"deployment_environment":{"type":["string","null"],"description":"The deployment environment from the root span's resource attributes (e.g. \"production\")."},"duration_ms":{"type":"number","format":"double"},"error_count":{"type":"integer","format":"int64"},"kind":{"$ref":"#/components/schemas/SpanKind"},"root_span_name":{"type":"string"},"service_name":{"type":"string"},"span_count":{"type":"integer","format":"int64"},"start_time":{"type":"string","format":"date-time"},"status_code":{"$ref":"#/components/schemas/SpanStatusCode"},"trace_id":{"type":"string"}}},"TracesResponse":{"type":"object","required":["data","count"],"properties":{"count":{"type":"integer","minimum":0},"data":{"type":"array","items":{"$ref":"#/components/schemas/SpanRecord"}}}},"TrackedLinkResponse":{"type":"object","description":"Tracked link with click count","required":["link_index","original_url","click_count"],"properties":{"click_count":{"type":"integer","format":"int32"},"link_index":{"type":"integer","format":"int32"},"original_url":{"type":"string"}}},"TrackingEventResponse":{"type":"object","description":"Email tracking event","required":["id","email_id","event_type","created_at"],"properties":{"created_at":{"type":"string"},"email_id":{"type":"string"},"event_type":{"type":"string"},"id":{"type":"integer","format":"int64"},"ip_address":{"type":["string","null"]},"link_index":{"type":["integer","null"],"format":"int32"},"link_url":{"type":["string","null"]},"user_agent":{"type":["string","null"]}}},"TriggerAgentRequest":{"type":"object","properties":{"trigger_source_id":{"type":["integer","null"],"format":"int32"},"trigger_source_type":{"type":["string","null"]},"user_context":{"type":["string","null"],"description":"Optional context from the user (e.g. a research topic, bug description, or instructions)."}}},"TriggerDigestResponse":{"type":"object","required":["success","message"],"properties":{"message":{"type":"string"},"success":{"type":"boolean"}}},"TriggerPipelinePayload":{"type":"object","properties":{"branch":{"type":["string","null"]},"commit":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment ID - if not provided, will use the project's preview environment"},"tag":{"type":["string","null"]}}},"TriggerPipelineResponse":{"type":"object","required":["message","project_id","environment_id"],"properties":{"branch":{"type":["string","null"]},"commit":{"type":["string","null"]},"environment_id":{"type":"integer","format":"int32"},"message":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"tag":{"type":["string","null"]}}},"TriggerScanRequest":{"type":"object","required":["environment_id"],"properties":{"environment_id":{"type":"integer","format":"int32","description":"Environment ID to scan (uses the current deployment for this environment)","example":1}}},"TriggerScanResponse":{"type":"object","required":["scan_id","status","message"],"properties":{"message":{"type":"string"},"scan_id":{"type":"integer","format":"int32"},"status":{"type":"string"}}},"TtlRequest":{"type":"object","description":"Request to get TTL for a key","required":["key"],"properties":{"key":{"type":"string","description":"The key to check TTL for","example":"session:abc"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"TtlResponse":{"type":"object","description":"Response for TTL operation","required":["ttl"],"properties":{"ttl":{"type":"integer","format":"int64","description":"TTL in seconds, -1 if no expiration, -2 if key doesn't exist","example":3600}}},"TxtRecord":{"type":"object","required":["name","value"],"properties":{"name":{"type":"string"},"value":{"type":"string"}}},"UiManifest":{"type":"object","description":"Describes the plugin's embedded UI bundle.","required":["entry_js"],"properties":{"css":{"type":"array","items":{"type":"string"},"description":"CSS files to load"},"entry_js":{"type":"string","description":"JavaScript entry point filename relative to the bundle root"},"routes":{"type":"array","items":{"$ref":"#/components/schemas/UiRoute"},"description":"Client-side routes the plugin handles"}}},"UiRoute":{"type":"object","description":"A client-side route provided by the plugin UI.","required":["path","title"],"properties":{"path":{"type":"string","description":"Route path pattern (e.g., \"/my-plugin\", \"/my-plugin/:id\")"},"title":{"type":"string","description":"Page title for breadcrumbs"}}},"UndrainNodeResponse":{"type":"object","description":"Response after undraining (reactivating) a node.","required":["id","name","status","message"],"properties":{"id":{"type":"integer","format":"int32"},"message":{"type":"string"},"name":{"type":"string"},"status":{"type":"string"}}},"UnifiedTrace":{"type":"object","description":"Merged cross-project trace result (Phase 2 unified waterfall).\n\nSpans are sorted by `start_time ASC`. At most 20 projects and 10,000\nspans total are included; `truncated` / `truncated_projects` signal when\nthe caps were hit.","required":["trace_id","projects","spans","start_time","end_time","total_duration_ms","span_count","error_count","has_redacted_spans","truncated","truncated_projects"],"properties":{"end_time":{"type":"string","format":"date-time"},"error_count":{"type":"integer","minimum":0},"has_redacted_spans":{"type":"boolean","description":"`true` when at least one project has `cross_project_trace_sharing = false`\nand its spans were therefore excluded from the result set."},"projects":{"type":"array","items":{"$ref":"#/components/schemas/ProjectRef"},"description":"Projects that contributed spans to this result set."},"span_count":{"type":"integer","minimum":0},"spans":{"type":"array","items":{"$ref":"#/components/schemas/AnnotatedSpan"},"description":"Annotated, merged span list sorted by `start_time ASC`."},"start_time":{"type":"string","format":"date-time"},"total_duration_ms":{"type":"number","format":"double","description":"Trace wall-clock duration in milliseconds (`end_time – start_time`)."},"trace_id":{"type":"string"},"truncated":{"type":"boolean","description":"`true` when the 20-project or 10,000-span cap was hit."},"truncated_projects":{"type":"array","items":{"type":"integer","format":"int32"},"description":"project_ids excluded due to truncation (most-recent first_seen dropped first)."}}},"UniqueCountsQuery":{"type":"object","description":"Query parameters for unique counts over time frame","required":["start_date","end_date"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment filter"},"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment filter"},"metric":{"type":"string","description":"Metric to count: \"sessions\" (unique sessions), \"visitors\" (unique visitors),\n\"returning_visitors\" (visitors seen before the range), or \"page_views\"\n(total page views) (default: \"sessions\")"},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"UniqueCountsResponse":{"type":"object","required":["count"],"properties":{"count":{"type":"integer","format":"int64"}}},"UnsupportedFeature":{"type":"object","description":"A feature from the source platform that cannot be migrated","required":["feature","reason"],"properties":{"alternative":{"type":["string","null"],"description":"Suggested alternative in Temps (if any)"},"feature":{"type":"string","description":"Feature name (e.g., \"Edge Middleware\", \"Serverless Functions\", \"Cron Jobs\")"},"reason":{"type":"string","description":"Why it can't be migrated"}}},"UpdateAdminGateRequest":{"type":"object","required":["allowed_ips","allowed_hosts","trust_forwarded_for"],"properties":{"allowed_hosts":{"type":"array","items":{"type":"string"}},"allowed_ips":{"type":"array","items":{"type":"string"}},"trust_forwarded_for":{"type":"boolean"}}},"UpdateAiProviderRequest":{"type":"object","description":"Body for `PATCH /settings/ai-providers/{provider_id}` — updates\nprovider-scoped settings (just the default model for now) without\ntouching the credential. Keeping credentials out of this shape means\nthe UI can auto-save model changes on select, without forcing the user\nto re-paste their token or config file.\nName-spaced schema name avoids an OpenAPI collision with\n`temps-notifications::UpdateProviderRequest`, which has different fields.\nBoth are exposed as `utoipa::ToSchema`; without the override the merged\nOpenAPI doc would silently shadow one struct with the other and break\ngenerated CLI/web clients.","properties":{"default_model":{"type":["string","null"],"description":"New default model id. `None` or an empty string clears the stored\nvalue so the CLI falls back to its own default."},"max_turns_analysis":{"type":["integer","null"],"format":"int32","description":"Default max turns for the autofixer analysis phase (1–200). `0`\nclears the stored value (built-in default applies); omitted/`None`\nleaves the current value unchanged — so a PATCH that only updates\n`default_model` doesn't wipe the turn settings."},"max_turns_feedback":{"type":["integer","null"],"format":"int32","description":"Default max turns for autofixer feedback rounds (1–200). `0` clears;\nomitted leaves unchanged."},"max_turns_fix":{"type":["integer","null"],"format":"int32","description":"Default max turns for the autofixer fix phase (1–200). `0` clears;\nomitted leaves unchanged."}}},"UpdateAiProviderResponse":{"type":"object","required":["provider_id"],"properties":{"default_model":{"type":["string","null"]},"max_turns_analysis":{"type":["integer","null"],"format":"int32"},"max_turns_feedback":{"type":["integer","null"],"format":"int32"},"max_turns_fix":{"type":["integer","null"],"format":"int32"},"provider_id":{"type":"string"}}},"UpdateAlertRuleRequest":{"type":"object","properties":{"cooldown_minutes":{"type":["integer","null"],"format":"int32"},"enabled":{"type":["boolean","null"]},"environment_filter":{"type":["integer","null"],"format":"int32"},"error_level_filter":{"type":["string","null"]},"name":{"type":["string","null"]},"notification_priority":{"type":["string","null"]},"trigger_config":{},"trigger_type":{"type":["string","null"]}}},"UpdateApiKeyRequest":{"type":"object","properties":{"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"is_active":{"type":["boolean","null"]},"name":{"type":["string","null"]},"permissions":{"type":["array","null"],"items":{"type":"string"},"example":["projects:read","deployments:read"]}}},"UpdateAutomaticDeployRequest":{"type":"object","required":["automatic_deploy"],"properties":{"automatic_deploy":{"type":"boolean"}}},"UpdateBackupScheduleRequest":{"type":"object","description":"Request body for updating an existing backup schedule via `PATCH /api/backups/schedules/{id}`.\n\nAll fields are optional; only present fields are updated. Absent fields\nleave the corresponding column unchanged.","properties":{"description":{"type":["string","null"],"description":"New human-readable description. Pass an empty string `\"\"` to clear."},"enabled":{"type":["boolean","null"],"description":"Enable or disable the schedule. Skipped when `None`."},"include_control_plane":{"type":["boolean","null"],"description":"Toggle whether the control-plane backup is produced on every run."},"max_runtime_secs":{"type":["integer","null"],"format":"int64","description":"Per-schedule wall-clock timeout override (seconds).\n\n- `None` (field absent) — leave current value unchanged\n- `Some(None)` (field present, JSON `null`) — clear override; fall back to engine default\n- `Some(Some(n))` — set to `n` seconds (must be >= 60)"},"name":{"type":["string","null"],"description":"New schedule name. Skipped when `None`. Must not be empty if provided."},"retention_period":{"type":["integer","null"],"format":"int32","description":"Days to retain backups produced by this schedule. Must be >= 1."},"schedule_expression":{"type":["string","null"],"description":"New cron expression. When changed, `next_run` is recomputed."},"tags":{"type":["array","null"],"items":{"type":"string"},"description":"Replace the full tag list. Skipped when `None`."},"target_all_services":{"type":["boolean","null"],"description":"Toggle between \"back up every database\" (`true`) and \"back up only\nthe explicit list\" (`false`). When set to `true`, the server clears\nthe explicit membership rows for this schedule."}}},"UpdateBlobRequest":{"type":"object","description":"Request to update Blob service configuration","properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use (e.g., \"rustfs/rustfs:1.0.0-alpha.98\")","example":"rustfs/rustfs:1.0.0-alpha.98"}}},"UpdateBlobResponse":{"type":"object","description":"Response after updating Blob service","required":["success","message","status"],"properties":{"message":{"type":"string","description":"Human-readable message","example":"Blob service updated successfully"},"status":{"$ref":"#/components/schemas/BlobStatusResponse","description":"Current status"},"success":{"type":"boolean","description":"Whether the operation succeeded","example":true}}},"UpdateCloudflareProviderRequest":{"type":"object","required":["config"],"properties":{"config":{"$ref":"#/components/schemas/CloudflareConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateConfigBody":{"type":"object","properties":{"config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ProviderConfig","description":"Typed provider configuration. Setting `config` to `null` clears\nthe stored config back to the accept-everything default. The\nconfig's `provider` tag must match the integration's provider."}]}}},"UpdateCustomDomainRequest":{"type":"object","properties":{"branch":{"type":["string","null"]},"domain":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"redirect_to":{"type":["string","null"]},"service_name":{"type":["string","null"],"description":"Docker Compose service name this domain routes to (empty string clears it)"},"status_code":{"type":["integer","null"],"format":"int32"}}},"UpdateDashboardRequest":{"type":"object","properties":{"layout":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DashboardLayout"}]},"name":{"type":["string","null"]}}},"UpdateDeploymentConfigRequest":{"type":"object","properties":{"automaticDeploy":{"type":["boolean","null"]},"cpuLimit":{"type":["integer","null"],"format":"int32"},"cpuRequest":{"type":["integer","null"],"format":"int32"},"crossArchitectureBuilds":{"type":["boolean","null"],"description":"Build one image per architecture the eligible nodes run. Off by\ndefault; environments inherit this and may override it. Cross-builds\nare emulated on the control plane and substantially slower, so they are\nopted into rather than triggered by cluster topology."},"exposedPort":{"type":["integer","null"],"format":"int32"},"memoryLimit":{"type":["integer","null"],"format":"int32"},"memoryRequest":{"type":["integer","null"],"format":"int32"},"performanceMetricsEnabled":{"type":["boolean","null"]},"replicas":{"type":["integer","null"],"format":"int32"},"security":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SecurityConfig"}]},"sessionRecordingEnabled":{"type":["boolean","null"]}}},"UpdateDeploymentTokenRequest":{"type":"object","properties":{"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"is_active":{"type":["boolean","null"]},"name":{"type":["string","null"]},"permissions":{"type":["array","null"],"items":{"type":"string"},"example":["visitors:enrich","emails:send"]}}},"UpdateDnsProviderRequest":{"type":"object","description":"Request to update a DNS provider","properties":{"credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DnsProviderCredentials","description":"New credentials"}]},"description":{"type":["string","null"],"description":"New description"},"is_active":{"type":["boolean","null"],"description":"Active status"},"name":{"type":["string","null"],"description":"New name"}}},"UpdateEmailProviderRequest":{"type":"object","description":"Request body for `PATCH /email-providers/{id}`.\n\nAll fields are optional. Omit any field to leave it unchanged. The\n`provider_type` is immutable — to switch providers, delete the row and\ncreate a new one. For credentials, supplying any credential variant\nre-encrypts the stored blob; omitting them preserves the existing secret\n(so operators can rename without re-typing passwords).","properties":{"is_active":{"type":["boolean","null"]},"name":{"type":["string","null"],"example":"My AWS SES"},"region":{"type":["string","null"],"example":"us-east-1"},"scaleway_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ScalewayCredentialsRequest"}]},"ses_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SesCredentialsRequest"}]},"smtp_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SmtpCredentialsRequest"}]},"sns_topic_arn":{"type":["string","null"],"description":"Rotate or clear the exact SNS topic allowed for this SES provider.\nOmit to preserve it, send `null` to clear it, or send a string to set it."}}},"UpdateEnvironmentSettingsRequest":{"type":"object","properties":{"anti_affinity":{"type":["boolean","null"],"description":"Anti-affinity: spread replicas across different nodes.\nWhen enabled, the scheduler avoids placing two replicas of the same\nenvironment on the same node. Defaults to `true`."},"attack_mode":{"type":["boolean","null"],"description":"Per-environment CAPTCHA attack-mode override (tri-state):\n- absent → leave the current override unchanged\n- JSON `null` → clear the override (inherit the project-level setting)\n- `true`/`false` → override the project setting for this environment"},"automatic_deploy":{"type":["boolean","null"],"description":"Enable/disable automatic deployments for this environment"},"branch":{"type":["string","null"]},"cpu_limit":{"type":["integer","null"],"format":"int32","description":"Maximum (limit) CPU in microcores. Send JSON `null` to clear → \"no limit\".\nAbsent leaves the current value unchanged."},"cpu_request":{"type":["integer","null"],"format":"int32","description":"Minimum (request) CPU in microcores. Send JSON `null` to clear (no request).\nAbsent leaves the current value unchanged."},"cross_architecture_builds":{"type":["boolean","null"],"description":"Build one image per architecture the eligible nodes run (overrides the\nproject-level setting). Off by default: cross-architecture builds are\nemulated on the control plane and substantially slower, so they are\nopted into per environment rather than triggered by cluster topology."},"exposed_port":{"type":["integer","null"],"format":"int32","description":"Port exposed by the container (overrides project-level port for this environment)\n\nPriority order for port resolution:\n1. Image EXPOSE directive (auto-detected from built image)\n2. This environment-level exposed_port (overrides project setting)\n3. Project-level exposed_port (fallback)\n4. Default: 3000","example":8080},"force_https":{"type":["boolean","null"],"description":"Per-environment HTTP→HTTPS redirect override (tri-state):\n- absent → leave the current override unchanged\n- JSON `null` → clear the override (inherit the proxy default, which\n redirects only when the host has an active TLS certificate)\n- `true` → always redirect plain HTTP to HTTPS for this environment,\n even when no local certificate exists (TLS terminated upstream)\n- `false` → never redirect this environment, even when a certificate does\n exist\n\nRequests under `/.well-known/acme-challenge/` are never redirected\nregardless of this setting, so ACME HTTP-01 validation always completes."},"idle_timeout_seconds":{"type":["integer","null"],"format":"int32","description":"Seconds of inactivity before stopping containers (60-86400). Default: 300."},"memory_limit":{"type":["integer","null"],"format":"int32","description":"Maximum (limit) memory in MB. Send JSON `null` to clear → \"no limit\".\nAbsent leaves the current value unchanged."},"memory_request":{"type":["integer","null"],"format":"int32","description":"Minimum (request) memory in MB. Send JSON `null` to clear (no request).\nAbsent leaves the current value unchanged."},"on_demand":{"type":["boolean","null"],"description":"Enable on-demand mode (scale-to-zero). Containers are stopped after\nidle_timeout_seconds of no traffic and started on the next request."},"password":{"type":["string","null"],"description":"Set a password to protect this environment. The proxy will show an HTML\npassword form before allowing access. The password is bcrypt-hashed\nserver-side and never stored in plaintext.\nSend an empty string to remove password protection."},"performance_metrics_enabled":{"type":["boolean","null"],"description":"Enable/disable performance metrics collection"},"protected":{"type":["boolean","null"],"description":"When true, git pushes do NOT auto-deploy to this environment.\nDeployments must be promoted from another environment."},"replicas":{"type":["integer","null"],"format":"int32"},"security":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SecurityConfig","description":"Security configuration for this environment (overrides project-level settings)"}]},"session_recording_enabled":{"type":["boolean","null"],"description":"Enable/disable session recording"},"target_labels":{"description":"Label selector for node-based scheduling (overrides project-level setting).\nSame key with array value -> OR, different keys -> AND.\nExample: `{\"region\": [\"us\", \"asia\"], \"gpu\": \"true\"}`"},"target_nodes":{"type":["array","null"],"items":{"type":"integer","format":"int32"},"description":"Optional list of node IDs to deploy to (overrides project-level setting)"},"wake_timeout_seconds":{"type":["integer","null"],"format":"int32","description":"Max seconds to wait for containers to start on wake (5-120). Default: 30."}}},"UpdateEnvironmentSubdomainRequest":{"type":"object","description":"Request to rename an environment's auto-managed subdomain.\n\nThe subdomain is the host label inserted in front of the platform's\npreview domain (e.g. `myapp` in `myapp.preview.temps.sh`). Renaming\nreplaces the previous subdomain entirely — the old hostname stops\nresolving immediately after this request succeeds.","required":["subdomain"],"properties":{"subdomain":{"type":"string","description":"New subdomain label. Must be a DNS-safe slug (lowercase letters,\ndigits, and hyphens, 1-63 characters). The value is slugified\nserver-side, so casing and disallowed characters are normalized.","example":"myapp"}}},"UpdateEnvironmentVariableRequest":{"type":"object","required":["key","environment_ids"],"properties":{"environment_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"include_in_preview":{"type":"boolean"},"is_secret":{"type":["boolean","null"],"description":"Optional secret-flag transition.\n- `Some(true)` promotes a regular var to a secret.\n- `Some(false)` is rejected if the row is already secret (one-way flag).\n- `None` (omitted) leaves the flag unchanged."},"key":{"type":"string"},"value":{"type":["string","null"],"description":"New plaintext value. `None` (omitted) keeps the existing ciphertext,\nwhich is the only way to edit a secret env var without re-typing its\nvalue (e.g. changing which environments it applies to)."}}},"UpdateErrorGroupRequest":{"type":"object","required":["status"],"properties":{"assigned_to":{"type":["string","null"]},"status":{"type":"string"}}},"UpdateExternalServiceRequest":{"type":"object","required":["parameters"],"properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use for the service (e.g., \"gotempsh/postgres-walg:18-bookworm\", \"timescale/timescaledb-ha:pg18\")\nWhen provided, the service will be recreated with the new image while preserving data"},"parameters":{"type":"object","additionalProperties":{},"propertyNames":{"type":"string"}}}},"UpdateFlagRequest":{"type":"object","properties":{"client_visible":{"type":["boolean","null"]},"default_value":{"description":"Must match the flag's existing `value_type`."},"description":{"type":["string","null"],"description":"Tri-state: absent leaves it, `null` clears it, a string sets it."}}},"UpdateGitSettingsRequest":{"type":"object","required":["main_branch","repo_owner","repo_name","directory"],"properties":{"directory":{"type":"string"},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"git_url":{"type":["string","null"],"description":"Git clone URL for public repositories"},"is_public_repo":{"type":["boolean","null"],"description":"Whether this is a public repository (no git provider connection needed)"},"main_branch":{"type":"string"},"preset":{"type":["string","null"]},"preset_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PresetConfigSchema","description":"Preset-specific configuration (e.g., Dockerfile path for Docker preset)\n\nExample for Dockerfile preset:\n```json\n{\n \"dockerfilePath\": \"docker/Dockerfile\",\n \"buildContext\": \"./api\"\n}\n```"}]},"repo_name":{"type":"string"},"repo_owner":{"type":"string"}}},"UpdateIncidentStatusRequest":{"type":"object","required":["status","message"],"properties":{"message":{"type":"string"},"status":{"type":"string"}}},"UpdateIpAccessControlRequest":{"type":"object","description":"Request to update an IP access control rule","properties":{"action":{"type":["string","null"],"description":"Optional new action"},"ip_address":{"type":["string","null"],"description":"Optional new IP address"},"reason":{"type":["string","null"],"description":"Optional new reason"}}},"UpdateKvRequest":{"type":"object","description":"Request to update KV service configuration","properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use (e.g., \"gotempsh/redis-walg:8-bookworm\")","example":"gotempsh/redis-walg:8-bookworm"}}},"UpdateKvResponse":{"type":"object","description":"Response after updating KV service","required":["success","message","status"],"properties":{"message":{"type":"string","description":"Status message","example":"KV service updated successfully"},"status":{"$ref":"#/components/schemas/KvStatusResponse","description":"Current service status"},"success":{"type":"boolean","description":"Whether the operation succeeded"}}},"UpdateManagedDomainApiRequest":{"type":"object","description":"Request to update a managed domain's settings.","properties":{"auto_manage":{"type":["boolean","null"],"description":"Toggle automatic DNS management for this domain."},"generated_hostname_mode":{"type":["string","null"],"description":"`\"standard\"` or `\"flat\"`. Persisted as-is; switching to `\"flat\"` does not\nrecompute existing hostnames — use the apply endpoint for that."},"sync_generated_records":{"type":["boolean","null"],"description":"Toggle DNS record sync for this domain."}}},"UpdateMcpRequest":{"type":"object","required":["config"],"properties":{"config":{"type":"object"},"description":{"type":["string","null"]},"name":{"type":["string","null"]}}},"UpdateMemberRoleRequest":{"type":"object","description":"The new fixed role for an existing membership.","required":["role"],"properties":{"role":{"$ref":"#/components/schemas/TeamRole"}}},"UpdateMetricAlertRequest":{"type":"object","properties":{"aggregation":{"type":["string","null"]},"detection_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DetectionConfig","description":"Replaces the detector wholesale when present (absent = leave unchanged)."}]},"dynamic_alerts":{"type":["boolean","null"],"description":"Toggles per-series (\"dynamic\") alerting (absent = leave unchanged)."},"enabled":{"type":["boolean","null"]},"for_duration_secs":{"type":["integer","null"],"format":"int32"},"group_by":{"type":["array","null"],"items":{"type":"string"},"description":"Replaces the group_by keys wholesale when present (absent = leave unchanged)."},"grouped_notification_threshold":{"type":["integer","null"],"format":"int32","description":"Updates the notification-grouping threshold (absent = leave unchanged)."},"label_filters":{"type":["array","null"],"items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"Replaces the label filters wholesale when present (absent = leave unchanged)."},"max_series":{"type":["integer","null"],"format":"int32","description":"Updates the dynamic-alerting cardinality cap (absent = leave unchanged)."},"metric_name":{"type":["string","null"]},"name":{"type":["string","null"]},"severity":{"type":["string","null"]},"window_secs":{"type":["integer","null"],"format":"int32"}}},"UpdateNotificationEmailProviderRequest":{"type":"object","required":["config"],"properties":{"config":{"$ref":"#/components/schemas/EmailConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateOidcProviderRequest":{"type":"object","properties":{"client_id":{"type":["string","null"]},"client_secret":{"type":["string","null"]},"default_role":{"type":["string","null"]},"enabled":{"type":["boolean","null"]},"group_claim":{"type":["string","null"]},"issuer_url":{"type":["string","null"]},"jit_provisioning":{"type":["boolean","null"]},"name":{"type":["string","null"]},"role_claim":{"type":["string","null"]},"scopes":{"type":["string","null"]},"template":{"type":["string","null"]},"trust_idp_email":{"type":["boolean","null"]}}},"UpdatePreferencesRequest":{"type":"object","required":["preferences"],"properties":{"preferences":{"$ref":"#/components/schemas/NotificationPreferencesResponse"}}},"UpdateProjectSecretRequest":{"type":"object","description":"Request to update a project secret. The `value` field is optional — omit it\nto rotate only the environment scoping / preview flag without touching the\nciphertext.","properties":{"environment_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"include_in_preview":{"type":"boolean"},"value":{"type":["string","null"],"description":"New plaintext value, <= 1 MiB. Omit to keep the existing value."}}},"UpdateProjectSettingsRequest":{"type":"object","properties":{"ai_alert_summaries_enabled":{"type":["boolean","null"],"description":"Opt in to AI summarization of metric alert notifications (ADR-021)."},"ai_debug_chat_enabled":{"type":["boolean","null"],"description":"Opt in to AI debugging chat, e.g. on deployment failures (ADR-023)."},"ai_write_actions_enabled":{"type":["boolean","null"],"description":"Opt in to AI propose-then-confirm write capability."},"attack_mode":{"type":["boolean","null"],"description":"Enable/disable attack mode (CAPTCHA protection) for all project environments"},"cross_project_trace_sharing":{"type":["boolean","null"],"description":"ADR-027 Phase 3 opt-out: set to false to suppress this project's traces\nfrom appearing in cross-project discovery results. Default true (consistent\nwith the OSS global-observability model). Omit to leave unchanged."},"directory":{"type":["string","null"]},"enable_preview_environments":{"type":["boolean","null"],"description":"Enable automatic preview environment creation for each branch"},"error_source_context_enabled":{"type":["boolean","null"],"description":"Opt in to native error-tracking source context (source-file upload +\nsource code shown in stack traces)."},"error_source_root":{"type":["string","null"],"description":"Set the auto-capture source root (relative to the checkout). Send an\nempty string to clear it back to the build-context default. Omit to\nleave unchanged."},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"main_branch":{"type":["string","null"]},"preset":{"type":["string","null"]},"preset_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PresetConfigSchema","description":"Preset-specific configuration (e.g., Dockerfile path for Docker preset)\n\nExample for Dockerfile preset:\n```json\n{\n \"dockerfilePath\": \"docker/Dockerfile\",\n \"buildContext\": \"./api\"\n}\n```"}]},"preview_envs_idle_timeout_seconds":{"type":["integer","null"],"format":"int32","description":"Idle timeout (seconds, 60..=86400) for on-demand preview environments."},"preview_envs_on_demand":{"type":["boolean","null"],"description":"When true, newly-created preview environments default to on-demand mode."},"preview_envs_wake_timeout_seconds":{"type":["integer","null"],"format":"int32","description":"Wake timeout (seconds, 5..=120) for on-demand preview environments."},"repo_name":{"type":["string","null"]},"repo_owner":{"type":["string","null"]},"slug":{"type":["string","null"]}}},"UpdateProviderCredentialsRequest":{"type":"object","description":"Partial-update payload for provider credentials. Every field is optional;\nonly the fields the user re-enters are applied. The server validates that\nthe fields supplied make sense for the provider's current auth_method\n(e.g. `app_id` + `private_key` only apply to GitHub Apps).","properties":{"app_id":{"type":["string","null"],"description":"Application ID (GitHub App integer as string; GitLab App string)."},"app_secret":{"type":["string","null"],"description":"GitLab App secret (not used by GitHub App — use `client_secret`)."},"client_id":{"type":["string","null"],"description":"OAuth client ID (GitLab OAuth, GitHub App)."},"client_secret":{"type":["string","null"],"description":"OAuth client secret (GitLab OAuth, GitHub App)."},"private_key":{"type":["string","null"],"description":"GitHub App private key (PEM)."},"redirect_uri":{"type":["string","null"],"description":"OAuth redirect URI (GitLab OAuth / GitLab App)."},"token":{"type":["string","null"],"description":"PAT for PAT-type providers."},"webhook_secret":{"type":["string","null"],"description":"GitHub App webhook secret."}}},"UpdateProviderKeyRequest":{"type":"object","properties":{"api_key":{"type":["string","null"]},"base_url":{"type":["string","null"],"description":"Double-Option: absent = leave unchanged, present-null = clear (revert to\nthe provider's default endpoint), present-value = set."},"default_model":{"type":["string","null"],"description":"Double-Option: absent = leave unchanged, present-null = clear the pinned\nmodel (revert to the per-provider default), present-value = set."},"display_name":{"type":["string","null"]},"is_active":{"type":["boolean","null"]}}},"UpdateProviderRequest":{"type":"object","properties":{"config":{},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateRouteRequest":{"type":"object","required":["host","port","enabled"],"properties":{"enabled":{"type":"boolean"},"host":{"type":"string"},"port":{"type":"integer","format":"int32"},"route_type":{"type":["string","null"],"description":"Route type: \"http\" (default) matches on HTTP Host header,\n\"tls\" matches on TLS SNI hostname for TCP passthrough"}}},"UpdateS3SourceRequest":{"type":"object","properties":{"access_key_id":{"type":["string","null"],"description":"Optional new access key ID","example":"AKIAXXXXXXXXXXXXXXXX"},"bucket_name":{"type":["string","null"],"description":"Optional new bucket name"},"bucket_path":{"type":["string","null"],"description":"Optional new bucket path"},"endpoint":{"type":["string","null"],"description":"Optional new endpoint URL for S3-compatible services","example":"http://minio.example.com:9000"},"force_path_style":{"type":["boolean","null"],"description":"Optional new path-style addressing setting","example":true},"name":{"type":["string","null"],"description":"Optional new name for the source"},"region":{"type":["string","null"],"description":"Optional new region"},"secret_key":{"type":["string","null"],"description":"Optional new secret key"}}},"UpdateSecretBody":{"type":"object","required":["signing_secret"],"properties":{"signing_secret":{"type":"string","description":"New signing secret from the provider's dashboard. Encrypted at\nrest; never returned in any API response."}}},"UpdateSelfRequest":{"type":"object","properties":{"email":{"type":["string","null"],"example":"john.doe@example.com"},"name":{"type":["string","null"],"example":"John Doe"}}},"UpdateSessionDurationRequest":{"type":"object","required":["duration"],"properties":{"duration":{"type":"integer","format":"int32"}}},"UpdateSessionDurationResponse":{"type":"object","required":["message"],"properties":{"message":{"type":"string"}}},"UpdateSkillRequest":{"type":"object","properties":{"content":{"type":["string","null"]},"description":{"type":["string","null"]},"name":{"type":["string","null"]}}},"UpdateSlackProviderRequest":{"type":"object","required":["config"],"properties":{"config":{"$ref":"#/components/schemas/SlackConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateSpeedMetricsPayload":{"type":"object","description":"Update speed metrics payload for late-loading metrics","properties":{"cls":{"type":["number","null"],"format":"float","description":"Cumulative Layout Shift (score)"},"inp":{"type":["number","null"],"format":"float","description":"Interaction to Next Paint (milliseconds)"}}},"UpdateStatusResponse":{"type":"object","description":"Result of the background release-update check, driving the web console's\nupgrade banner. All optional fields are set together iff\n`update_available` is true.","required":["update_available","docs_url"],"properties":{"channel":{"type":["string","null"],"description":"Channel the install tracks: `stable` or `beta`."},"checked_at":{"type":["string","null"],"description":"When the check that found the update ran (ISO 8601, UTC)."},"current_version":{"type":["string","null"],"description":"Version tag of the running binary, e.g. `v0.1.0-beta.45`."},"docs_url":{"type":"string","description":"Docs page with upgrade instructions. Always present so the UI links\nthe same page regardless of update state."},"latest_version":{"type":["string","null"],"description":"Newest published tag on this install's channel."},"release_url":{"type":["string","null"],"description":"Release-notes page (GitHub release) for the newer version."},"update_available":{"type":"boolean","description":"True when a newer release than the running binary has been published\non this install's channel."}}},"UpdateTeamRequest":{"type":"object","properties":{"description":{"type":["string","null"]},"name":{"type":["string","null"]}}},"UpdateTokenRequest":{"type":"object","required":["access_token"],"properties":{"access_token":{"type":"string"},"refresh_token":{"type":["string","null"]}}},"UpdateTokenResponse":{"type":"object","required":["connection_id","message","is_active"],"properties":{"connection_id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"message":{"type":"string"}}},"UpdateUserRequest":{"type":"object","properties":{"email":{"type":["string","null"],"example":"john.doe@example.com"},"name":{"type":["string","null"],"example":"John Doe"}}},"UpdateWebhookProviderRequest":{"type":"object","required":["config"],"properties":{"config":{"$ref":"#/components/schemas/WebhookConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateWebhookRequestBody":{"type":"object","properties":{"enabled":{"type":["boolean","null"],"description":"Whether the webhook is enabled"},"events":{"type":["array","null"],"items":{"type":"string"},"description":"Event types to subscribe to"},"secret":{"type":["string","null"],"description":"Secret for HMAC signature verification"},"url":{"type":["string","null"],"description":"Target URL for webhook delivery"}}},"UpgradeExternalServiceRequest":{"type":"object","required":["docker_image"],"properties":{"docker_image":{"type":"string","description":"Docker image to upgrade to (e.g., \"gotempsh/postgres-walg:18-bookworm\")\nThis will trigger pg_upgrade for PostgreSQL or equivalent upgrade procedures for other services","example":"gotempsh/postgres-walg:18-bookworm"}}},"UpgradeRequest":{"type":"object","required":["image"],"properties":{"image":{"type":"string","description":"Image reference to pull and run (e.g.\n`ghcr.io/gotempsh/temps-preview-gateway:latest`). Empty resets to default."}}},"UpsertAgentRequest":{"type":"object","properties":{"ai_model":{"type":["string","null"],"description":"Preferred model identifier for the CLI. `Some(\"\")` clears the stored value."},"ai_provider":{"type":["string","null"]},"ai_provider_key_id":{"type":["integer","null"],"format":"int32"},"api_key":{"type":["string","null"],"description":"Plain-text API key — will be encrypted before storage"},"branch_prefix":{"type":["string","null"]},"config_repo_branch":{"type":["string","null"],"description":"Branch of the config repo to use (default: \"main\")."},"config_repo_url":{"type":["string","null"],"description":"Private config repo containing .claude/ directory (skills, MCP, plugins)."},"cooldown_minutes":{"type":["integer","null"],"format":"int32"},"daily_budget_cents":{"type":["integer","null"],"format":"int32"},"deliverable":{"type":["string","null"]},"description":{"type":["string","null"]},"enabled":{"type":["boolean","null"]},"max_turns":{"type":["integer","null"],"format":"int32"},"mcp_servers_config":{"description":"MCP servers config (Claude Code settings.json mcpServers format).\nCredential-bearing legacy inline objects are write-only: normal reads\nmask them, and updates must omit this field to preserve existing values."},"name":{"type":["string","null"]},"prompt":{"type":["string","null"]},"sandbox_enabled":{"type":["boolean","null"]},"skills_config":{"description":"Skills config as JSON array."},"slug":{"type":["string","null"]},"timeout_seconds":{"type":["integer","null"],"format":"int32"},"tools_config":{"description":"Tools config as JSON array. Custom-tool webhook URLs and headers are\nwrite-only; omit this field on update to preserve them."},"trigger_config":{"description":"Trigger configuration JSON: { \"error\": { \"new_issue\": true, \"regression\": true }, \"manual\": true }"}}},"UpsertSecretRequest":{"type":"object","required":["name","value"],"properties":{"description":{"type":["string","null"]},"mount_path":{"type":["string","null"],"description":"Required for \"file\" type secrets — absolute path inside the sandbox"},"name":{"type":"string"},"secret_type":{"type":"string","description":"\"env\" (environment variable) or \"file\" (written to mount_path)"},"value":{"type":"string"}}},"UptimeDataPoint":{"type":"object","required":["timestamp","status"],"properties":{"error_message":{"type":["string","null"]},"response_time_ms":{"type":["integer","null"],"format":"int32"},"status":{"type":"string"},"timestamp":{"type":"string","format":"date-time"}}},"UptimeHistoryResponse":{"type":"object","required":["monitor_id","uptime_data"],"properties":{"monitor_id":{"type":"integer","format":"int32"},"uptime_data":{"type":"array","items":{"$ref":"#/components/schemas/UptimeDataPoint"}}}},"UsageFilter":{"type":"object","description":"Filters for querying AI usage data.\n\nCost bounds are expressed in microcents (the unit stored in\n`estimated_cost_microcents`). At most one of `gte`/`gt` and one of\n`lte`/`lt` is meaningful per query; if both are set the stricter wins\nnaturally because they are ANDead together.","properties":{"conversation_id":{"type":["string","null"]},"cost_gt":{"type":["integer","null"],"format":"int64","description":"Cost strictly greater-than, in microcents."},"cost_gte":{"type":["integer","null"],"format":"int64","description":"Cost greater-than-or-equal, in microcents."},"cost_lt":{"type":["integer","null"],"format":"int64","description":"Cost strictly less-than, in microcents."},"cost_lte":{"type":["integer","null"],"format":"int64","description":"Cost less-than-or-equal, in microcents."},"model":{"type":["string","null"]},"provider":{"type":["string","null"]},"status":{"type":["integer","null"],"format":"int32","description":"Filter by HTTP status code (exact match)."},"tags":{"type":["string","null"],"description":"Comma-separated tags to filter by (AND logic)."},"tokens_gt":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) strictly greater-than."},"tokens_gte":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) greater-than-or-equal."},"tokens_lt":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) strictly less-than."},"tokens_lte":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) less-than-or-equal."},"user_id":{"type":["integer","null"],"format":"int32"}}},"UsageInfo":{"type":"object","required":["prompt_tokens","completion_tokens","total_tokens"],"properties":{"completion_tokens":{"type":"integer","format":"int64"},"prompt_tokens":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"UsageLogEntry":{"type":"object","required":["id","timestamp","provider","model","input_tokens","output_tokens","latency_ms","estimated_cost_microcents","status","is_streaming","is_byok","tags"],"properties":{"conversation_id":{"type":["string","null"]},"estimated_cost_microcents":{"type":"integer","format":"int64"},"id":{"type":"integer","format":"int64"},"input_tokens":{"type":"integer","format":"int64"},"is_byok":{"type":"boolean"},"is_streaming":{"type":"boolean"},"latency_ms":{"type":"integer","format":"int32"},"model":{"type":"string"},"output_tokens":{"type":"integer","format":"int64"},"provider":{"type":"string"},"request_id":{"type":["string","null"]},"status":{"type":"integer","format":"int32"},"tags":{"type":"array","items":{"type":"string"}},"timestamp":{"type":"string"},"trace_id":{"type":["string","null"]}}},"UsageLogPage":{"type":"object","description":"A page of recent usage log entries plus the total count for pagination.","required":["entries","total"],"properties":{"entries":{"type":"array","items":{"$ref":"#/components/schemas/UsageLogEntry"},"description":"The usage log entries for the requested page."},"total":{"type":"integer","format":"int64","description":"Total number of entries matching the filter (across all pages)."}}},"UsageQueryParams":{"type":"object","properties":{"conversation_id":{"type":["string","null"],"description":"Filter by conversation ID"},"from":{"type":["string","null"],"description":"ISO 8601 start time (defaults to 24h ago)"},"model":{"type":["string","null"],"description":"Filter by model name"},"provider":{"type":["string","null"],"description":"Filter by provider name"},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"to":{"type":["string","null"],"description":"ISO 8601 end time (defaults to now)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"UsageSource":{"type":"string","description":"How the \"actual usage\" numbers were obtained","enum":["metrics-api","requests-only","unavailable"]},"UsageSummary":{"type":"object","required":["total_requests","total_input_tokens","total_output_tokens","total_tokens","avg_latency_ms","total_cost_microcents","error_count","streaming_count","byok_count"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"byok_count":{"type":"integer","format":"int64"},"error_count":{"type":"integer","format":"int64"},"streaming_count":{"type":"integer","format":"int64"},"total_cost_microcents":{"type":"integer","format":"int64"},"total_input_tokens":{"type":"integer","format":"int64"},"total_output_tokens":{"type":"integer","format":"int64"},"total_requests":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"UserResponse":{"type":"object","required":["id","username","name","avatar_url","mfa_enabled","role"],"properties":{"avatar_url":{"type":"string"},"email":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"mfa_enabled":{"type":"boolean"},"name":{"type":"string"},"role":{"type":"string","description":"User's role (e.g., \"admin\", \"user\", \"demo\")"},"username":{"type":"string"}}},"ValidateEmailRequest":{"type":"object","description":"Request body for validating an email address","required":["email"],"properties":{"email":{"type":"string","description":"Email address to validate","example":"someone@gmail.com"}},"additionalProperties":false},"ValidateEmailResponse":{"type":"object","description":"Complete email validation response","required":["email","is_reachable","syntax","mx","misc","smtp"],"properties":{"email":{"type":"string","description":"The email address that was validated","example":"someone@gmail.com"},"is_reachable":{"$ref":"#/components/schemas/ReachabilityStatus","description":"Overall reachability status: safe, risky, invalid, or unknown"},"misc":{"$ref":"#/components/schemas/MiscResult","description":"Miscellaneous validation result"},"mx":{"$ref":"#/components/schemas/MxResult","description":"MX record validation result"},"smtp":{"$ref":"#/components/schemas/SmtpResult","description":"SMTP validation result"},"syntax":{"$ref":"#/components/schemas/SyntaxResult","description":"Syntax validation result"}}},"ValidationLevel":{"type":"string","description":"Validation severity level","enum":["info","warning","error","critical"]},"ValidationReport":{"type":"object","description":"Complete validation report","required":["results","overall_status","summary"],"properties":{"overall_status":{"$ref":"#/components/schemas/ValidationStatus","description":"Overall status"},"results":{"type":"array","items":{"$ref":"#/components/schemas/ValidationResult"},"description":"All validation results"},"summary":{"$ref":"#/components/schemas/ValidationSummary","description":"Summary statistics"}}},"ValidationResponse":{"type":"object","required":["connection_id","is_valid","message"],"properties":{"connection_id":{"type":"integer","format":"int32"},"is_valid":{"type":"boolean"},"message":{"type":"string"}}},"ValidationResult":{"type":"object","description":"Result of a validation check","required":["rule_id","rule_name","level","passed","message","affected_resources"],"properties":{"affected_resources":{"type":"array","items":{"type":"string"},"description":"Affected resources/fields"},"level":{"$ref":"#/components/schemas/ValidationLevel","description":"Validation level"},"message":{"type":"string","description":"Message describing the result"},"passed":{"type":"boolean","description":"Whether the validation passed"},"remediation":{"type":["string","null"],"description":"Suggested remediation (if failed)"},"rule_id":{"type":"string","description":"Rule that was checked"},"rule_name":{"type":"string","description":"Human-readable rule name"}}},"ValidationStatus":{"type":"string","description":"Overall validation status","enum":["passed","passed-with-warnings","failed-with-warnings","failed"]},"ValidationSummary":{"type":"object","description":"Validation summary statistics","required":["total_count","passed_count","failed_count","info_count","warning_count","error_count","critical_count"],"properties":{"critical_count":{"type":"integer","description":"Critical-level results","minimum":0},"error_count":{"type":"integer","description":"Error-level results","minimum":0},"failed_count":{"type":"integer","description":"Validations that failed","minimum":0},"info_count":{"type":"integer","description":"Info-level results","minimum":0},"passed_count":{"type":"integer","description":"Validations that passed","minimum":0},"total_count":{"type":"integer","description":"Total validations run","minimum":0},"warning_count":{"type":"integer","description":"Warning-level results","minimum":0}}},"VerifyMfaRequest":{"type":"object","required":["code"],"properties":{"code":{"type":"string"}}},"VerifyStepUpRequest":{"type":"object","required":["code"],"properties":{"code":{"type":"string","description":"Current TOTP value or an unused recovery code."}}},"ViewItem":{"type":"object","required":["label","value"],"properties":{"label":{"type":"string","format":"date-time"},"value":{"type":"integer","format":"int64"}}},"ViewsOverTime":{"type":"object","required":["items","metric","present_index"],"properties":{"comparison_labels":{"type":["array","null"],"items":{"type":"string"}},"comparison_plot":{"type":["array","null"],"items":{"type":"integer","format":"int64"}},"full_intervals":{"type":["array","null"],"items":{"type":"string"}},"items":{"type":"array","items":{"$ref":"#/components/schemas/ViewItem"}},"metric":{"type":"string"},"present_index":{"type":"integer","minimum":0}}},"ViewsOverTimeQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"VisitorDetails":{"type":"object","required":["id","visitor_id","project_id","environment_id","first_seen","last_seen","is_crawler"],"properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"crawler_name":{"type":["string","null"]},"custom_data":{},"environment_id":{"type":"integer","format":"int32"},"first_channel":{"type":["string","null"],"description":"Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")"},"first_referrer":{"type":["string","null"],"description":"Full referrer URL from the visitor's first session"},"first_referrer_hostname":{"type":["string","null"],"description":"Hostname extracted from first_referrer"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":["string","null"]},"ip_address_id":{"type":["integer","null"],"format":"int32"},"is_crawler":{"type":"boolean"},"is_eu":{"type":["boolean","null"]},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"latitude":{"type":["number","null"],"format":"double"},"longitude":{"type":["number","null"],"format":"double"},"project_id":{"type":"integer","format":"int32"},"region":{"type":["string","null"]},"timezone":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":"string"}}},"VisitorFacetValue":{"type":"object","description":"A single facet value with its visitor count. Used to populate filter\ndropdowns on the visitors page (e.g. \"Germany — 1,234 visitors\").","required":["value","count"],"properties":{"code":{"type":["string","null"],"description":"Optional secondary code for the value. Currently only populated for\nthe `country` facet, where it carries the 2-letter ISO country code\nso the UI can render a flag without re-mapping."},"count":{"type":"integer","format":"int64","description":"Distinct visitor count matching this value in the current segment."},"value":{"type":"string","description":"The dimension value (e.g. \"United States\", \"Chrome\", \"google.com\").\n`None` is encoded as the literal string \"Direct\" for referrer and as\nthe empty string for the rest."}}},"VisitorFacets":{"type":"object","description":"All filter dropdown contents in one response. Each list is the top N\nvalues for that dimension within the current date range and segment\n(excluding the dimension being queried so the dropdown still shows\nalternatives when a value is already selected).","required":["country","region","city","channel","referrer"],"properties":{"channel":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}},"city":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}},"country":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}},"referrer":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}},"region":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}}}},"VisitorFacetsQuery":{"allOf":[{"$ref":"#/components/schemas/VisitorSegmentFilters"},{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"has_activity_only":{"type":["boolean","null"]},"include_crawlers":{"type":["boolean","null"]},"per_facet_limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of values returned per dimension (default: 50, max: 200)."},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}}],"description":"Query parameters for the visitor-facets endpoint. Mirrors the shape of\n`VisitorsListQuery` so the same segment filters apply — facet counts are\nalways computed against the *currently filtered* visitor pool, minus the\ndimension being aggregated."},"VisitorInfo":{"type":"object","required":["id","visitor_id","project_id","environment_id","first_seen","last_seen","is_crawler"],"properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"crawler_name":{"type":["string","null"]},"current_page":{"type":["string","null"],"description":"Most recent page path visited by this visitor"},"custom_data":{},"environment_id":{"type":"integer","format":"int32"},"first_channel":{"type":["string","null"],"description":"Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")"},"first_referrer":{"type":["string","null"],"description":"Full referrer URL from the visitor's first session"},"first_referrer_hostname":{"type":["string","null"],"description":"Hostname extracted from first_referrer"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":["string","null"]},"ip_address_id":{"type":["integer","null"],"format":"int32"},"is_crawler":{"type":"boolean"},"is_eu":{"type":["boolean","null"]},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"latitude":{"type":["number","null"],"format":"double"},"longitude":{"type":["number","null"],"format":"double"},"project_id":{"type":"integer","format":"int32"},"region":{"type":["string","null"]},"timezone":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":"string"}}},"VisitorJourneyQuery":{"type":"object","required":["project_id"],"properties":{"limit_sessions":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"VisitorJourneyResponse":{"type":"object","description":"Complete visitor journey response","required":["visitor_id","total_sessions","total_events","sessions"],"properties":{"sessions":{"type":"array","items":{"$ref":"#/components/schemas/JourneySession"},"description":"Sessions with their events, ordered newest first"},"total_events":{"type":"integer","format":"int64","description":"Total number of events across all sessions"},"total_sessions":{"type":"integer","format":"int64","description":"Total number of sessions"},"visitor_id":{"type":"integer","format":"int32","description":"Visitor internal ID"}}},"VisitorLocationsQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"granularity":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/LocationGranularity"}]},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"VisitorRecord":{"type":"object","required":["id","visitor_id","project_id","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"custom_data":{},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"visitor_id":{"type":"string"}}},"VisitorSegmentFilters":{"type":"object","description":"Optional segment filters for [`VisitorsListQuery`]. Each filter narrows the\nresult set to visitors who match the given dimension value within the date\nrange. All filters resolve against `visitor` / `ip_geolocations` — by\ndesign we never touch the events hypertable here so filtering stays fast\nregardless of event volume.","properties":{"filter_channel":{"type":["string","null"],"description":"First-touch marketing channel (matches `visitor.first_channel`)"},"filter_city":{"type":["string","null"],"description":"Geolocation city (matches `ip_geolocations.city`)"},"filter_country":{"type":["string","null"],"description":"Geolocation country (matches `ip_geolocations.country`)"},"filter_referrer":{"type":["string","null"],"description":"First-touch referrer hostname (matches `visitor.first_referrer_hostname`)"},"filter_region":{"type":["string","null"],"description":"Geolocation region (matches `ip_geolocations.region`)"}}},"VisitorSessionsQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"VisitorSessionsResponse":{"type":"object","required":["visitor_id","sessions","total_sessions"],"properties":{"sessions":{"type":"array","items":{"$ref":"#/components/schemas/SessionSummary"}},"total_sessions":{"type":"integer","format":"int64"},"visitor_id":{"type":"string"}}},"VisitorStats":{"type":"object","required":["visitor_id","first_seen","last_seen","total_sessions","total_page_views","total_events","average_session_duration","bounce_rate","engagement_rate","top_pages","top_referrers","devices_used","locations"],"properties":{"average_session_duration":{"type":"number","format":"double"},"bounce_rate":{"type":"number","format":"double"},"devices_used":{"type":"array","items":{"type":"string"}},"engagement_rate":{"type":"number","format":"double"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"locations":{"type":"array","items":{"$ref":"#/components/schemas/LocationInfo"}},"top_pages":{"type":"array","items":{"$ref":"#/components/schemas/PageVisit"}},"top_referrers":{"type":"array","items":{"type":"string"}},"total_events":{"type":"integer","format":"int64"},"total_page_views":{"type":"integer","format":"int64"},"total_sessions":{"type":"integer","format":"int64"},"visitor_id":{"type":"integer","format":"int32"}}},"VisitorWithGeolocation":{"type":"object","required":["id","visitor_id","project_id","environment_id","first_seen","last_seen","is_crawler"],"properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"crawler_name":{"type":["string","null"]},"custom_data":{},"environment_id":{"type":"integer","format":"int32"},"first_channel":{"type":["string","null"],"description":"Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")"},"first_referrer":{"type":["string","null"],"description":"Full referrer URL from the visitor's first session"},"first_referrer_hostname":{"type":["string","null"],"description":"Hostname extracted from first_referrer"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":["string","null"]},"is_crawler":{"type":"boolean"},"is_eu":{"type":["boolean","null"]},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"latitude":{"type":["number","null"],"format":"double"},"longitude":{"type":["number","null"],"format":"double"},"project_id":{"type":"integer","format":"int32"},"region":{"type":["string","null"]},"timezone":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":"string"}}},"VisitorsListQuery":{"allOf":[{"$ref":"#/components/schemas/VisitorSegmentFilters"},{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"has_activity_only":{"type":["boolean","null"],"description":"Filter to only include visitors with recorded activity (events/sessions).\nWhen true, excludes \"ghost\" visitors that have no events."},"include_crawlers":{"type":["boolean","null"]},"limit":{"type":["integer","null"],"format":"int32"},"offset":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}}]},"VisitorsResponse":{"type":"object","required":["visitors","total_count","filtered_count"],"properties":{"filtered_count":{"type":"integer","format":"int64"},"total_count":{"type":"integer","format":"int64"},"visitors":{"type":"array","items":{"$ref":"#/components/schemas/VisitorInfo"}}}},"VolumeMount":{"type":"object","description":"Volume mount in deployment","required":["source","destination","read_only","type"],"properties":{"destination":{"type":"string","description":"Destination path in container"},"read_only":{"type":"boolean","description":"Read-only flag"},"source":{"type":"string","description":"Source (volume name or path)"},"type":{"$ref":"#/components/schemas/VolumeType","description":"Volume type"}}},"VolumeType":{"type":"string","description":"Volume type","enum":["bind","volume","tmpfs"]},"VulnerabilityResponse":{"type":"object","required":["id","scan_id","vulnerability_id","package_name","installed_version","severity","title","created_at"],"properties":{"class":{"type":["string","null"],"example":"os-pkgs"},"created_at":{"type":"string","example":"2025-12-08T12:15:47.609192Z"},"cvss_score":{"type":["number","null"],"format":"float"},"description":{"type":["string","null"]},"fixed_version":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"installed_version":{"type":"string"},"last_modified_date":{"type":["string","null"],"example":"2025-12-08T12:15:47.609192Z"},"package_name":{"type":"string"},"primary_url":{"type":["string","null"]},"published_date":{"type":["string","null"],"example":"2025-12-08T12:15:47.609192Z"},"references":{},"scan_id":{"type":"integer","format":"int32"},"severity":{"type":"string"},"target":{"type":["string","null"],"example":"alpine:3.18 (alpine 3.18.0)"},"title":{"type":"string"},"type":{"type":["string","null"],"example":"alpine"},"vulnerability_id":{"type":"string"}}},"WalWarning":{"oneOf":[{"type":"object","description":"`pg_wal` is significantly larger than `max_wal_size`.","required":["pg_wal_bytes","max_wal_size_bytes","ratio","kind"],"properties":{"kind":{"type":"string","enum":["wal_bloat"]},"max_wal_size_bytes":{"type":"integer","format":"int64"},"pg_wal_bytes":{"type":"integer","format":"int64"},"ratio":{"type":"number","format":"double"}}},{"type":"object","description":"A replication slot is holding WAL it's not consuming.","required":["slot_name","retained_bytes","active","kind"],"properties":{"active":{"type":"boolean"},"kind":{"type":"string","enum":["stale_slot"]},"retained_bytes":{"type":"integer","format":"int64"},"slot_name":{"type":"string"}}},{"type":"object","description":"`archive_status/*.ready` count exceeds threshold — `archive_command`\nis either failing or running slower than WAL generation.","required":["ready_count","kind"],"properties":{"kind":{"type":"string","enum":["archive_backlog"]},"ready_count":{"type":"integer","format":"int64"}}},{"type":"object","description":"`archive_mode = on` but `archive_command` is empty / `/bin/true`.\nWAL accumulates forever waiting for a destination that never accepts.","required":["kind"],"properties":{"kind":{"type":"string","enum":["archive_mode_without_command"]}}},{"type":"object","description":"Oldest WAL segment is older than `WAL_NOT_RECYCLED_AGE_SECS`.\nIndependent signal: something is blocking recycling even if total\nsize hasn't exploded yet.","required":["oldest_age_secs","kind"],"properties":{"kind":{"type":"string","enum":["wal_not_recycled"]},"oldest_age_secs":{"type":"integer","format":"int64"}}}],"description":"One actionable warning surfaced to the UI.\n\nEach variant carries the data needed to render a remediation hint without\nthe frontend re-querying anything."},"WalWarningSeverity":{"type":"string","enum":["warning","critical"]},"WebhookConfig":{"type":"object","description":"Configuration for a generic webhook notification provider","required":["url"],"properties":{"headers":{"type":"object","description":"Custom headers to include in the request (e.g., for authentication tokens)","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"},"example":{"Authorization":"Bearer your-token","X-Custom-Header":"custom-value"}},"method":{"type":"string","description":"HTTP method to use (POST, PUT, PATCH). Defaults to POST.","example":"POST"},"timeout_secs":{"type":"integer","format":"int64","description":"Request timeout in seconds. Defaults to 30.","example":30,"minimum":0},"url":{"type":"string","description":"The URL to send webhook requests to","example":"https://api.example.com/notifications"}}},"WebhookDeliveryResponse":{"type":"object","required":["id","webhook_id","event_type","event_id","payload","success","attempt_number","created_at"],"properties":{"attempt_number":{"type":"integer","format":"int32"},"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"delivered_at":{"type":["string","null"],"format":"date-time"},"error_message":{"type":["string","null"]},"event_id":{"type":"string"},"event_type":{"type":"string"},"id":{"type":"integer","format":"int32"},"payload":{"type":"string","description":"JSON payload that was sent to the webhook endpoint","example":{"event_type":"deployment.succeeded","data":{"deployment_id":123}}},"status_code":{"type":["integer","null"],"format":"int32"},"success":{"type":"boolean"},"webhook_id":{"type":"integer","format":"int32"}}},"WebhookResponse":{"type":"object","required":["id","project_id","url","events","enabled","has_secret","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"enabled":{"type":"boolean"},"events":{"type":"array","items":{"type":"string"}},"has_secret":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"url":{"type":"string"}}},"WebhookTriggerRequest":{"allOf":[{"description":"Arbitrary JSON payload from the caller. Passed to the agent as user_context."}]},"WebhookTriggerResponse":{"type":"object","required":["run_id","status"],"properties":{"run_id":{"type":"integer","format":"int32"},"status":{"type":"string"}}},"WorkflowDryRunRequest":{"type":"object","required":["yaml"],"properties":{"cpu_limit":{"type":["number","null"],"format":"double","description":"Optional CPU override applied after parsing YAML (clamped server-side).\nWhen `Some`, this takes precedence over `cpu_limit` inside the YAML —\nlets the CLI pass `--cpu` without rewriting the YAML text."},"error_group_id":{"type":["integer","null"],"format":"int32","description":"Optional error group to link this dry-run to. When set, the executor's\n`load_error_context` path injects `{{error_type}}` / `{{error_message}}`\n/ `{{stack_trace}}` into the prompt — same behaviour as a committed\nworkflow triggered with `trigger_source_type = \"error_group\"`. Must\nbelong to `project_id` (handler enforces)."},"memory_limit_mb":{"type":["integer","null"],"format":"int64","description":"Optional memory override in MB (clamped server-side). Same precedence\nrule as `cpu_limit`.","minimum":0},"user_context":{"type":["string","null"],"description":"Optional context appended to the prompt (e.g. \"test against staging\nonly\"). Mirrors `TriggerAgentRequest.user_context`."},"yaml":{"type":"string","description":"Full WorkflowYamlConfig as YAML text. Server validates and re-serializes\nbefore storing on the run row."}}},"WorkloadDescriptor":{"type":"object","description":"Brief descriptor for discovered workloads (used in listing)","required":["id","workload_type","status","labels"],"properties":{"created_at":{"type":["string","null"],"format":"date-time","description":"Creation timestamp"},"id":{"$ref":"#/components/schemas/WorkloadId","description":"Unique ID in source system"},"image":{"type":["string","null"],"description":"Image/build reference (for containers)"},"labels":{"type":"object","description":"Labels/tags from source system","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":["string","null"],"description":"Workload name (if any)"},"status":{"$ref":"#/components/schemas/WorkloadStatus","description":"Current status"},"workload_type":{"$ref":"#/components/schemas/WorkloadType","description":"Workload type (container, function, static-site, etc.)"}}},"WorkloadId":{"type":"string","description":"Unique identifier for a workload in the source system"},"WorkloadStatus":{"type":"string","description":"Workload status in source system","enum":["running","paused","stopped","exited","failed","deployed","building","unknown"]},"WorkloadType":{"type":"string","description":"Workload type","enum":["container","function","static-site","server-side-app","worker","database","message-queue","cache","cron-job","other"]},"WriteFileBody":{"type":"object","required":["path","contents_b64"],"properties":{"contents_b64":{"type":"string","description":"File contents, base64-encoded. Required — lets callers ship binary\ndata over JSON without charset games."},"mode":{"type":["integer","null"],"format":"int32","description":"Unix permission mask (e.g. 0o644). Defaults to 0o644 when absent.","minimum":0},"path":{"type":"string","description":"Absolute path inside the sandbox. Must start with `/`."}},"additionalProperties":false},"WriteFilesBody":{"type":"object","required":["files"],"properties":{"files":{"type":"array","items":{"$ref":"#/components/schemas/WriteFileBody"},"description":"List of files to write. Each entry must include an absolute\n`path` and base64-encoded `contents_b64`. Empty list is a no-op."}},"additionalProperties":false},"WriteFilesResponse":{"type":"object","required":["written"],"properties":{"written":{"type":"integer","description":"Number of files successfully written before the first failure\n(if any). On full success this equals `files.len()`.","minimum":0}}},"ZoneListResponse":{"type":"object","description":"Zone list response","required":["zones"],"properties":{"zones":{"type":"array","items":{"$ref":"#/components/schemas/DnsZone"}}}}},"securitySchemes":{"bearer_auth":{"type":"http","scheme":"bearer","description":"Bearer token authentication. Use format: `Bearer `. Supports API keys (starting with `tk_`), CLI tokens, and session tokens."}}},"tags":[{"name":"Events","description":"Analytics events tracking endpoints"},{"name":"Metrics","description":"Analytics metrics collection endpoints including performance web vitals"},{"name":"Funnels","description":"Funnel management endpoints"},{"name":"Analytics","description":"Analytics and session replay management"},{"name":"Performance","description":"Performance metrics management"},{"name":"geo","description":"Geolocation API endpoints"},{"name":"Platform","description":"Platform information and compatibility"},{"name":"Teams","description":"Teams and project-scoped access"},{"name":"Git Providers","description":"Git provider management endpoints"},{"name":"Repositories","description":"Repository management endpoints"},{"name":"Public Repositories","description":"Endpoints for accessing public repositories without authentication. Supports GitHub and GitLab."},{"name":"Notification Providers","description":"Notification provider management endpoints"},{"name":"Notification Preferences","description":"User notification preferences and settings"},{"name":"DNS Providers","description":"DNS provider management endpoints"},{"name":"Internal DNS","description":"Per-node DNS resolver sync (ADR-011)"},{"name":"Domains","description":"Domain management endpoints"},{"name":"Email Providers","description":"Email provider management endpoints"},{"name":"Email Domains","description":"Email domain management and verification"},{"name":"Emails","description":"Email sending and retrieval"},{"name":"Email Tracking","description":"Email open and click tracking"},{"name":"Email Validation","description":"Email address validation and verification"},{"name":"Webhooks","description":"Webhook management endpoints"},{"name":"Webhook Deliveries","description":"Webhook delivery history and retry endpoints"},{"name":"External Services","description":"External service integration endpoints"},{"name":"External Services - Query","description":"Data querying and exploration endpoints"},{"name":"Metrics","description":"Time-series metrics and alert rule endpoints"},{"name":"KV Store","description":"Key-Value storage operations"},{"name":"KV Management","description":"KV service management operations"},{"name":"Blob","description":"Blob storage operations"},{"name":"Blob Management","description":"Blob service management operations"},{"name":"Feature Flags","description":"Runtime configuration that changes without a redeploy"},{"name":"Environments","description":"Environment management operations"},{"name":"Secrets","description":"File-mounted secrets (/run/secrets/)"},{"name":"Projects","description":"Project management endpoints"},{"name":"Presets","description":"Available deployment presets"},{"name":"Templates","description":"Project template endpoints"},{"name":"Custom Domains","description":"Custom domain management for projects"},{"name":"error-tracking","description":"Error tracking data fetching endpoints"},{"name":"Vulnerability Scans","description":"Vulnerability scan management endpoints"},{"name":"Agents","description":"Autonomous AI agents, autofixer (interactive AI debugging), skills/MCP definitions, and preview gateway management."},{"name":"Crons","description":"Cron jobs management API"},{"name":"Sandboxes","description":"Standalone sandbox API (`/v1/sandboxes/*`) for running isolated containers."},{"name":"Logs","description":"Log search, context, live tail, and retention management"},{"name":"Imports","description":"Import workloads from external sources"},{"name":"Status Page","description":"Status page and monitoring endpoints"},{"name":"OTel Ingest","description":"OTLP/HTTP ingest endpoints (protobuf)"},{"name":"OTel","description":"Query endpoints for the monitoring UI"},{"name":"GenAI","description":"GenAI agent activity tracing endpoints"},{"name":"Alarms","description":"Unified alarm history — list, summarise, acknowledge, resolve"},{"name":"Authentication","description":"Authentication and authorization endpoints"},{"name":"Users","description":"User management endpoints"},{"name":"Backups","description":"Backup management endpoints"},{"name":"Restore","description":"External service restore operations"},{"name":"Revenue","description":"Per-project revenue tracking integrations and analytics"},{"name":"Observability","description":"Unified observability event stream — runtime logs, requests, spans, errors, revenue"},{"name":"AI Gateway","description":"OpenAI-compatible chat, embeddings, and model endpoints"},{"name":"AI Gateway Admin","description":"Provider key management endpoints"},{"name":"AI Gateway Usage","description":"Usage analytics and reporting endpoints"},{"name":"AI Gateway Pricing","description":"Model pricing endpoints"},{"name":"API Keys","description":"API key management endpoints"},{"name":"Load Balancer","description":"Load balancer management endpoints"},{"name":"IP Access Control","description":"IP access control management endpoints"},{"name":"Files","description":"Static file serving endpoints"},{"name":"External Plugins","description":"External plugin management and discovery"}]} +{ + "components": { + "schemas": { + "AcmeOrderResponse": { + "type": "object", + "required": [ + "id", + "order_url", + "domain_id", + "email", + "status", + "identifiers", + "created_at", + "updated_at" + ], + "properties": { + "authorizations": {}, + "certificate_url": { + "type": [ + "string", + "null" + ] + }, + "challenge_validation": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/ChallengeValidationStatus", + "description": "Live challenge validation status fetched from Let's Encrypt" + } + ] + }, + "created_at": { + "type": "integer", + "format": "int64" + }, + "domain_id": { + "type": "integer", + "format": "int32" + }, + "email": { + "type": "string" + }, + "error": { + "type": [ + "string", + "null" + ] + }, + "error_type": { + "type": [ + "string", + "null" + ] + }, + "expires_at": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "finalize_url": { + "type": [ + "string", + "null" + ] + }, + "id": { + "type": "integer", + "format": "int32" + }, + "identifiers": {}, + "order_url": { + "type": "string" + }, + "status": { + "type": "string" + }, + "updated_at": { + "type": "integer", + "format": "int64" + } + } + }, + "ActivateProviderResponse": { + "type": "object", + "required": [ + "default_provider" + ], + "properties": { + "default_provider": { + "type": "string" + } + } + }, + "ActiveVisitor": { + "type": "object", + "required": [ + "session_id", + "session_start", + "last_activity", + "page_count", + "event_count", + "duration_seconds", + "is_active" + ], + "properties": { + "current_page": { + "type": [ + "string", + "null" + ] + }, + "duration_seconds": { + "type": "integer", + "format": "int64" + }, + "event_count": { + "type": "integer", + "format": "int32" + }, + "is_active": { + "type": "boolean" + }, + "last_activity": { + "type": "string" + }, + "page_count": { + "type": "integer", + "format": "int32" + }, + "session_id": { + "type": "string" + }, + "session_start": { + "type": "string" + }, + "visitor_id": { + "type": [ + "string", + "null" + ] + } + } + }, + "ActiveVisitorsQuery": { + "type": "object", + "properties": { + "deployment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + } + }, + "ActiveVisitorsResponse": { + "type": "object", + "required": [ + "active_visitors", + "window_minutes" + ], + "properties": { + "active_visitors": { + "type": "integer", + "format": "int64" + }, + "window_minutes": { + "type": "integer", + "format": "int32" + } + } + }, + "ActivityDay": { + "type": "object", + "description": "Daily activity count for a single day", + "required": [ + "date", + "count", + "level" + ], + "properties": { + "count": { + "type": "integer", + "format": "int64", + "description": "Number of deployments on this day" + }, + "date": { + "type": "string", + "description": "Date in YYYY-MM-DD format", + "example": "2024-06-15" + }, + "level": { + "type": "integer", + "format": "int32", + "description": "Intensity level (0-4) for visualization\n0: No activity, 1: Low (1-2), 2: Medium (3-5), 3: High (6-10), 4: Very High (11+)", + "example": 2 + } + } + }, + "ActivityEvent": { + "type": "object", + "description": "A single activity event for the real-time activity feed", + "required": [ + "id", + "timestamp", + "event_type", + "page_path", + "is_crawler" + ], + "properties": { + "browser": { + "type": [ + "string", + "null" + ], + "description": "Browser" + }, + "city": { + "type": [ + "string", + "null" + ], + "description": "Visitor's city (from ip_geolocations)" + }, + "country": { + "type": [ + "string", + "null" + ], + "description": "Visitor's country (from ip_geolocations)" + }, + "country_code": { + "type": [ + "string", + "null" + ], + "description": "Visitor's country code (from ip_geolocations)" + }, + "device_type": { + "type": [ + "string", + "null" + ], + "description": "Device type" + }, + "event_name": { + "type": [ + "string", + "null" + ], + "description": "Event name (for custom events)" + }, + "event_type": { + "type": "string", + "description": "Event type: \"page_view\", \"custom\", etc." + }, + "id": { + "type": "integer", + "format": "int64", + "description": "Event ID" + }, + "is_crawler": { + "type": "boolean", + "description": "Whether this event was from a crawler" + }, + "latitude": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Latitude" + }, + "longitude": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Longitude" + }, + "operating_system": { + "type": [ + "string", + "null" + ], + "description": "Operating system" + }, + "page_path": { + "type": "string", + "description": "Page path where the event happened" + }, + "page_title": { + "type": [ + "string", + "null" + ], + "description": "Page title" + }, + "referrer": { + "type": [ + "string", + "null" + ], + "description": "Referrer" + }, + "timestamp": { + "type": "string", + "format": "date-time", + "description": "When the event occurred" + }, + "visitor_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Visitor numeric ID" + } + } + }, + "ActivityGraphQuery": { + "type": "object", + "description": "Query parameters for activity graph endpoint", + "properties": { + "days": { + "type": "integer", + "format": "int32", + "description": "Number of days to include (default: 365 for last year)" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Optional environment ID to filter activity" + }, + "project_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Optional project ID to filter activity" + } + } + }, + "ActivityGraphResponse": { + "type": "object", + "description": "Response for activity graph showing daily deployment activity", + "required": [ + "days", + "total_count", + "start_date", + "end_date" + ], + "properties": { + "days": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ActivityDay" + }, + "description": "Array of daily activity counts" + }, + "end_date": { + "type": "string", + "description": "Date range end (YYYY-MM-DD)", + "example": "2024-12-31" + }, + "start_date": { + "type": "string", + "description": "Date range start (YYYY-MM-DD)", + "example": "2024-01-01" + }, + "total_count": { + "type": "integer", + "format": "int64", + "description": "Total count of activities across all days" + } + } + }, + "AddClusterMemberRequest": { + "type": "object", + "description": "Request body for adding a single member to a running cluster.", + "required": [ + "role" + ], + "properties": { + "node_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Target worker node ID. Omit or null to run on the control plane." + }, + "role": { + "type": "string", + "description": "Member role. Currently only `replica` is accepted at runtime \u2014\nmonitor is a singleton, primary is elected by pg_auto_failover.", + "example": "replica" + } + } + }, + "AddContextRequest": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } + }, + "AddEnvironmentDomainRequest": { + "type": "object", + "required": [ + "domain", + "is_primary" + ], + "properties": { + "domain": { + "type": "string" + }, + "is_primary": { + "type": "boolean" + } + } + }, + "AddEventsRequest": { + "type": "object", + "required": [ + "events" + ], + "properties": { + "events": { + "type": "string" + } + } + }, + "AddEventsResponse": { + "type": "object", + "required": [ + "event_count", + "message" + ], + "properties": { + "event_count": { + "type": "integer", + "minimum": 0 + }, + "message": { + "type": "string" + } + } + }, + "AddManagedDomainApiRequest": { + "type": "object", + "description": "Request to add a managed domain", + "required": [ + "domain" + ], + "properties": { + "auto_manage": { + "type": "boolean" + }, + "domain": { + "type": "string", + "example": "example.com" + }, + "generated_hostname_mode": { + "type": [ + "string", + "null" + ], + "description": "Generated hostname layout: `\"standard\"` (default) or `\"flat\"`." + }, + "sync_generated_records": { + "type": "boolean", + "description": "Opt in to reconciling generated hostnames into this domain's DNS zone." + } + } + }, + "AdminGateResponse": { + "type": "object", + "required": [ + "allowed_ips", + "allowed_hosts", + "trust_forwarded_for", + "source", + "editable" + ], + "properties": { + "allowed_hosts": { + "type": "array", + "items": { + "type": "string" + }, + "description": "`Host` header values allowed. Empty = any host." + }, + "allowed_ips": { + "type": "array", + "items": { + "type": "string" + }, + "description": "IPs / CIDRs allowed to reach the admin listener. Empty = any source." + }, + "editable": { + "type": "boolean", + "description": "True when the config is writable through this API. False when env\nvars are dictating the active config." + }, + "source": { + "$ref": "#/components/schemas/AdminGateSource", + "description": "Where the active config came from." + }, + "trust_forwarded_for": { + "type": "boolean", + "description": "When true, the gate trusts `X-Forwarded-For` from loopback peers." + } + } + }, + "AdminGateSource": { + "type": "string", + "description": "Where the active gate configuration came from. Env-supplied configs are\nfrozen at the process level \u2014 the UI shows them read-only and refuses to\npersist DB writes. DB-supplied configs are editable at runtime.", + "enum": [ + "default", + "db", + "env" + ] + }, + "AgentConfigResponse": { + "type": "object", + "description": "Response DTO for a single agent \u2014 masks the encrypted API key.", + "required": [ + "id", + "project_id", + "slug", + "name", + "source", + "enabled", + "trigger_config", + "ai_provider", + "api_key_set", + "max_turns", + "timeout_seconds", + "daily_budget_cents", + "cooldown_minutes", + "branch_prefix", + "deliverable", + "created_at", + "updated_at" + ], + "properties": { + "ai_model": { + "type": [ + "string", + "null" + ], + "description": "Preferred model for the CLI (e.g. \"sonnet\", \"gpt-5-codex\"). `None` means default." + }, + "ai_provider": { + "type": "string" + }, + "ai_provider_key_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "api_key_set": { + "type": "boolean", + "description": "`true` if an API key is set; `false` otherwise." + }, + "branch_prefix": { + "type": "string" + }, + "config_repo_branch": { + "type": [ + "string", + "null" + ], + "description": "Branch of the config repo to use." + }, + "config_repo_url": { + "type": [ + "string", + "null" + ], + "description": "Private config repo containing .claude/ directory (skills, MCP, plugins)." + }, + "cooldown_minutes": { + "type": "integer", + "format": "int32" + }, + "created_at": { + "type": "string" + }, + "daily_budget_cents": { + "type": "integer", + "format": "int32" + }, + "deliverable": { + "type": "string" + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "enabled": { + "type": "boolean" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "max_turns": { + "type": "integer", + "format": "int32" + }, + "mcp_servers_config": { + "description": "MCP servers config (Claude Code settings.json mcpServers format).\nCredential-bearing legacy inline values are write-only and appear as\n`***`. Omit this field on update to preserve their stored values." + }, + "name": { + "type": "string" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "prompt": { + "type": [ + "string", + "null" + ] + }, + "sandbox_enabled": { + "type": [ + "boolean", + "null" + ], + "description": "None = use global sandbox setting, true = force on, false = force off" + }, + "skills_config": { + "description": "Skills config as JSON array." + }, + "slug": { + "type": "string" + }, + "source": { + "type": "string" + }, + "timeout_seconds": { + "type": "integer", + "format": "int32" + }, + "tools_config": { + "description": "Tools config as JSON array. Legacy custom-tool webhook URLs and headers\nare write-only and appear as `***`. Omit this field on update to\npreserve their stored values." + }, + "trigger_config": {}, + "updated_at": { + "type": "string" + }, + "webhook_token": { + "type": [ + "string", + "null" + ], + "description": "Secret token for the `X-Webhook-Token` header. Shown once when created,\nmasked with `***` prefix in subsequent reads." + }, + "webhook_url": { + "type": [ + "string", + "null" + ], + "description": "Public webhook URL for triggering this agent externally.\nOnly set when `on: { webhook: true }` is configured.\nUsage: `POST {webhook_url}` with header `X-Webhook-Token: {webhook_token}`" + } + } + }, + "AgentRunLogResponse": { + "type": "object", + "required": [ + "id", + "run_id", + "level", + "message", + "created_at" + ], + "properties": { + "created_at": { + "type": "string" + }, + "id": { + "type": "integer", + "format": "int64" + }, + "level": { + "type": "string" + }, + "message": { + "type": "string" + }, + "metadata": {}, + "run_id": { + "type": "integer", + "format": "int32" + } + } + }, + "AgentRunResponse": { + "type": "object", + "required": [ + "id", + "project_id", + "source", + "trigger_type", + "status", + "tokens_input", + "tokens_output", + "estimated_cost_cents", + "files_changed", + "created_at", + "sandbox_enabled" + ], + "properties": { + "agent_name": { + "type": [ + "string", + "null" + ], + "description": "Name of the agent that created this run, if available." + }, + "agent_slug": { + "type": [ + "string", + "null" + ], + "description": "Slug of the agent that created this run, if available." + }, + "ai_model": { + "type": [ + "string", + "null" + ] + }, + "ai_output": { + "type": [ + "string", + "null" + ] + }, + "ai_provider": { + "type": [ + "string", + "null" + ], + "description": "AI provider slug that executed this run (e.g. claude_cli, codex_cli, opencode)." + }, + "ai_reasoning": { + "type": [ + "string", + "null" + ] + }, + "ai_session_id": { + "type": [ + "string", + "null" + ], + "description": "Claude CLI session UUID for resuming conversations via `--resume`." + }, + "analysis": { + "type": [ + "string", + "null" + ], + "description": "Report / analysis text produced by the agent (used for report/notification deliverables)." + }, + "branch_name": { + "type": [ + "string", + "null" + ] + }, + "commit_sha": { + "type": [ + "string", + "null" + ] + }, + "completed_at": { + "type": [ + "string", + "null" + ] + }, + "config_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Optional. NULL for ephemeral CLI runs (`source = \"cli_ephemeral\"`) and\nhistorical autofixer runs that pre-date the agent_id column." + }, + "created_at": { + "type": "string" + }, + "ephemeral_yaml": { + "type": [ + "string", + "null" + ], + "description": "Full WorkflowYamlConfig as YAML text. Populated only when\n`source = \"cli_ephemeral\"`. Used by the web UI to show a \"View YAML\"\nmodal so the user can see exactly what the executor ran." + }, + "error_message": { + "type": [ + "string", + "null" + ] + }, + "estimated_cost_cents": { + "type": "integer", + "format": "int32" + }, + "files_changed": { + "type": "integer", + "format": "int32" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "phase": { + "type": [ + "string", + "null" + ], + "description": "Autofixer phase: \"analyzing\", \"analyzed\", \"fixing\", \"fix_ready\", \"no_fix\",\n\"pr_created\", or NULL for non-autofixer runs." + }, + "pr_number": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "pr_url": { + "type": [ + "string", + "null" + ] + }, + "preview_url": { + "type": [ + "string", + "null" + ] + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "prompt_text": { + "type": [ + "string", + "null" + ], + "description": "Final assembled prompt the AI CLI actually saw (trigger context block +\nYAML prompt, with error-group fields interpolated). Captured once per\nrun. `None` for pre-migration rows." + }, + "run_config": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/AutofixRunConfig", + "description": "Per-run AI options the user chose when starting an autofixer run\n(provider, model, max_turns, branch). NULL for generic agent runs\nand historical rows. Used to prefill the retry dialog." + } + ] + }, + "sandbox_enabled": { + "type": "boolean", + "description": "Legacy field \u2014 all runs now execute in a sandbox. Kept for\nbackwards-compatible JSON shape; always `true`." + }, + "source": { + "type": "string", + "description": "`committed` (the run's config lives in `project_agents`) or\n`cli_ephemeral` (the config was uploaded via the CLI for a one-off\ndry run; see `ephemeral_yaml`)." + }, + "started_at": { + "type": [ + "string", + "null" + ] + }, + "status": { + "type": "string" + }, + "tokens_input": { + "type": "integer", + "format": "int32" + }, + "tokens_output": { + "type": "integer", + "format": "int32" + }, + "trigger_source_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "trigger_source_type": { + "type": [ + "string", + "null" + ] + }, + "trigger_type": { + "type": "string" + }, + "user_context": { + "type": [ + "string", + "null" + ], + "description": "User-provided context for this run (e.g. webhook payload, manual instructions)." + } + } + }, + "AgentRunWithLogsResponse": { + "type": "object", + "required": [ + "run", + "logs" + ], + "properties": { + "logs": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AgentRunLogResponse" + } + }, + "run": { + "$ref": "#/components/schemas/AgentRunResponse" + } + } + }, + "AgentSandboxSettings": { + "type": "object", + "description": "Global agent sandbox settings. Controls whether agent runs are isolated\ninside Docker containers by default. Individual agents can override this.", + "properties": { + "api_key_encrypted": { + "type": [ + "string", + "null" + ], + "description": "DEPRECATED: use `providers[default_provider].credentials_encrypted` instead.", + "default": null + }, + "auth_type": { + "type": "string", + "description": "DEPRECATED: use `providers[default_provider].auth_type` instead.", + "default": "subscription" + }, + "cpu_limit": { + "type": "number", + "format": "double", + "description": "CPU limit in cores for sandbox containers", + "default": 4.0, + "example": 4.0 + }, + "custom_image": { + "type": "string", + "description": "Custom Docker image (only used when runtime is \"custom\").\nMust have git and claude CLI installed.", + "default": "", + "example": "" + }, + "default_provider": { + "type": "string", + "description": "Default AI provider for agents: \"claude_cli\", \"opencode\", or \"codex_cli\".\nWorkspaces always use this provider \u2014 no per-session override.", + "default": "claude_cli", + "example": "claude_cli" + }, + "enabled": { + "type": "boolean", + "description": "Sandbox is always enabled \u2014 the executor refuses to run any agent\noutside a sandboxed container. Field is retained so existing settings\nrows still deserialize, but it is ignored at runtime.", + "default": true + }, + "memory_limit_mb": { + "type": "integer", + "format": "int64", + "description": "Memory limit in MB for sandbox containers", + "default": 8192, + "example": 8192, + "minimum": 0 + }, + "network_mode": { + "type": "string", + "description": "Network access level: \"full\" (unrestricted), \"restricted\" (Temps network only), \"none\" (no network)", + "default": "full", + "example": "full" + }, + "providers": { + "type": "object", + "description": "Per-provider auth + config. Keyed by provider id (e.g. `claude_cli`,\n`codex_cli`, `opencode`). Adding a new provider only requires a new\ncatalog entry on the Rust side \u2014 the JSON column stays migration-free.", + "default": {}, + "additionalProperties": { + "$ref": "#/components/schemas/ProviderConfig" + }, + "propertyNames": { + "type": "string" + } + }, + "runtime": { + "type": "string", + "description": "Runtime preset: \"node\", \"bun\", \"python\", \"rust\", \"go\", \"full\", or \"custom\"", + "default": "node", + "example": "node" + }, + "sandbox_backend": { + "type": [ + "string", + "null" + ], + "description": "Default isolation backend for sandboxes: \"docker\" (default) or\n\"firecracker\" (ADR-029; requires `temps firecracker setup`). Only\nconsulted when the Firecracker backend probes available \u2014 otherwise\nDocker is used regardless.", + "default": null, + "example": "docker" + } + } + }, + "AgentSandboxSettingsMasked": { + "type": "object", + "description": "Agent sandbox settings with masked per-provider credentials.\nEach provider entry reports only whether a credential is saved, not\nthe encrypted blob itself. Non-sensitive fields (auth_type, default_model,\nextra) are passed through so the UI can render provider-specific state.", + "required": [ + "default_provider", + "providers", + "api_key_saved", + "auth_type", + "enabled", + "runtime", + "custom_image", + "cpu_limit", + "memory_limit_mb", + "network_mode", + "sandbox_backend" + ], + "properties": { + "api_key_saved": { + "type": "boolean" + }, + "auth_type": { + "type": "string" + }, + "cpu_limit": { + "type": "number", + "format": "double" + }, + "custom_image": { + "type": "string" + }, + "default_provider": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "memory_limit_mb": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "network_mode": { + "type": "string" + }, + "providers": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/ProviderConfigMasked" + }, + "propertyNames": { + "type": "string" + } + }, + "runtime": { + "type": "string" + }, + "sandbox_backend": { + "type": "string" + } + } + }, + "AggregatedBucketItem": { + "type": "object", + "required": [ + "timestamp", + "count" + ], + "properties": { + "count": { + "type": "integer", + "format": "int64" + }, + "timestamp": { + "type": "string" + } + } + }, + "AggregatedBucketsQuery": { + "type": "object", + "description": "Query parameters for aggregated metrics by time bucket", + "required": [ + "start_date", + "end_date" + ], + "properties": { + "aggregation_level": { + "$ref": "#/components/schemas/AggregationLevel", + "description": "Aggregation level: events, sessions, or visitors" + }, + "bucket_size": { + "type": "string", + "description": "Time bucket size: \"1 hour\", \"1 day\", \"1 week\", etc. (default: \"1 hour\")" + }, + "deployment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Optional deployment filter" + }, + "end_date": { + "type": "string", + "format": "date-time", + "description": "End date for the query range" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Optional environment filter" + }, + "start_date": { + "type": "string", + "format": "date-time", + "description": "Start date for the query range" + } + } + }, + "AggregatedBucketsResponse": { + "type": "object", + "required": [ + "bucket_size", + "aggregation_level", + "items", + "total" + ], + "properties": { + "aggregation_level": { + "type": "string" + }, + "bucket_size": { + "type": "string" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AggregatedBucketItem" + } + }, + "total": { + "type": "integer", + "format": "int64" + } + } + }, + "AggregationLevel": { + "type": "string", + "enum": [ + "events", + "sessions", + "visitors" + ] + }, + "AggregationTemporality": { + "type": "string", + "description": "The aggregation temporality of a Sum/Histogram/ExponentialHistogram metric.\n\nMirrors OTel's `AggregationTemporality` proto enum: whether reported values\nare cumulative since the start of the series (Cumulative) or only the delta\nsince the previous report (Delta).", + "enum": [ + "unspecified", + "delta", + "cumulative" + ] + }, + "AiAgentBreakdownResponse": { + "type": "object", + "description": "Response wrapping the AI agent breakdown rows.", + "required": [ + "items", + "start_time", + "end_time" + ], + "properties": { + "end_time": { + "type": "string" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AiAgentBreakdownRow" + } + }, + "start_time": { + "type": "string" + } + } + }, + "AiAgentBreakdownRow": { + "type": "object", + "description": "One row in the AI-agent analytics breakdown. `agent` is the canonical\ncrawler name (e.g. `GPTBot`, `Claude-User`), `provider` is the vendor used\nfor grouping + logos. The UI mirrors the browsers card and ranks by\n`request_count`.", + "required": [ + "provider", + "agent", + "purpose", + "request_count", + "unique_ips" + ], + "properties": { + "agent": { + "type": "string" + }, + "last_seen": { + "type": [ + "string", + "null" + ], + "description": "Last-seen timestamp in RFC3339 format, or `None` if no rows matched.", + "example": "2026-05-29T12:00:00Z" + }, + "provider": { + "type": "string" + }, + "purpose": { + "type": "string" + }, + "request_count": { + "type": "integer", + "format": "int64" + }, + "unique_ips": { + "type": "integer", + "format": "int64" + } + } + }, + "AiAgentDescriptor": { + "type": "object", + "description": "Static descriptor for one entry in the known-AI-agents taxonomy.", + "required": [ + "provider", + "agent", + "purpose" + ], + "properties": { + "agent": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "purpose": { + "type": "string" + } + } + }, + "AiAgentPageRow": { + "type": "object", + "description": "One row in the pages-by-agent breakdown. Returned by\n[`ProxyLogService::get_ai_agent_pages`] for a single named agent.\n`unique_ips` counts distinct client IPs that hit this path via that agent\n(same definition as the per-agent unique-IPs in [`AiAgentBreakdownRow`]).", + "required": [ + "path", + "request_count", + "unique_ips" + ], + "properties": { + "last_seen": { + "type": [ + "string", + "null" + ], + "description": "Last-seen timestamp in RFC3339 format, or `None` if no rows matched.", + "example": "2026-05-29T12:00:00Z" + }, + "path": { + "type": "string" + }, + "request_count": { + "type": "integer", + "format": "int64" + }, + "unique_ips": { + "type": "integer", + "format": "int64" + } + } + }, + "AiAgentPagesResponse": { + "type": "object", + "description": "Response wrapping the per-agent pages breakdown rows.", + "required": [ + "agent", + "items", + "start_time", + "end_time" + ], + "properties": { + "agent": { + "type": "string", + "description": "The agent name this breakdown is scoped to." + }, + "end_time": { + "type": "string" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AiAgentPageRow" + } + }, + "start_time": { + "type": "string" + } + } + }, + "AiAgentTimelineResponse": { + "type": "object", + "description": "Response wrapping the AI agent timeline rows.", + "required": [ + "items", + "start_time", + "end_time", + "bucket", + "group_by" + ], + "properties": { + "bucket": { + "type": "string", + "description": "Bucket interval used for the buckets (so the UI can label the x-axis).", + "example": "1 hour" + }, + "end_time": { + "type": "string" + }, + "group_by": { + "type": "string", + "description": "Echoes the grouping dimension actually applied.", + "example": "provider" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AiAgentTimelineRow" + } + }, + "start_time": { + "type": "string" + } + } + }, + "AiAgentTimelineRow": { + "type": "object", + "description": "One point in the AI-agent timeline: the request count for a single\n(`bucket`, `key`) pair, where `key` is a provider or agent name depending on\nthe requested grouping. The UI pivots these into one stacked series per\n`key` across the shared bucket x-axis.", + "required": [ + "bucket", + "key", + "request_count" + ], + "properties": { + "bucket": { + "type": "string", + "description": "Bucket start in RFC3339 format.", + "example": "2026-05-29T12:00:00Z" + }, + "key": { + "type": "string", + "description": "Provider or agent name this count belongs to.", + "example": "OpenAI" + }, + "request_count": { + "type": "integer", + "format": "int64" + } + } + }, + "AiChatLimitsSettings": { + "type": "object", + "description": "Bounds on one AI chat turn.\n\nA turn is bounded by TIME rather than by a number of steps. A step count\nsays nothing about cost or about how long someone has been watching a\nspinner, and it cuts short exactly the long, productive turns the chat\nexists for. The user can already see each tool call and press Stop; the\ndeadline is what guarantees an *unattended* turn still ends.\n\nThe right value is a property of the model, which is why it is configurable\nrather than compiled in: a full alert-suggestion turn takes ~10 minutes\nagainst a slow local model and seconds against a hosted one.", + "properties": { + "turn_timeout_secs": { + "type": "integer", + "format": "int32", + "description": "How long one turn may run before it is stopped and the partial answer\nreturned, in seconds. The user is told the turn was cut short.\n\nChecked between steps, not mid-call: a model round already in flight\nfinishes, so a turn can overrun by up to one round. Against a slow\nself-hosted model that is a minute or two. Aborting mid-stream would cut\nthe answer off in the middle of a sentence and throw away work already\npaid for, which is worse than a late stop.", + "default": 900, + "example": 900, + "maximum": 3600, + "minimum": 30 + } + } + }, + "AiConfigSettings": { + "type": "object", + "description": "Global AI configuration settings. Controls the default config repo\ncontaining `.claude/` directory (skills, MCP servers, plugins) that\ngets overlaid into every agent sandbox.", + "properties": { + "config_repo": { + "type": "string", + "description": "Global config repo URL in \"owner/repo\" format (e.g. \"myorg/claude-config\").\nCloned at agent run time and overlaid into the sandbox's `.claude/` directory.", + "default": "", + "example": "" + }, + "config_repo_branch": { + "type": "string", + "description": "Branch of the config repo to use.", + "default": "main", + "example": "main" + } + } + }, + "AiDataAccessResponse": { + "type": "object", + "required": [ + "service_id", + "enabled" + ], + "properties": { + "enabled": { + "type": "boolean", + "description": "Whether the AI assistant may read row data from this service", + "example": false + }, + "service_id": { + "type": "integer", + "format": "int32", + "description": "Service id" + } + } + }, + "AiPageBreakdownResponse": { + "type": "object", + "description": "Response wrapping the AI page breakdown rows.", + "required": [ + "items", + "start_time", + "end_time" + ], + "properties": { + "end_time": { + "type": "string" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AiPageBreakdownRow" + } + }, + "start_time": { + "type": "string" + } + } + }, + "AiPageBreakdownRow": { + "type": "object", + "description": "One row in the AI-crawled-pages breakdown. `agent_count` is the number of\n*distinct* AI agents that hit this path, so the UI can show both how heavily\nand how broadly a page is being crawled.", + "required": [ + "path", + "request_count", + "agent_count" + ], + "properties": { + "agent_count": { + "type": "integer", + "format": "int64" + }, + "last_seen": { + "type": [ + "string", + "null" + ], + "description": "Last-seen timestamp in RFC3339 format, or `None` if no rows matched.", + "example": "2026-05-29T12:00:00Z" + }, + "path": { + "type": "string" + }, + "request_count": { + "type": "integer", + "format": "int64" + } + } + }, + "AiStatusBreakdownResponse": { + "type": "object", + "description": "Response wrapping the AI status breakdown rows.", + "required": [ + "items", + "start_time", + "end_time" + ], + "properties": { + "end_time": { + "type": "string" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AiStatusBreakdownRow" + } + }, + "start_time": { + "type": "string" + } + } + }, + "AiStatusBreakdownRow": { + "type": "object", + "description": "One row in the AI-agent HTTP status breakdown: the request count for a\nstatus class (`2xx`/`3xx`/`4xx`/`5xx`/`other`) across crawler traffic.", + "required": [ + "status_class", + "request_count" + ], + "properties": { + "request_count": { + "type": "integer", + "format": "int64" + }, + "status_class": { + "type": "string", + "description": "Status class label.", + "example": "2xx" + } + } + }, + "AlarmListResponse": { + "type": "object", + "description": "Paginated list of alarms.", + "required": [ + "items", + "total", + "page", + "page_size" + ], + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AlarmResponse" + } + }, + "page": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "page_size": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "total": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + }, + "AlarmResponse": { + "type": "object", + "description": "Full alarm representation returned by list/summary endpoints.", + "required": [ + "id", + "project_id", + "alarm_type", + "severity", + "status", + "title", + "fired_at", + "created_at", + "updated_at" + ], + "properties": { + "acknowledged_at": { + "type": [ + "string", + "null" + ], + "description": "ISO-8601 UTC timestamp when the alarm was acknowledged, if any." + }, + "acknowledged_by": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "User ID who acknowledged the alarm, if any." + }, + "alarm_type": { + "type": "string" + }, + "container_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "created_at": { + "type": "string", + "description": "ISO-8601 UTC timestamp when the row was created." + }, + "deployment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "fired_at": { + "type": "string", + "description": "ISO-8601 UTC timestamp when the alarm fired." + }, + "id": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": [ + "string", + "null" + ] + }, + "metadata": { + "description": "Arbitrary JSON metadata attached by the alarm source." + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "resolved_at": { + "type": [ + "string", + "null" + ], + "description": "ISO-8601 UTC timestamp when the alarm was resolved, if any." + }, + "service_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "severity": { + "type": "string" + }, + "status": { + "type": "string" + }, + "title": { + "type": "string" + }, + "updated_at": { + "type": "string", + "description": "ISO-8601 UTC timestamp when the row was last updated." + } + } + }, + "AlarmSummaryResponse": { + "type": "object", + "description": "Re-export AlarmSummary for the OpenAPI schema.", + "required": [ + "total_active", + "firing", + "acknowledged", + "critical", + "warning", + "by_type" + ], + "properties": { + "acknowledged": { + "type": "integer", + "format": "int32", + "minimum": 0 + }, + "by_type": { + "type": "object", + "additionalProperties": { + "type": "integer", + "format": "int32", + "minimum": 0 + }, + "propertyNames": { + "type": "string" + } + }, + "critical": { + "type": "integer", + "format": "int32", + "minimum": 0 + }, + "firing": { + "type": "integer", + "format": "int32", + "minimum": 0 + }, + "total_active": { + "type": "integer", + "format": "int32", + "minimum": 0 + }, + "warning": { + "type": "integer", + "format": "int32", + "minimum": 0 + } + } + }, + "AlertRuleResponse": { + "type": "object", + "required": [ + "id", + "project_id", + "name", + "trigger_type", + "trigger_config", + "notification_priority", + "cooldown_minutes", + "enabled", + "created_at", + "updated_at" + ], + "properties": { + "cooldown_minutes": { + "type": "integer", + "format": "int32" + }, + "created_at": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "environment_filter": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "error_level_filter": { + "type": [ + "string", + "null" + ] + }, + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "notification_priority": { + "type": "string" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "trigger_config": {}, + "trigger_type": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + } + }, + "AllocEntry": { + "type": "object", + "description": "Wire-format allocation. `null` in the JSON when the node hasn't been\nallocated yet \u2014 workers should treat that as \"single-host mode, do\nnot bring up the overlay\".", + "required": [ + "node_id", + "compute_cidr", + "bridge_address", + "underlay_address" + ], + "properties": { + "bridge_address": { + "type": "string" + }, + "compute_cidr": { + "type": "string" + }, + "node_id": { + "type": "string", + "description": "Stable v5 UUID derived from the database node id." + }, + "underlay_address": { + "type": "string" + } + } + }, + "AnalyticsSessionEventsResponse": { + "type": "object", + "required": [ + "session_id", + "events", + "total_events" + ], + "properties": { + "events": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SessionEvent" + } + }, + "session_id": { + "type": "string" + }, + "total_events": { + "type": "integer", + "minimum": 0 + } + } + }, + "AnnotatedSpan": { + "type": "object", + "description": "A single span annotated with the project that originally stored it.\nUsed in `UnifiedTrace` to let the UI colour-code spans by project.", + "required": [ + "project_id", + "project_name", + "span" + ], + "properties": { + "project_id": { + "type": "integer", + "format": "int32", + "description": "The project that stored this span (same as `span.project_id`)." + }, + "project_name": { + "type": "string", + "description": "Human-readable project name for waterfall colour-coding and legend." + }, + "span": { + "$ref": "#/components/schemas/SpanRecord", + "description": "Original span data verbatim from storage." + } + } + }, + "AnomalyAlgorithm": { + "type": "string", + "description": "Anomaly baseline algorithm. Adding one (e.g. a new robust variant) is a\ncode-only enum addition \u2014 no migration, since it lives inside the blob.", + "enum": [ + "robust", + "basic", + "agile", + "ewma" + ] + }, + "AnomalyParams": { + "type": "object", + "description": "Seasonal anomaly-band detector parameters (stub \u2014 not yet evaluated).", + "properties": { + "algorithm": { + "$ref": "#/components/schemas/AnomalyAlgorithm", + "description": "Baseline model. `robust` is the default (seasonal, stable, flags level\nshifts); `ewma`/`agile` adopt level shifts; `basic` is non-seasonal." + }, + "baseline_lookback_days": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "How far back to build the baseline. `None` = an evaluator default." + }, + "deviations": { + "type": "number", + "format": "double", + "description": "Band width in robust standard deviations (Datadog's `bounds`)." + }, + "direction": { + "$ref": "#/components/schemas/Direction", + "description": "Which side(s) of the band a deviation must be on to count." + }, + "pct_anomalous": { + "type": "number", + "format": "double", + "description": "Fraction (0..=1) of points in the window that must be anomalous to fire." + }, + "seasonality": { + "$ref": "#/components/schemas/Seasonality", + "description": "Seasonality model for the baseline." + } + } + }, + "AnomalyPreviewPointResponse": { + "type": "object", + "required": [ + "bucket", + "value", + "lower", + "upper", + "breaching" + ], + "properties": { + "breaching": { + "type": "boolean" + }, + "bucket": { + "type": "string", + "example": "2025-10-12T12:15:47Z" + }, + "lower": { + "type": "number", + "format": "double", + "description": "Lower edge of the expected band at this point." + }, + "upper": { + "type": "number", + "format": "double", + "description": "Upper edge of the expected band at this point." + }, + "value": { + "type": "number", + "format": "double" + } + } + }, + "AnomalyPreviewRequest": { + "type": "object", + "required": [ + "project_id", + "metric_name", + "aggregation", + "window_secs", + "detection_config" + ], + "properties": { + "aggregation": { + "type": "string", + "description": "One of `avg|sum|min|max|count|rate|p50|p90|p95|p99`." + }, + "detection_config": { + "$ref": "#/components/schemas/DetectionConfig", + "description": "The detector to backtest. `static` and `anomaly` are supported \u2014 the\nkinds the evaluator actually runs." + }, + "end_time": { + "type": [ + "string", + "null" + ], + "description": "RFC 3339; defaults to now.", + "example": "2025-10-12T12:15:47Z" + }, + "metric_name": { + "type": "string" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "start_time": { + "type": [ + "string", + "null" + ], + "description": "RFC 3339; defaults to 7 days before `end_time`.", + "example": "2025-10-12T12:15:47Z" + }, + "window_secs": { + "type": "integer", + "format": "int32" + } + } + }, + "AnomalyPreviewResponse": { + "type": "object", + "required": [ + "points", + "breach_count", + "baseline_samples", + "sufficient" + ], + "properties": { + "baseline_samples": { + "type": "integer", + "format": "int64", + "description": "Baseline sample count (drives the `sufficient` flag)." + }, + "breach_count": { + "type": "integer", + "format": "int64", + "description": "How many points in the range would have fired." + }, + "points": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AnomalyPreviewPointResponse" + } + }, + "sufficient": { + "type": "boolean", + "description": "Whether the baseline had enough history for a trustworthy band." + } + } + }, + "ApiKeyListResponse": { + "type": "object", + "required": [ + "api_keys", + "total" + ], + "properties": { + "api_keys": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ApiKeyResponse" + } + }, + "total": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + }, + "ApiKeyResponse": { + "type": "object", + "required": [ + "id", + "name", + "key_prefix", + "role_type", + "is_active", + "created_at" + ], + "properties": { + "created_at": { + "type": "string", + "format": "date-time", + "example": "2024-01-01T00:00:00Z" + }, + "expires_at": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "example": "2024-12-31T23:59:59Z" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "is_active": { + "type": "boolean" + }, + "key_prefix": { + "type": "string" + }, + "last_used_at": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "example": "2024-01-01T00:00:00Z" + }, + "name": { + "type": "string" + }, + "permissions": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "role_type": { + "type": "string" + } + } + }, + "AppSettings": { + "type": "object", + "description": "Application settings stored in the database\nAll fields have sensible defaults for easy onboarding", + "properties": { + "agent_sandbox": { + "oneOf": [ + { + "$ref": "#/components/schemas/AgentSandboxSettings" + } + ], + "default": { + "default_provider": "claude_cli", + "providers": {}, + "auth_type": "subscription", + "api_key_encrypted": null, + "enabled": true, + "runtime": "node", + "custom_image": "", + "cpu_limit": 4.0, + "memory_limit_mb": 8192, + "network_mode": "full", + "sandbox_backend": null + } + }, + "ai_chat_limits": { + "oneOf": [ + { + "$ref": "#/components/schemas/AiChatLimitsSettings", + "description": "Limits on a single AI chat turn. Operator-tunable because the right\nvalue depends on the model: a turn against a slow self-hosted model can\nlegitimately take ten minutes, while a hosted one finishes in seconds\nand a shorter ceiling keeps costs predictable." + } + ], + "default": { + "turn_timeout_secs": 900 + } + }, + "ai_config": { + "oneOf": [ + { + "$ref": "#/components/schemas/AiConfigSettings" + } + ], + "default": { + "config_repo": "", + "config_repo_branch": "main" + } + }, + "build_limits": { + "oneOf": [ + { + "$ref": "#/components/schemas/BuildLimitsSettings", + "description": "Build-time resource limits applied on the control plane to prevent\n`docker build` from saturating host CPU/RAM. Worker nodes are\nintentionally NOT subject to these limits (each worker is dedicated\nhardware that already has its own per-host headroom)." + } + ], + "default": { + "max_concurrent": 2, + "cpu_limit_cores": 0.0, + "memory_limit_mb": 0 + } + }, + "cluster_dns": { + "oneOf": [ + { + "$ref": "#/components/schemas/ClusterDnsSettings", + "description": "Cluster-DNS resolver settings (ADR-024, experimental beta). Off by\ndefault \u2014 see `ClusterDnsSettings` for the incident background and\ntrade-offs. Must be explicitly enabled by operators who need\n`*.temps.local` service-to-service resolution inside containers." + } + ], + "default": { + "enabled": false + } + }, + "console_version": { + "type": [ + "string", + "null" + ], + "description": "Binary version tag (e.g. \"v0.1.0\") of the *console* process\n(`temps serve`, role=all or role=console) that last started. Written\non console startup; read by the standalone `temps proxy` to detect\nversion skew during a rolling upgrade (ADR-017 Phase 3). `None` on\ninstalls that never ran a console build carrying this field.\n\nThis is informational state written by the binary itself \u2014 NOT an\noperator-tunable setting. It is intentionally absent from\n`AppSettingsResponse` and the PATCH path so an operator cannot\naccidentally overwrite the self-recorded value.", + "default": null + }, + "container_logs": { + "oneOf": [ + { + "$ref": "#/components/schemas/ContainerLogSettings" + } + ], + "default": { + "max_size": "50m", + "max_file": 3, + "service_max_size": "20m", + "service_max_file": 3 + } + }, + "disk_space_alert": { + "oneOf": [ + { + "$ref": "#/components/schemas/DiskSpaceAlertSettings" + } + ], + "default": { + "enabled": true, + "threshold_percent": 80, + "check_interval_seconds": 300, + "monitor_path": null + } + }, + "dns_provider": { + "oneOf": [ + { + "$ref": "#/components/schemas/DnsProviderSettings" + } + ], + "default": { + "provider": "manual", + "cloudflare_api_key": null + } + }, + "docker_registry": { + "oneOf": [ + { + "$ref": "#/components/schemas/DockerRegistrySettings" + } + ], + "default": { + "enabled": false, + "registry_url": null, + "username": null, + "password": null, + "tls_verify": true, + "ca_certificate": null + } + }, + "edge_target": { + "type": [ + "string", + "null" + ], + "description": "Public edge target that generated DNS records point at when a managed\ndomain opts into automatic record sync. An IPv4/IPv6 address produces an\n`A`/`AAAA` record; anything else is treated as a `CNAME` target. `None`\ndisables DNS record sync regardless of per-domain opt-in.", + "default": null + }, + "external_url": { + "type": [ + "string", + "null" + ], + "default": null + }, + "insecure_tls": { + "type": "boolean", + "description": "Skip TLS certificate verification on outbound HTTP clients built by the\nserver (deployer, agent, remote service client). Strictly opt-in for\noperators running self-signed control plane / worker certs on a trusted\ninternal network. Worker\u2192control-plane traffic that traverses the public\ninternet must keep this `false` \u2014 otherwise a MitM steals the join token.", + "default": false + }, + "internal_url": { + "type": [ + "string", + "null" + ], + "description": "URL that service containers use to reach the Temps API from *inside*\nthe Docker network (OTLP metrics ingest, agent callbacks, etc.). On\nDocker Desktop this defaults to `http://host.docker.internal:`;\non Linux it requires the `host.docker.internal:host-gateway` host\nmapping (which Temps adds to provisioned containers). Distinct from\n`external_url`, which is the public-facing address.", + "default": null + }, + "letsencrypt": { + "oneOf": [ + { + "$ref": "#/components/schemas/LetsEncryptSettings" + } + ], + "default": { + "email": null, + "environment": "production" + } + }, + "monitoring": { + "oneOf": [ + { + "$ref": "#/components/schemas/MonitoringSettings", + "description": "Metrics observability settings. Controls the MetricsStore backend,\nscrape interval, and tiered retention windows." + } + ], + "default": { + "enabled": false, + "store": "timescale_db", + "scrape_interval_secs": 30, + "retention_raw_days": 7, + "retention_hourly_days": 90, + "retention_daily_years": 2, + "clickhouse_url": null + } + }, + "multi_node": { + "oneOf": [ + { + "$ref": "#/components/schemas/MultiNodeSettings" + } + ], + "default": { + "join_token_hash": null, + "private_address": null, + "legacy_shared_token_enabled": true, + "cluster_ca_cert_pem": null, + "cluster_ca_key_encrypted": null, + "require_mtls": false, + "node_cpu_alert_percent": 90.0, + "node_memory_alert_percent": 90.0, + "node_disk_alert_percent": 90.0 + } + }, + "observability_compression": { + "oneOf": [ + { + "$ref": "#/components/schemas/ObservabilityCompressionSettings", + "description": "TimescaleDB compression delays for immutable observability data.\nChanges are applied at runtime by the Settings API." + } + ], + "default": { + "proxy_logs_after_hours": 24, + "otel_spans_after_hours": 24 + } + }, + "observability_retention": { + "oneOf": [ + { + "$ref": "#/components/schemas/ObservabilityRetentionSettings", + "description": "Retention windows for raw proxy and OpenTelemetry telemetry.\nTimescaleDB policies are updated at runtime by the Settings API." + } + ], + "default": { + "proxy_logs_days": 30, + "otel_spans_days": 90, + "otel_logs_days": 90, + "otel_metrics_days": 90 + } + }, + "on_demand_tls": { + "oneOf": [ + { + "$ref": "#/components/schemas/OnDemandTlsSettings" + } + ], + "default": { + "enabled": false, + "zone": null, + "max_concurrent": 3, + "hourly_cap": 10, + "deployment_url_mode": "http" + } + }, + "preview_domain": { + "type": "string", + "default": "localho.st" + }, + "preview_gateway": { + "oneOf": [ + { + "$ref": "#/components/schemas/PreviewGatewaySettings" + } + ], + "default": { + "image": "ghcr.io/gotempsh/temps-preview-gateway:latest", + "host_port": 8090, + "auto_upgrade": true + } + }, + "rate_limiting": { + "oneOf": [ + { + "$ref": "#/components/schemas/RateLimitSettings" + } + ], + "default": { + "enabled": false, + "max_requests_per_minute": 60, + "max_requests_per_hour": 1000, + "whitelist_ips": [], + "blacklist_ips": [] + } + }, + "require_mfa_for_admins": { + "type": "boolean", + "description": "When `true`, any user holding the `Admin` role must have MFA enrolled\n(`users.mfa_enabled = true`) to complete a **password** login. Users\nwithout MFA enrolled are rejected with a typed error instructing them\nto enroll before retrying. This only gates the password-login path\n(`AuthService::login`) -- SSO/OIDC logins are handled by a separate\ncode path (`OidcService::resolve_user` + `oidc_handler`) and are\nintentionally unaffected, since federating identity to a\nproperly-hardened IdP is itself an acceptable alternative to local\nTOTP MFA. Modeled as a settings row (not an env var) per CLAUDE.md so\nan operator can flip it at runtime via the Settings API without\nrestarting the binary.", + "default": false + }, + "screenshots": { + "oneOf": [ + { + "$ref": "#/components/schemas/ScreenshotSettings" + } + ], + "default": { + "enabled": false, + "provider": "local", + "url": "" + } + }, + "security_headers": { + "oneOf": [ + { + "$ref": "#/components/schemas/SecurityHeadersSettings" + } + ], + "default": { + "enabled": false, + "preset": "moderate", + "content_security_policy": "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'self'", + "x_frame_options": "SAMEORIGIN", + "x_content_type_options": "nosniff", + "x_xss_protection": "1; mode=block", + "strict_transport_security": "max-age=31536000; includeSubDomains", + "referrer_policy": "strict-origin-when-cross-origin", + "permissions_policy": "geolocation=(), microphone=(), camera=()" + } + }, + "setup_complete": { + "type": "boolean", + "description": "Set to `true` by `temps setup` (all modes) once initial configuration\nhas been applied. The web onboarding wizard reads this from the server\nand skips itself when true, preventing the \"Configure Base Domain\" wall\nfrom appearing on installs that were already configured via the CLI.", + "default": false + }, + "cloud": { + "oneOf": [ + { + "$ref": "#/components/schemas/CloudSettings", + "description": "Managed control-plane connection. Credentials are deliberately not\nstored here; they live in the owner-only cloud-link state file." + } + ], + "default": { + "backend_url": "https://app.temps.sh" + } + } + } + }, + "AppSettingsResponse": { + "type": "object", + "description": "Safe response for application settings that masks sensitive fields", + "required": [ + "preview_domain", + "screenshots", + "letsencrypt", + "dns_provider", + "security_headers", + "rate_limiting", + "docker_registry", + "disk_space_alert", + "container_logs", + "agent_sandbox", + "ai_config", + "preview_gateway", + "multi_node", + "monitoring", + "observability_compression", + "observability_retention", + "effective_metrics_store", + "effective_observability_store", + "insecure_tls", + "setup_complete", + "require_mfa_for_admins", + "cluster_dns", + "build_limits", + "ai_chat_limits" + ], + "properties": { + "agent_sandbox": { + "$ref": "#/components/schemas/AgentSandboxSettingsMasked" + }, + "ai_chat_limits": { + "$ref": "#/components/schemas/AiChatLimitsSettings", + "description": "Per-turn limits for the AI chat. No sensitive content." + }, + "ai_config": { + "$ref": "#/components/schemas/AiConfigSettings" + }, + "build_limits": { + "$ref": "#/components/schemas/BuildLimitsSettings", + "description": "Build-time resource limits (control-plane only). No sensitive content,\npassed through as-is." + }, + "cluster_dns": { + "$ref": "#/components/schemas/ClusterDnsSettings", + "description": "Cluster-DNS resolver settings (ADR-024, experimental beta). No masking\nneeded \u2014 `enabled` is a plain bool with no sensitive content. Passed\nthrough as-is so the settings UI can read and toggle the flag." + }, + "container_logs": { + "$ref": "#/components/schemas/ContainerLogSettings" + }, + "disk_space_alert": { + "$ref": "#/components/schemas/DiskSpaceAlertSettings" + }, + "dns_provider": { + "$ref": "#/components/schemas/DnsProviderSettingsMasked" + }, + "docker_registry": { + "$ref": "#/components/schemas/DockerRegistrySettingsMasked" + }, + "edge_target": { + "type": [ + "string", + "null" + ], + "description": "Public edge target that synced DNS records point at (IP \u2192 A/AAAA, else CNAME)." + }, + "effective_metrics_store": { + "$ref": "#/components/schemas/MetricsStoreKind", + "description": "The storage backend the runtime is **actually** using for metrics,\nafter reconciling the `monitoring.store` toggle with the server's\n`TEMPS_CLICKHOUSE_*` configuration. When `monitoring.store` is\n`click_house` but those env vars are not fully set, the runtime falls\nback to TimescaleDB \u2014 in that case this reports `timescale_db` even\nthough `monitoring.store` says `click_house`. The UI shows this as the\neffective backend and warns when it diverges from the configured store." + }, + "effective_observability_store": { + "$ref": "#/components/schemas/MetricsStoreKind", + "description": "Storage backend actually used for proxy logs, OTel spans, and OTel\nmetrics. OTel logs remain TimescaleDB-backed. Unlike resource metrics,\nthese domains switch to ClickHouse whenever the server-level ClickHouse\nconnection is configured; they do not use the monitoring store toggle." + }, + "external_url": { + "type": [ + "string", + "null" + ] + }, + "insecure_tls": { + "type": "boolean" + }, + "internal_url": { + "type": [ + "string", + "null" + ] + }, + "letsencrypt": { + "$ref": "#/components/schemas/LetsEncryptSettings" + }, + "monitored_services_count": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Number of enabled, running services the MetricsScraper currently\nincludes. Used for the lightweight storage estimate in the UI.", + "minimum": 0 + }, + "monitoring": { + "$ref": "#/components/schemas/MonitoringSettingsMasked" + }, + "multi_node": { + "$ref": "#/components/schemas/MultiNodeSettingsMasked" + }, + "observability_compression": { + "$ref": "#/components/schemas/ObservabilityCompressionSettings", + "description": "TimescaleDB compression delays for immutable proxy logs and OTel spans." + }, + "observability_retention": { + "$ref": "#/components/schemas/ObservabilityRetentionSettings", + "description": "Retention windows for raw proxy logs and OpenTelemetry data." + }, + "preview_domain": { + "type": "string" + }, + "preview_gateway": { + "$ref": "#/components/schemas/PreviewGatewaySettingsMasked" + }, + "rate_limiting": { + "$ref": "#/components/schemas/RateLimitSettings" + }, + "require_mfa_for_admins": { + "type": "boolean", + "description": "When enabled, Admin-role accounts without MFA enrolled are rejected\nat password login (bherila/temps#32). SSO/OIDC logins are unaffected." + }, + "screenshots": { + "$ref": "#/components/schemas/ScreenshotSettings" + }, + "security_headers": { + "$ref": "#/components/schemas/SecurityHeadersSettings" + }, + "setup_complete": { + "type": "boolean", + "description": "Whether `temps setup` has been run at least once. The web onboarding\nwizard checks this field on load and skips itself when true." + } + } + }, + "ApplyHostnameModeRequest": { + "type": "object", + "description": "Request to apply a hostname mode (recompute + optional DNS sync).", + "required": [ + "mode" + ], + "properties": { + "mode": { + "type": "string", + "description": "Target mode to apply: `\"standard\"` or `\"flat\"`." + }, + "sync_dns": { + "type": "boolean", + "description": "Also reconcile the provider's DNS zone for the affected hostnames." + } + } + }, + "ArchiveFlagResponse": { + "type": "object", + "required": [ + "key" + ], + "properties": { + "archived_at": { + "type": [ + "string", + "null" + ] + }, + "key": { + "type": "string" + } + } + }, + "ArchiveMode": { + "type": "string", + "enum": [ + "off", + "on", + "always", + "unknown" + ] + }, + "AssignRoleRequest": { + "type": "object", + "required": [ + "user_id", + "role_type" + ], + "properties": { + "role_type": { + "type": "string" + }, + "user_id": { + "type": "integer", + "format": "int32" + } + } + }, + "AttachScheduleServicesRequest": { + "type": "object", + "description": "Body for `POST /api/backups/schedules/{id}/services` \u2014 attach external\nservices to a backup schedule. Idempotent.", + "required": [ + "service_ids" + ], + "properties": { + "service_ids": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "description": "External service ids to attach. Duplicates are de-duplicated server-side." + } + } + }, + "AttachScheduleServicesResponse": { + "type": "object", + "description": "Response for `POST /api/backups/schedules/{id}/services`.", + "required": [ + "inserted", + "total_attached" + ], + "properties": { + "inserted": { + "type": "integer", + "format": "int64", + "description": "Number of rows actually inserted (excludes rows skipped by\n`ON CONFLICT DO NOTHING`).", + "minimum": 0 + }, + "total_attached": { + "type": "integer", + "description": "Total number of services now attached to the schedule.", + "minimum": 0 + } + } + }, + "AuditLogIpInfo": { + "type": "object", + "description": "IP address information in audit log", + "required": [ + "ip" + ], + "properties": { + "city": { + "type": [ + "string", + "null" + ], + "description": "City name", + "example": "San Francisco" + }, + "country": { + "type": [ + "string", + "null" + ], + "description": "Country code", + "example": "US" + }, + "ip": { + "type": "string", + "description": "IP address", + "example": "192.168.1.1" + }, + "latitude": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Latitude", + "example": 37.7749 + }, + "longitude": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Longitude", + "example": 122.4194 + } + } + }, + "AuditLogResponse": { + "type": "object", + "description": "Response type for audit log entries", + "required": [ + "id", + "operation_type", + "audit_date" + ], + "properties": { + "audit_date": { + "type": "integer", + "format": "int64", + "description": "When the action occurred", + "example": 11932193 + }, + "data": { + "description": "Additional context about the action" + }, + "id": { + "type": "integer", + "format": "int32", + "description": "Unique identifier for the audit log entry" + }, + "ip_address": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/AuditLogIpInfo", + "description": "IP address details" + } + ] + }, + "operation_type": { + "type": "string", + "description": "The type of action that was performed", + "example": "USER_LOGIN" + }, + "user": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/AuditLogUserInfo", + "description": "User details who performed the action" + } + ] + }, + "user_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "The user who performed the action (`null` when that account has\nsince been deleted; `data` retains the original actor context)" + } + } + }, + "AuditLogUserInfo": { + "type": "object", + "description": "User information in audit log", + "required": [ + "id", + "name", + "email" + ], + "properties": { + "email": { + "type": "string", + "description": "User's email", + "example": "john.doe@example.com" + }, + "id": { + "type": "integer", + "format": "int32", + "description": "User ID" + }, + "name": { + "type": "string", + "description": "User's name", + "example": "John Doe" + } + } + }, + "AuthFlavorDto": { + "type": "object", + "description": "One auth flavor surfaced to the UI. Mirrors `AuthFlavor` in the catalog\nbut without the seed-path / env-var fields the frontend doesn't need\n(those are server-side only \u2014 exposing them just bloats the response).", + "required": [ + "id", + "label", + "description", + "format" + ], + "properties": { + "description": { + "type": "string" + }, + "env_var": { + "type": [ + "string", + "null" + ], + "description": "For `api_key` format: the env var name that will be set inside the\nsandbox. Useful for showing the user \"we'll set OPENAI_API_KEY\" so\nthey know what their key controls." + }, + "format": { + "type": "string", + "description": "`api_key`, `oauth_token`, or `config_file` \u2014 drives which input UI\nthe settings page renders (single-line vs. multi-line textarea)." + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + } + } + }, + "AuthResponse": { + "type": "object", + "required": [ + "success", + "message", + "mfa_required" + ], + "properties": { + "message": { + "type": "string" + }, + "mfa_required": { + "type": "boolean" + }, + "success": { + "type": "boolean" + }, + "user_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + } + }, + "AuthStatusResponse": { + "type": "object", + "required": [ + "status" + ], + "properties": { + "cli_token": { + "type": [ + "string", + "null" + ] + }, + "status": { + "type": "string" + } + } + }, + "AuthTokenResponse": { + "type": "object", + "required": [ + "access_token", + "refresh_token", + "expires_at" + ], + "properties": { + "access_token": { + "type": "string" + }, + "expires_at": { + "type": "integer", + "format": "int64" + }, + "refresh_token": { + "type": "string" + } + } + }, + "AutoWatchParams": { + "type": "object", + "description": "Auto-watch (Watchdog-style) detector parameters (stub \u2014 not evaluated).", + "properties": { + "direction": { + "$ref": "#/components/schemas/Direction", + "description": "The engine self-tunes the band; the user supplies only the direction." + } + } + }, + "AutofixRunConfig": { + "type": "object", + "description": "User-chosen per-run options, persisted as JSON in `agent_runs.run_config`.\nEvery field is optional \u2014 unset fields fall back to the provider defaults\nin settings, then to built-in defaults.", + "properties": { + "branch": { + "type": [ + "string", + "null" + ], + "description": "Branch to clone instead of the project's main branch.", + "default": null + }, + "max_turns": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Per-run turn cap applied to every phase of this run. Only enforced\nfor CLIs with a turn flag (Claude Code); Codex/OpenCode run to\ncompletion. `None` uses the provider's per-phase defaults.", + "default": null + }, + "model": { + "type": [ + "string", + "null" + ], + "description": "Model id for the chosen provider. `None` uses the provider's saved\ndefault model, or the CLI's own default.", + "default": null + }, + "provider": { + "type": [ + "string", + "null" + ], + "description": "AI provider id (\"claude_cli\", \"codex_cli\", \"opencode\"). `None` uses\nthe platform default provider from agent sandbox settings.", + "default": null + } + } + }, + "AutofixerRunResponse": { + "type": "object", + "required": [ + "id", + "project_id", + "status", + "tokens_input", + "tokens_output", + "files_changed", + "created_at" + ], + "properties": { + "ai_model": { + "type": [ + "string", + "null" + ] + }, + "ai_output": { + "type": [ + "string", + "null" + ] + }, + "ai_provider": { + "type": [ + "string", + "null" + ], + "description": "AI provider slug this run executes with (e.g. claude_cli, codex_cli)." + }, + "analysis": { + "type": [ + "string", + "null" + ] + }, + "branch_name": { + "type": [ + "string", + "null" + ] + }, + "completed_at": { + "type": [ + "string", + "null" + ] + }, + "created_at": { + "type": "string" + }, + "error_message": { + "type": [ + "string", + "null" + ] + }, + "files_changed": { + "type": "integer", + "format": "int32" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "phase": { + "type": [ + "string", + "null" + ] + }, + "pr_number": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "pr_url": { + "type": [ + "string", + "null" + ] + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "run_config": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/AutofixRunConfig", + "description": "Per-run options the run was started with; used to prefill the\nretry / start-over dialog." + } + ] + }, + "started_at": { + "type": [ + "string", + "null" + ] + }, + "status": { + "type": "string" + }, + "tokens_input": { + "type": "integer", + "format": "int32" + }, + "tokens_output": { + "type": "integer", + "format": "int32" + }, + "trigger_source_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "user_context": { + "type": [ + "string", + "null" + ] + } + } + }, + "AutofixerRunWithLogsResponse": { + "type": "object", + "required": [ + "run", + "logs" + ], + "properties": { + "logs": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AgentRunLogResponse" + } + }, + "run": { + "$ref": "#/components/schemas/AutofixerRunResponse" + } + } + }, + "AvailableContainerInfo": { + "type": "object", + "description": "Available Docker container that can be imported as a service", + "required": [ + "container_id", + "container_name", + "image", + "version", + "service_type", + "is_running" + ], + "properties": { + "container_id": { + "type": "string", + "description": "Container ID or name", + "example": "abc123def456" + }, + "container_name": { + "type": "string", + "description": "Container display name", + "example": "my-postgres" + }, + "exposed_ports": { + "type": "array", + "items": { + "type": "integer", + "format": "int32", + "minimum": 0 + }, + "description": "Exposed ports (e.g., [5432] for PostgreSQL, [6379] for Redis)" + }, + "image": { + "type": "string", + "description": "Docker image name (e.g., \"gotempsh/postgres-walg:18-bookworm\")", + "example": "gotempsh/postgres-walg:18-bookworm" + }, + "is_running": { + "type": "boolean", + "description": "Whether the container is currently running", + "example": true + }, + "service_type": { + "$ref": "#/components/schemas/ServiceTypeRoute", + "description": "Service type this container represents" + }, + "version": { + "type": "string", + "description": "Extracted version from image", + "example": "18" + } + } + }, + "AvailablePermissions": { + "type": "object", + "description": "Response containing all available permissions for frontend validation", + "required": [ + "permissions", + "roles" + ], + "properties": { + "permissions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PermissionInfo" + }, + "description": "All available permissions in the system" + }, + "roles": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RoleInfo" + }, + "description": "All available roles" + } + } + }, + "BackupAlertListResponse": { + "type": "object", + "description": "Response body for the list-backup-alerts endpoint.", + "required": [ + "alerts" + ], + "properties": { + "alerts": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BackupAlertResponse" + }, + "description": "All currently open (unresolved) alerts, newest first." + } + } + }, + "BackupAlertResponse": { + "type": "object", + "description": "A single open backup alert surfaced in the UI banner.\n\nAlerts are auto-opened by the watcher and auto-resolved when the triggering\ncondition clears. No manual dismiss is required or supported.\n\nThe optional `schedule_s3_source_id` field is included so the UI can\ndeep-link an `overdue_schedule` alert to the S3 source detail page that\nhosts the schedule. `stalled_job` alerts no longer carry a deep-link\ntarget \u2014 the alert message text contains the backup id for display.", + "required": [ + "id", + "kind", + "severity", + "message", + "opened_at" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64", + "description": "Database id of the alert row." + }, + "kind": { + "type": "string", + "description": "`\"overdue_schedule\"` or `\"stalled_job\"`." + }, + "message": { + "type": "string", + "description": "Human-readable description of the alert condition." + }, + "opened_at": { + "type": "string", + "description": "RFC 3339 timestamp when the alert was opened.", + "example": "2026-05-15T10:00:00Z" + }, + "schedule_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "FK to `backup_schedules.id`. Set for `overdue_schedule` alerts." + }, + "schedule_name": { + "type": [ + "string", + "null" + ], + "description": "Human-readable name of the linked schedule, if applicable." + }, + "schedule_s3_source_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "FK to `backup_schedules.s3_source_id`. The UI uses this to deep-link\nthe alert to the S3 source detail page that hosts the schedule.\nSet for `overdue_schedule` alerts." + }, + "severity": { + "type": "string", + "description": "`\"warning\"` or `\"critical\"`." + } + } + }, + "BackupResponse": { + "type": "object", + "description": "Response type for backup", + "required": [ + "id", + "name", + "backup_id", + "backup_type", + "state", + "started_at", + "s3_source_id", + "s3_location", + "metadata", + "compression_type", + "created_by", + "tags" + ], + "properties": { + "attempts": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "How many times this job has been claimed and run. `null` for legacy\nbackups with no `backup_jobs` row." + }, + "backup_id": { + "type": "string" + }, + "backup_type": { + "type": "string" + }, + "checksum": { + "type": [ + "string", + "null" + ] + }, + "completed_at": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "compression_type": { + "type": "string" + }, + "created_by": { + "type": "integer", + "format": "int32" + }, + "current_step": { + "type": [ + "string", + "null" + ], + "description": "Name of the engine step currently executing (e.g., `\"walg_push\"`).\n`null` when no `backup_jobs` row exists for this backup (legacy rows\npre-dating ADR-014), or when the job has not yet completed its first step." + }, + "error_message": { + "type": [ + "string", + "null" + ] + }, + "expires_at": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "external_service": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/ExternalServiceSummary", + "description": "External service that owns this backup (Redis, Postgres, etc.).\n`null` for control-plane backups (the Temps server's own database)." + } + ] + }, + "file_count": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "live_size_bytes": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Best-effort partial size while a backup is still running, computed\nby listing the S3 prefix. Null when the backup is finished\n(`size_bytes` is authoritative in that case)." + }, + "max_attempts": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Maximum attempts before the job is permanently failed. `null` for\nlegacy backups." + }, + "max_runtime_secs": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Resolved wall-clock timeout for this backup job (seconds). `null` for\nlegacy backups. Derived from the three-tier resolution order:\ncaller override \u2192 schedule override \u2192 engine default." + }, + "metadata": {}, + "name": { + "type": "string" + }, + "s3_location": { + "type": "string" + }, + "s3_source_id": { + "type": "integer", + "format": "int32" + }, + "schedule_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "size_bytes": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Final size of the backup once completed. Null while running." + }, + "started_at": { + "type": "integer", + "format": "int64" + }, + "state": { + "type": "string" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "BackupScheduleResponse": { + "type": "object", + "description": "Response type for backup schedule", + "required": [ + "id", + "name", + "backup_type", + "retention_period", + "s3_source_id", + "schedule_expression", + "enabled", + "created_at", + "updated_at", + "tags", + "target_all_services", + "include_control_plane" + ], + "properties": { + "backup_type": { + "type": "string" + }, + "created_at": { + "type": "integer", + "format": "int64" + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "enabled": { + "type": "boolean" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "include_control_plane": { + "type": "boolean", + "description": "When `true`, every run also produces a `control_plane` backup\n(Temps's own Postgres). When `false`, only the external service\nfan-out happens." + }, + "last_run": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "max_runtime_secs": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Per-schedule wall-clock timeout override for backup jobs (seconds).\n`null` means the engine-family default is used. See\n`temps_backup_core::timeouts::default_max_runtime_secs`." + }, + "name": { + "type": "string" + }, + "next_run": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "retention_period": { + "type": "integer", + "format": "int32" + }, + "s3_source_id": { + "type": "integer", + "format": "int32" + }, + "schedule_expression": { + "type": "string", + "example": "0 0 * * *" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + } + }, + "target_all_services": { + "type": "boolean", + "description": "When `true`, the schedule auto-includes every external service on\nthe host (and any future ones). When `false`, the schedule only\ntargets services attached via `backup_schedule_services`." + }, + "updated_at": { + "type": "integer", + "format": "int64" + } + } + }, + "BitbucketAuthInput": { + "oneOf": [ + { + "type": "object", + "description": "Personal / Workspace / Repository Access Token.", + "required": [ + "token", + "type" + ], + "properties": { + "token": { + "type": "string", + "description": "The Bitbucket access token value." + }, + "type": { + "type": "string", + "enum": [ + "access_token" + ] + } + } + }, + { + "type": "object", + "description": "HTTP Basic / App Password authentication.", + "required": [ + "username", + "password", + "type" + ], + "properties": { + "password": { + "type": "string", + "description": "App password generated in Bitbucket security settings." + }, + "type": { + "type": "string", + "enum": [ + "app_password" + ] + }, + "username": { + "type": "string", + "description": "Bitbucket account username." + } + } + } + ], + "description": "Authentication input for a Bitbucket Cloud provider. Use `access_token` for\na Repository or Workspace Access Token (PAT), or `username` + `app_password`\nfor App Password (HTTP Basic) authentication." + }, + "BlobResponse": { + "type": "object", + "description": "Response after uploading a blob", + "required": [ + "url", + "pathname", + "contentType", + "size", + "uploadedAt" + ], + "properties": { + "contentType": { + "type": "string", + "description": "Content type of the blob", + "example": "image/png" + }, + "pathname": { + "type": "string", + "description": "Original pathname", + "example": "images/avatar-abc123.png" + }, + "size": { + "type": "integer", + "format": "int64", + "description": "Size in bytes", + "example": 12345 + }, + "uploadedAt": { + "type": "string", + "format": "date-time", + "description": "Upload timestamp", + "example": "2025-01-03T12:00:00Z" + }, + "url": { + "type": "string", + "description": "URL path to access the blob", + "example": "/api/blob/123/images/avatar-abc123.png" + } + } + }, + "BlobStatusResponse": { + "type": "object", + "description": "Response for Blob service status", + "required": [ + "enabled", + "healthy" + ], + "properties": { + "docker_image": { + "type": [ + "string", + "null" + ], + "description": "Docker image being used", + "example": "ghcr.io/rustfs/rustfs:0.5.0" + }, + "enabled": { + "type": "boolean", + "description": "Whether the Blob service is enabled", + "example": true + }, + "healthy": { + "type": "boolean", + "description": "Whether the service is healthy", + "example": true + }, + "version": { + "type": [ + "string", + "null" + ], + "description": "Current version (if running)", + "example": "0.5.0" + } + } + }, + "BranchInfo": { + "type": "object", + "required": [ + "name", + "commit_sha", + "protected" + ], + "properties": { + "commit_sha": { + "type": "string" + }, + "name": { + "type": "string" + }, + "protected": { + "type": "boolean" + } + } + }, + "BranchListResponse": { + "type": "object", + "required": [ + "branches" + ], + "properties": { + "branches": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BranchInfo" + } + } + } + }, + "BrowserCount": { + "type": "object", + "required": [ + "browser", + "count", + "percentage" + ], + "properties": { + "browser": { + "type": "string" + }, + "count": { + "type": "integer", + "format": "int64" + }, + "percentage": { + "type": "number", + "format": "double" + } + } + }, + "BrowsersQuery": { + "type": "object", + "required": [ + "start_date", + "end_date", + "project_id" + ], + "properties": { + "end_date": { + "type": "string", + "format": "date-time" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "limit": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "start_date": { + "type": "string", + "format": "date-time" + } + } + }, + "BuildConfiguration": { + "type": "object", + "description": "Build configuration (for building images from source)", + "required": [ + "context", + "args" + ], + "properties": { + "args": { + "type": "object", + "description": "Build arguments", + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + } + }, + "context": { + "type": "string", + "description": "Build context (Dockerfile path or buildpack)" + }, + "dockerfile": { + "type": [ + "string", + "null" + ], + "description": "Dockerfile path (relative to context)" + }, + "target": { + "type": [ + "string", + "null" + ], + "description": "Target stage (for multi-stage builds)" + } + } + }, + "BuildLimitsSettings": { + "type": "object", + "description": "Control-plane build resource limits.\n\nCaps how many builds run concurrently AND how much CPU/memory each build\nis allowed to consume. A single global semaphore in the deployer crate\ngates every `DockerRuntime::build_image` call to `max_concurrent`. When\nthe semaphore is full, additional builds queue and wait \u2014 they do not\nfail. Per-build CPU/memory caps are forwarded to Docker via\n`BuildImageOptions { memory, cpuquota, cpuperiod }`.\n\n`cpu_limit_cores = 0.0` or `memory_limit_mb = 0` means \"no explicit cap\"\n\u2014 fall back to the legacy 50%-of-host heuristic for backwards\ncompatibility with operators who never visit the settings page.", + "properties": { + "cpu_limit_cores": { + "type": "number", + "format": "float", + "description": "CPU cores allowed per build (float, e.g. 2.0 = 2 cores, 0.5 = half\na core). 0 means \"use the legacy 50%-of-host default\".", + "default": 0.0, + "example": 2.0, + "minimum": 0 + }, + "max_concurrent": { + "type": "integer", + "format": "int32", + "description": "Maximum number of `docker build` operations allowed to run at the\nsame time on the control plane. Additional builds queue. Min 1.", + "default": 2, + "example": 2, + "minimum": 1 + }, + "memory_limit_mb": { + "type": "integer", + "format": "int32", + "description": "Memory allowed per build, in megabytes. 0 means \"use the legacy\n50%-of-host default\". Docker enforces this as a hard cap \u2014 builds\nthat exceed it OOM-kill.", + "default": 0, + "example": 2048, + "minimum": 0 + } + } + }, + "CancelBackupResponse": { + "type": "object", + "description": "Response body for cancel endpoints.", + "required": [ + "cancelled" + ], + "properties": { + "cancelled": { + "type": "integer", + "format": "int64", + "description": "Number of rows that were actually flipped to `failed`. `0` is a valid\nsuccess and means the backup was already terminal \u2014 the call is\nidempotent.", + "minimum": 0 + } + } + }, + "CertStatusResponse": { + "type": "object", + "description": "Current on-demand cert status for a single hostname (ADR-018 \u00a75). Backs\n`GET /domains/by-host/{hostname}/cert-status`.", + "required": [ + "hostname" + ], + "properties": { + "backoff_until": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "On-demand negative-cache deadline (epoch millis), when in backoff." + }, + "hostname": { + "type": "string", + "description": "SNI hostname." + }, + "last_attempt": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/OnDemandCertAttemptResponse", + "description": "The most recent on-demand issuance attempt for this hostname, if any." + } + ] + }, + "status": { + "type": [ + "string", + "null" + ], + "description": "Current cert lifecycle status from the `domains` row, when one exists." + } + } + }, + "ChallengeConfig": { + "type": "object", + "description": "Challenge configuration (future feature)\nFor CAPTCHA, JS challenges, proof-of-work, etc.", + "required": [ + "challengeType", + "difficulty" + ], + "properties": { + "challengeType": { + "type": "string", + "description": "Challenge type: \"captcha\", \"js_challenge\", \"proof_of_work\"" + }, + "difficulty": { + "type": "integer", + "format": "int32", + "description": "Challenge difficulty level (1-10)", + "minimum": 0 + }, + "protectedPaths": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Paths that require challenges" + } + } + }, + "ChallengeError": { + "type": "object", + "required": [ + "type", + "detail", + "status" + ], + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error description" + }, + "status": { + "type": "integer", + "format": "int32", + "description": "HTTP status code" + }, + "type": { + "type": "string", + "description": "Error type (e.g., \"urn:ietf:params:acme:error:unauthorized\")" + } + } + }, + "ChallengeValidationStatus": { + "type": "object", + "required": [ + "type", + "url", + "status", + "token" + ], + "properties": { + "error": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/ChallengeError", + "description": "Error details if validation failed" + } + ] + }, + "status": { + "type": "string", + "description": "Challenge status (e.g., \"pending\", \"valid\", \"invalid\")" + }, + "token": { + "type": "string", + "description": "Challenge token" + }, + "type": { + "type": "string", + "description": "Challenge type (e.g., \"dns-01\", \"http-01\")" + }, + "url": { + "type": "string", + "description": "Challenge validation URL" + }, + "validated": { + "type": [ + "string", + "null" + ], + "description": "When the challenge was validated (if successful)" + } + } + }, + "ChangePasswordRequest": { + "type": "object", + "required": [ + "current_password", + "new_password" + ], + "properties": { + "current_password": { + "type": "string", + "example": "current_password_value" + }, + "mfa_code": { + "type": [ + "string", + "null" + ], + "description": "TOTP code (or recovery code). Required iff the user has MFA enabled.", + "example": "123456" + }, + "new_password": { + "type": "string", + "example": "new_password_value" + }, + "revoke_other_sessions": { + "type": "boolean", + "description": "When true, every session OTHER than the one making this request is\nrevoked. Defaults to false; the UI surfaces this as a checkbox." + } + } + }, + "ChangeProjectSourceRequest": { + "type": "object", + "description": "Change a project's source type to a Git-less type (docker_image /\nstatic_files / manual). Switching TO `git` is done via the Git settings\nendpoint (which also supplies the repository + provider connection).", + "required": [ + "source_type" + ], + "properties": { + "source_type": { + "$ref": "#/components/schemas/SourceType" + } + } + }, + "ChatCompletionChoice": { + "type": "object", + "required": [ + "index", + "message" + ], + "properties": { + "finish_reason": { + "type": [ + "string", + "null" + ] + }, + "index": { + "type": "integer", + "format": "int32" + }, + "message": { + "$ref": "#/components/schemas/ChatMessage" + } + } + }, + "ChatCompletionRequest": { + "allOf": [ + { + "type": [ + "object", + "null" + ], + "description": "Tolerates extra SDK fields (stream_options, logprobs, etc.)", + "additionalProperties": {}, + "propertyNames": { + "type": "string" + } + }, + { + "type": "object", + "required": [ + "model", + "messages" + ], + "properties": { + "frequency_penalty": { + "type": [ + "number", + "null" + ], + "format": "double" + }, + "max_tokens": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "messages": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ChatMessage" + } + }, + "model": { + "type": "string" + }, + "n": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "presence_penalty": { + "type": [ + "number", + "null" + ], + "format": "double" + }, + "response_format": {}, + "seed": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "stop": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/StopSequence" + } + ] + }, + "stream": { + "type": "boolean" + }, + "temperature": { + "type": [ + "number", + "null" + ], + "format": "double" + }, + "tool_choice": {}, + "tools": { + "type": [ + "array", + "null" + ], + "items": {} + }, + "top_p": { + "type": [ + "number", + "null" + ], + "format": "double" + }, + "user": { + "type": [ + "string", + "null" + ] + } + } + } + ], + "description": "OpenAI-compatible chat completion request.\nUses `deny_unknown_fields = false` (serde default) so that SDK-specific\nfields like `stream_options`, `logprobs`, `top_logprobs`, `logit_bias`,\n`parallel_tool_calls`, etc. are silently accepted without breaking." + }, + "ChatCompletionResponse": { + "type": "object", + "required": [ + "id", + "object", + "created", + "model", + "choices" + ], + "properties": { + "choices": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ChatCompletionChoice" + } + }, + "created": { + "type": "integer", + "format": "int64" + }, + "id": { + "type": "string" + }, + "model": { + "type": "string" + }, + "object": { + "type": "string" + }, + "usage": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/UsageInfo" + } + ] + } + } + }, + "ChatMessage": { + "type": "object", + "required": [ + "role" + ], + "properties": { + "content": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/MessageContent" + } + ] + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "role": { + "type": "string" + }, + "tool_call_id": { + "type": [ + "string", + "null" + ] + }, + "tool_calls": { + "type": [ + "array", + "null" + ], + "items": {} + } + } + }, + "ChatReadinessResponse": { + "type": "object", + "description": "What still has to be true before an AI chat can run a turn in this project.\n\nThe three gates are independent and fail for different reasons with different\nfixes, so they are reported separately rather than collapsed into one boolean:\nan instance admin configures a provider (instance-wide), while the two toggles\nare per-project. Collapsing them would leave the user with \"AI unavailable\"\nand no idea which of three places to go.", + "required": [ + "ai_configured", + "chat_enabled", + "write_actions_enabled" + ], + "properties": { + "ai_configured": { + "type": "boolean", + "description": "An AI provider is configured on this instance. Fixed in\nSettings \u2192 AI Providers; instance-wide, not per project." + }, + "chat_enabled": { + "type": "boolean", + "description": "The per-project read-only chat toggle is on (the default)." + }, + "write_actions_enabled": { + "type": "boolean", + "description": "The per-project write-actions opt-in is on. Required for any flow where\nthe assistant *proposes* changes; irrelevant for read-only questions." + } + } + }, + "ChildBackupEntryResponse": { + "type": "object", + "description": "A single child backup entry in the `GET /backups/{id}/children` response.\n\nEach entry corresponds to one `external_service_backups` row joined with\n`external_services`, providing service metadata without a second request.", + "required": [ + "id", + "service_id", + "service_name", + "service_type", + "state", + "backup_type", + "started_at", + "s3_location", + "compression_type" + ], + "properties": { + "backup_type": { + "type": "string", + "description": "Backup variant (e.g. \"full\", \"incremental\")." + }, + "compression_type": { + "type": "string", + "description": "Compression algorithm used (e.g. \"gzip\", \"lz4\")." + }, + "error_message": { + "type": [ + "string", + "null" + ], + "description": "Engine-reported error message when `state = \"failed\"`." + }, + "finished_at": { + "type": [ + "string", + "null" + ], + "description": "When the child backup finished, if known.", + "example": "2025-01-15T14:35:00.456Z" + }, + "id": { + "type": "integer", + "format": "int32", + "description": "Row ID from `external_service_backups`." + }, + "s3_location": { + "type": "string", + "description": "Object key or `s3://` URL where the backup data lives." + }, + "service_id": { + "type": "integer", + "format": "int32", + "description": "FK to `external_services.id`." + }, + "service_name": { + "type": "string", + "description": "Human-readable name of the external service (e.g. \"redis-prod\")." + }, + "service_type": { + "type": "string", + "description": "Service type string (e.g. \"postgres\", \"redis\", \"mongodb\", \"s3\").", + "example": "postgres" + }, + "size_bytes": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Size of the child backup in bytes, if available." + }, + "started_at": { + "type": "string", + "description": "When the child backup started (RFC 3339).", + "example": "2025-01-15T14:30:00.123Z" + }, + "state": { + "type": "string", + "description": "Current state: \"pending\" | \"running\" | \"completed\" | \"failed\"." + } + } + }, + "ChildBackupListResponse": { + "type": "object", + "description": "Response body for `GET /backups/{id}/children`.\n\nReturns an empty `children` list (not 404) when the parent backup has no\nchild records (e.g. control-plane backups).", + "required": [ + "children" + ], + "properties": { + "children": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ChildBackupEntryResponse" + }, + "description": "Zero or more child backup entries ordered by `external_service_backups.id` ASC." + } + } + }, + "CleanupExpiredBackupsRequest": { + "type": "object", + "properties": { + "expected_backup_ids": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + }, + "description": "Exact candidates returned by the dry run. Execution fails if the\nretention selection has changed since preview." + } + } + }, + "CliDeviceApproveRequest": { + "type": "object", + "required": [ + "user_code" + ], + "properties": { + "user_code": { + "type": "string" + } + } + }, + "CliDeviceApproveResponse": { + "type": "object", + "required": [ + "user_code", + "status" + ], + "properties": { + "status": { + "type": "string" + }, + "user_code": { + "type": "string" + } + } + }, + "CliDeviceLookupResponse": { + "type": "object", + "required": [ + "user_code", + "status", + "expires_at" + ], + "properties": { + "client_name": { + "type": [ + "string", + "null" + ] + }, + "expires_at": { + "type": "string", + "format": "date-time" + }, + "requested_ip": { + "type": [ + "string", + "null" + ] + }, + "status": { + "type": "string", + "description": "`pending` | `approved` | `denied` | `expired`." + }, + "user_code": { + "type": "string" + } + } + }, + "CliDevicePollRequest": { + "type": "object", + "required": [ + "device_code" + ], + "properties": { + "device_code": { + "type": "string" + } + } + }, + "CliDevicePollResponse": { + "oneOf": [ + { + "type": "object", + "description": "Still waiting on the user to approve in the browser.", + "required": [ + "status" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "authorization_pending" + ] + } + } + }, + { + "type": "object", + "description": "CLI is polling faster than the server-suggested interval.", + "required": [ + "status" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "slow_down" + ] + } + } + }, + { + "type": "object", + "description": "User denied the request in the browser.", + "required": [ + "status" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "access_denied" + ] + } + } + }, + { + "type": "object", + "description": "The session has expired without approval.", + "required": [ + "status" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "expired_token" + ] + } + } + }, + { + "type": "object", + "description": "The session was approved; this is the only response that carries\nthe API key. The key is returned exactly once and then cleared\nfrom the session row.", + "required": [ + "user_id", + "email", + "role", + "api_key", + "key_prefix", + "status" + ], + "properties": { + "api_key": { + "type": "string" + }, + "email": { + "type": "string" + }, + "expires_at": { + "type": [ + "string", + "null" + ], + "format": "date-time" + }, + "key_prefix": { + "type": "string" + }, + "role": { + "type": "string" + }, + "status": { + "type": "string", + "enum": [ + "approved" + ] + }, + "user_id": { + "type": "integer", + "format": "int32" + } + } + } + ] + }, + "CliDeviceStartRequest": { + "type": "object", + "properties": { + "client_name": { + "type": [ + "string", + "null" + ], + "description": "Friendly hostname / client identifier shown in the browser approval\nscreen. Sanitized before display.", + "example": "dviejo-mac.local" + } + } + }, + "CliDeviceStartResponse": { + "type": "object", + "required": [ + "device_code", + "user_code", + "verification_uri", + "verification_uri_complete", + "expires_in", + "interval" + ], + "properties": { + "device_code": { + "type": "string", + "description": "Opaque secret the CLI polls with. Never display to a human." + }, + "expires_in": { + "type": "integer", + "format": "int64", + "description": "Seconds until the device_code expires." + }, + "interval": { + "type": "integer", + "format": "int64", + "description": "Suggested polling interval, in seconds." + }, + "user_code": { + "type": "string", + "description": "Short human-readable code the user types into the browser.", + "example": "ABCD-1234" + }, + "verification_uri": { + "type": "string", + "description": "Base verification URL \u2014 the CLI may display this when the\npre-filled URL is too long to be useful.", + "example": "https://temps.example.com/cli-login" + }, + "verification_uri_complete": { + "type": "string", + "description": "`verification_uri` with `user_code` pre-filled. Open this directly.", + "example": "https://temps.example.com/cli-login/ABCD-1234" + } + } + }, + "CliLoginRequest": { + "type": "object", + "required": [ + "username", + "password" + ], + "properties": { + "password": { + "type": "string" + }, + "username": { + "type": "string" + } + } + }, + "CloudProvider": { + "type": "string", + "description": "Cloud provider detected from node metadata", + "enum": [ + "aws", + "gcp", + "azure", + "hetzner", + "digitalocean", + "other" + ] + }, + "CloudflareConfig": { + "type": "object", + "description": "Configuration for a Cloudflare Email Sending notification provider.\n\nNotifications are delivered through Cloudflare's transactional Email Sending\nAPI. Only the account, token, sender and recipients are configured here \u2014\nsubject and body are derived from each notification.", + "required": [ + "account_id", + "api_token", + "from_address", + "to_addresses" + ], + "properties": { + "account_id": { + "type": "string", + "description": "Cloudflare account id that owns the Email Sending configuration.", + "example": "023e105f4ecef8ad9ca31a8372d0c353" + }, + "api_token": { + "type": "string", + "description": "Cloudflare API token with the Email Sending permission. Encrypted at\nrest and masked in normal API responses." + }, + "from_address": { + "type": "string", + "description": "Verified sender address (must belong to a domain enabled for Cloudflare\nEmail Sending).", + "example": "welcome@infracf.example.com" + }, + "from_name": { + "type": [ + "string", + "null" + ], + "description": "Optional human-friendly sender name shown in the recipient's inbox." + }, + "to_addresses": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Recipients that should receive the notification." + } + } + }, + "ClusterCapacity": { + "type": "object", + "description": "Total cluster capacity (sum of node allocatable resources)", + "required": [ + "node_count", + "cpu_millis", + "memory_mb" + ], + "properties": { + "cpu_millis": { + "type": "integer", + "format": "int64", + "description": "Total allocatable CPU in millicores" + }, + "memory_mb": { + "type": "integer", + "format": "int64", + "description": "Total allocatable memory in MB" + }, + "node_count": { + "type": "integer", + "description": "Number of nodes", + "minimum": 0 + } + } + }, + "ClusterDnsSettings": { + "type": "object", + "description": "Cluster-DNS resolver settings (ADR-024, experimental beta).\n\nWhen `enabled`, the Temps control plane starts a Hickory DNS resolver and\ninjects it as the first nameserver into every deployed container via\n`HostConfig.Dns` \u2014 giving containers the ability to resolve `*.temps.local`\nFQDNs for service-to-service communication. Worker nodes pick this flag up\nfrom the `/api/internal/nodes/{id}/network/peers` wire response and gate\ntheir own per-node resolver the same way.\n\n**Default: `false` (disabled).**\n\nWhy disabled by default: a production incident showed that when the injected\nHickory resolver was slow or transiently unresponsive for a non-`*.temps.local`\n(external) hostname, glibc's resolver cycled through all three nameservers\n(`172.20.0.1`, `1.1.1.1`, `8.8.8.8`) at ~5 s timeout \u00d7 2 attempts each,\ncausing 22\u201327 s delays for outbound TCP connections. Disabling the injection\nrestores Docker's embedded DNS as the sole resolver, eliminating that failure\nmode. Operators running single/multi-node installs that depend on\n`*.temps.local` resolution must explicitly opt in by setting `enabled: true`.\n\n`bool` defaults to `false` in Rust and JSON (`#[serde(default)]`), so the\nsafe-off behaviour is automatic for new installs and legacy settings rows.", + "properties": { + "enabled": { + "type": "boolean", + "description": "Master switch. When `false` (default), no custom DNS is injected into\ncontainers \u2014 they use Docker's embedded DNS which forwards to the host's\nown `resolv.conf`. When `true`, the control-plane Hickory resolver is\nstarted and its bridge IP is injected as the first nameserver so\n`*.temps.local` FQDNs resolve inside containers.", + "default": false, + "example": false + } + } + }, + "ClusterHealthReportResponse": { + "type": "object", + "description": "Response body for `GET /external-services/{id}/cluster-health`.", + "required": [ + "checked_at", + "monitor_response_ms", + "members" + ], + "properties": { + "checked_at": { + "type": "string", + "description": "ISO-8601 wall-clock when the report was generated.", + "example": "2025-10-12T12:15:47.609192Z" + }, + "members": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ClusterMemberHealthResponse" + } + }, + "monitor_error": { + "type": [ + "string", + "null" + ], + "description": "Set when the monitor itself was unreachable. UI shows a banner." + }, + "monitor_response_ms": { + "type": "integer", + "format": "int64", + "description": "Round-trip to query the monitor (ms)." + } + } + }, + "ClusterMemberHealthResponse": { + "type": "object", + "description": "One row in the cluster Members table \u2014 see `GET /external-services/{id}/cluster-health`.", + "required": [ + "nodename", + "nodehost", + "nodeport", + "reported_state", + "goal_state", + "health", + "seconds_since_report", + "candidate_priority", + "replication_quorum" + ], + "properties": { + "candidate_priority": { + "type": "integer", + "format": "int32" + }, + "goal_state": { + "type": "string", + "description": "What the monitor *wants* the node to be. Differs from\n`reported_state` mid-transition (failover, demotion, etc.)." + }, + "health": { + "type": "integer", + "format": "int32", + "description": "pg_auto_failover liveness signal: `1` healthy, `0` unknown\n(no recent report), `-1` unhealthy." + }, + "nodehost": { + "type": "string" + }, + "nodename": { + "type": "string" + }, + "nodeport": { + "type": "integer", + "format": "int32" + }, + "replay_lag_ms": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "`replay_lag` from `pg_stat_replication`, in milliseconds." + }, + "replication_quorum": { + "type": "boolean" + }, + "reported_state": { + "type": "string", + "description": "What the node *last told the monitor* it was. Stale during outages." + }, + "seconds_since_report": { + "type": "integer", + "format": "int64", + "description": "Wall-clock seconds since the node last reported in." + }, + "sync_state": { + "type": [ + "string", + "null" + ], + "description": "`sync` / `quorum` / `async` for secondaries; `null` for the primary." + } + } + }, + "ClusterMemberRequest": { + "type": "object", + "description": "Request spec for a single cluster member.", + "required": [ + "role" + ], + "properties": { + "node_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Target worker node ID. Omit or null to run on the control plane." + }, + "role": { + "type": "string", + "description": "Service-type-specific role (e.g., \"monitor\", \"primary\", \"replica\")", + "example": "primary" + } + } + }, + "CmdBody": { + "type": "object", + "required": [ + "command" + ], + "properties": { + "args": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Arguments to pass to the binary. Defaults to empty." + }, + "command": { + "type": "string", + "description": "Binary name (argv[0]) \u2014 e.g. `\"ls\"`, `\"node\"`. The SDK sends this\nseparately from `args`." + }, + "cwd": { + "type": [ + "string", + "null" + ], + "description": "Working directory override." + }, + "env": { + "type": "object", + "description": "Extra env vars.", + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + } + }, + "sudo": { + "type": "boolean", + "description": "When true, the SDK runs the command privileged. We ignore it today\n\u2014 the underlying provider always runs as the sandbox's own user." + }, + "wait": { + "type": "boolean", + "description": "When true, the response is an `application/x-ndjson` stream where\nthe first line is the running-command envelope and the second line\nis the finished-command envelope with `exitCode`." + } + } + }, + "CmdInner": { + "type": "object", + "description": "Inner `command` object \u2014 matches the SDK's zod validator exactly.\n`exitCode` is `null` until the command terminates; `startedAt` is Unix\nepoch milliseconds.", + "required": [ + "id", + "name", + "args", + "cwd", + "sandboxId", + "startedAt" + ], + "properties": { + "args": { + "type": "array", + "items": { + "type": "string" + } + }, + "cwd": { + "type": "string" + }, + "exitCode": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "sandboxId": { + "type": "string" + }, + "startedAt": { + "type": "integer", + "format": "int64" + } + } + }, + "CmdKillBody": { + "type": "object", + "description": "SDK-shaped kill body. The SDK sends `{signal: AbortSignal}` but only\nuses the signal for HTTP request abortion client-side; there's no\nsignal name on the wire.", + "properties": { + "force": { + "type": "boolean", + "description": "Optional: when true, SIGKILL instead of SIGTERM." + } + } + }, + "CmdResponse": { + "type": "object", + "description": "`@vercel/sandbox` envelope: `{ command: {...} }`.", + "required": [ + "command" + ], + "properties": { + "command": { + "$ref": "#/components/schemas/CmdInner" + } + } + }, + "CommitExistsResponse": { + "type": "object", + "required": [ + "exists" + ], + "properties": { + "commit": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/CommitInfo", + "description": "Commit metadata when the requested SHA exists." + } + ] + }, + "commit_sha": { + "type": [ + "string", + "null" + ] + }, + "exists": { + "type": "boolean" + } + } + }, + "CommitInfo": { + "type": "object", + "required": [ + "sha", + "message", + "author", + "author_email", + "date" + ], + "properties": { + "author": { + "type": "string", + "description": "Author name" + }, + "author_email": { + "type": "string", + "description": "Author email" + }, + "date": { + "type": "string", + "format": "date-time", + "description": "Commit date in ISO 8601 format", + "example": "2025-10-12T12:15:47.609192Z" + }, + "message": { + "type": "string", + "description": "Commit message" + }, + "sha": { + "type": "string", + "description": "Commit SHA hash" + } + } + }, + "CommitListResponse": { + "type": "object", + "required": [ + "commits" + ], + "properties": { + "commits": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CommitInfo" + } + } + } + }, + "Comparator": { + "type": "string", + "description": "Comparator for static/forecast threshold detectors. Serializes to the\nkeyword forms `gt|gte|lt|lte` (NOT the SQL operators used by\n`temps-monitoring::compare`).", + "enum": [ + "gt", + "gte", + "lt", + "lte" + ] + }, + "ComposePublicPort": { + "type": "object", + "description": "A port that should be exposed publicly through the proxy for a compose service.", + "required": [ + "service", + "port" + ], + "properties": { + "port": { + "type": "integer", + "format": "int32", + "description": "Container port to expose (e.g. 8123)", + "minimum": 0 + }, + "service": { + "type": "string", + "description": "Compose service name (e.g. \"web\", \"clickhouse\")" + } + } + }, + "ConnectionListQuery": { + "type": "object", + "properties": { + "direction": { + "type": [ + "string", + "null" + ] + }, + "page": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + }, + "per_page": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + }, + "sort": { + "type": [ + "string", + "null" + ] + } + } + }, + "ConnectionListResponse": { + "type": "object", + "required": [ + "connections", + "total_count", + "page", + "per_page" + ], + "properties": { + "connections": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ConnectionResponse" + } + }, + "page": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "per_page": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "total_count": { + "type": "integer", + "minimum": 0 + } + } + }, + "ConnectionResponse": { + "type": "object", + "required": [ + "id", + "provider_id", + "account_name", + "account_type", + "is_active", + "is_expired", + "syncing", + "synced_repository_count", + "health_status", + "consecutive_health_failures", + "created_at", + "updated_at" + ], + "properties": { + "account_name": { + "type": "string" + }, + "account_type": { + "type": "string" + }, + "consecutive_health_failures": { + "type": "integer", + "format": "int32" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "health_message": { + "type": [ + "string", + "null" + ], + "description": "Human-readable reason when health_status is \"unhealthy\"; null otherwise." + }, + "health_status": { + "type": "string", + "description": "Current health status: \"healthy\", \"unhealthy\", or \"unknown\"." + }, + "id": { + "type": "integer", + "format": "int32" + }, + "installation_id": { + "type": [ + "string", + "null" + ] + }, + "is_active": { + "type": "boolean" + }, + "is_expired": { + "type": "boolean" + }, + "last_health_check_at": { + "type": [ + "string", + "null" + ], + "format": "date-time" + }, + "last_synced_at": { + "type": [ + "string", + "null" + ], + "format": "date-time" + }, + "provider_id": { + "type": "integer", + "format": "int32" + }, + "synced_repository_count": { + "type": "integer", + "format": "int32", + "description": "Running count of repositories persisted by the current (or most\nrecent) sync. Resets to 0 when a new sync begins; useful for showing\nlive progress on large syncs." + }, + "syncing": { + "type": "boolean" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "user_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + } + }, + "ConnectionTestResult": { + "type": "object", + "description": "Connection test result", + "required": [ + "success", + "message" + ], + "properties": { + "message": { + "type": "string" + }, + "success": { + "type": "boolean" + } + } + }, + "ConsoleEventPayload": { + "type": "object", + "description": "Payload for server-side event ingestion via the console API.\n\nThe app backend reads the encrypted `_temps_visitor_id` and `_temps_sid`\ncookie values from the user's request and forwards them here.\nTemps decrypts them server-side to resolve visitor/session identity.", + "required": [ + "event_name", + "environment_id", + "deployment_id" + ], + "properties": { + "deployment_id": { + "type": "integer", + "format": "int32", + "description": "Deployment ID to attribute the event to" + }, + "environment_id": { + "type": "integer", + "format": "int32", + "description": "Environment ID to attribute the event to" + }, + "event_data": { + "description": "Arbitrary JSON event data" + }, + "event_name": { + "type": "string", + "description": "Event name (e.g. \"purchase\", \"signup\", custom event names)" + }, + "request_path": { + "type": "string", + "description": "Page path context (defaults to \"/\")" + }, + "request_query": { + "type": "string", + "description": "Query string context" + }, + "session_id": { + "type": [ + "string", + "null" + ], + "description": "Encrypted `_temps_sid` cookie value from the user's browser" + }, + "visitor_id": { + "type": [ + "string", + "null" + ], + "description": "Encrypted `_temps_visitor_id` cookie value from the user's browser" + } + } + }, + "ContainerActionResponse": { + "type": "object", + "description": "Response indicating success of container state change", + "required": [ + "container_id", + "container_name", + "action", + "status", + "message" + ], + "properties": { + "action": { + "type": "string" + }, + "container_id": { + "type": "string" + }, + "container_name": { + "type": "string" + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "ContainerDetailResponse": { + "type": "object", + "description": "Detailed container information with environment variables and metrics", + "required": [ + "id", + "container_id", + "container_name", + "image_name", + "status", + "deployment_id", + "created_at", + "deployed_at", + "container_port", + "environment_variables" + ], + "properties": { + "container_id": { + "type": "string" + }, + "container_name": { + "type": "string" + }, + "container_port": { + "type": "integer", + "format": "int32", + "description": "Port inside the container" + }, + "cpu_limit_cores": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "CPU limit in whole cores (e.g. 1.0). None when no limit is configured." + }, + "created_at": { + "type": "string", + "example": "2025-10-12T12:15:47.609192Z" + }, + "deployed_at": { + "type": "string", + "example": "2025-10-12T12:15:47.609192Z" + }, + "deployment_id": { + "type": "integer", + "format": "int32" + }, + "environment_variables": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EnvVarResponse" + }, + "description": "Environment variables (sensitive values masked)" + }, + "error_message": { + "type": [ + "string", + "null" + ], + "description": "Free-form error string from Docker's container state on exit." + }, + "exit_code": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Process exit code reported by Docker. None while still running." + }, + "exit_reason": { + "type": [ + "string", + "null" + ], + "description": "Human-readable reason the container exited." + }, + "finished_at": { + "type": [ + "string", + "null" + ], + "description": "When the container exited (Docker's FinishedAt). None while running.", + "example": "2025-10-12T12:16:47.609192Z" + }, + "host_port": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Port on the host machine" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "image_name": { + "type": "string" + }, + "oom_killed": { + "type": [ + "boolean", + "null" + ], + "description": "True when Docker's OOM killer terminated the container." + }, + "ready_at": { + "type": [ + "string", + "null" + ], + "example": "2025-10-12T12:16:47.609192Z" + }, + "resource_limits": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/ResourceLimitsResponse", + "description": "Resource limits" + } + ] + }, + "restart_count": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Container restart count from Docker" + }, + "service_name": { + "type": [ + "string", + "null" + ], + "description": "Compose service name (e.g. \"web\", \"redis\"). None for single-container deployments." + }, + "service_url": { + "type": [ + "string", + "null" + ], + "description": "Per-service URL for compose deployments" + }, + "started_at": { + "type": [ + "string", + "null" + ], + "description": "When the container's main process most recently started.", + "example": "2025-10-12T12:15:50.000000Z" + }, + "status": { + "type": "string" + } + } + }, + "ContainerEnvironmentVariableValueResponse": { + "type": "object", + "required": [ + "value" + ], + "properties": { + "value": { + "type": "string" + } + } + }, + "ContainerInfoResponse": { + "type": "object", + "required": [ + "container_id", + "container_name", + "image_name", + "status", + "created_at" + ], + "properties": { + "container_id": { + "type": "string" + }, + "container_name": { + "type": "string" + }, + "cpu_limit_cores": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "CPU limit in whole cores (e.g. 1.0). None when no limit is configured." + }, + "created_at": { + "type": "string", + "example": "2025-10-12T12:15:47.609192Z" + }, + "error_message": { + "type": [ + "string", + "null" + ], + "description": "Free-form error string from Docker's container state on exit." + }, + "exit_code": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Process exit code reported by Docker. None while still running." + }, + "exit_reason": { + "type": [ + "string", + "null" + ], + "description": "Human-readable reason the container exited (e.g. \"OOMKilled\",\n\"Killed by SIGKILL (exit code 137)\", \"Exit code 1\"). None while running." + }, + "finished_at": { + "type": [ + "string", + "null" + ], + "description": "When the container exited (Docker's FinishedAt). None while running.", + "example": "2025-10-12T12:16:47.609192Z" + }, + "image_name": { + "type": "string" + }, + "node_name": { + "type": [ + "string", + "null" + ], + "description": "Node name where this container is running. None for local (single-node) deployments." + }, + "oom_killed": { + "type": [ + "boolean", + "null" + ], + "description": "True when Docker's OOM killer terminated the container." + }, + "restart_count": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Container restart count from Docker. The UI shows a chip when this is\n> 0 so a crash loop is visible without opening detail." + }, + "service_name": { + "type": [ + "string", + "null" + ], + "description": "Compose service name (e.g. \"web\", \"redis\"). None for single-container deployments." + }, + "service_url": { + "type": [ + "string", + "null" + ], + "description": "Per-service URL for compose deployments (e.g. \"https://web-myapp.localho.st\")" + }, + "started_at": { + "type": [ + "string", + "null" + ], + "description": "When the container's main process most recently started. The UI uses\nthis for the uptime label so the count resets when a container is\nrestarted in place. None for containers that never started.", + "example": "2025-10-12T12:15:50.000000Z" + }, + "status": { + "type": "string" + } + } + }, + "ContainerInventoryItem": { + "type": "object", + "description": "A container reported by the agent during heartbeat reconciliation.", + "required": [ + "container_id", + "container_name" + ], + "properties": { + "container_id": { + "type": "string", + "description": "Docker container ID" + }, + "container_name": { + "type": "string", + "description": "Docker container name" + } + } + }, + "ContainerListResponse": { + "type": "object", + "required": [ + "containers", + "total" + ], + "properties": { + "containers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ContainerInfoResponse" + } + }, + "total": { + "type": "integer", + "minimum": 0 + } + } + }, + "ContainerLogSettings": { + "type": "object", + "description": "Docker container log rotation settings\nControls the `--log-opt max-size` and `--log-opt max-file` for containers", + "properties": { + "max_file": { + "type": "integer", + "format": "int32", + "description": "Maximum number of rotated log files to keep (e.g., 3 means up to 3 x max_size total)", + "default": 3, + "example": 3, + "minimum": 0 + }, + "max_size": { + "type": "string", + "description": "Maximum size of each log file (e.g., \"50m\", \"100m\", \"1g\")\nDocker default is unlimited; we default to \"50m\" to prevent disk exhaustion", + "default": "50m", + "example": "50m" + }, + "service_max_file": { + "type": "integer", + "format": "int32", + "description": "Maximum rotated log files for external service containers", + "default": 3, + "example": 3, + "minimum": 0 + }, + "service_max_size": { + "type": "string", + "description": "Maximum size for external service container logs (postgres, redis, etc.)\nDefaults to \"20m\" since services are typically less verbose than app containers", + "default": "20m", + "example": "20m" + } + } + }, + "ContainerLogsQuery": { + "type": "object", + "properties": { + "container_name": { + "type": [ + "string", + "null" + ], + "description": "Optional container name to get logs from (if deployment has multiple containers)" + }, + "end_date": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "follow": { + "type": "boolean", + "description": "Follow log output in real-time (default: true for backward compatibility)" + }, + "start_date": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "tail": { + "type": [ + "string", + "null" + ] + }, + "timestamps": { + "type": "boolean", + "description": "Include timestamps in log output (default: false)" + } + } + }, + "ContainerMetricHistoryPoint": { + "type": "object", + "description": "One bucketed data point of a container resource metric time series.", + "required": [ + "time", + "value" + ], + "properties": { + "time": { + "type": "string", + "description": "Bucket timestamp (ISO 8601 with `Z` suffix).", + "example": "2025-10-12T12:15:00+00:00" + }, + "value": { + "type": "number", + "format": "double", + "description": "Averaged metric value for the bucket." + } + } + }, + "ContainerMetricsHistoryQuery": { + "type": "object", + "description": "Query parameters for the container metrics history endpoint.", + "required": [ + "metric" + ], + "properties": { + "metric": { + "type": "string", + "description": "Dotted metric name, e.g. `container.cpu_percent` or\n`container.memory_used_bytes`." + }, + "range": { + "type": "string", + "description": "Time window: `1h`, `6h`, `24h`, or `7d` (defaults to `1h`)." + } + } + }, + "ContainerMetricsResponse": { + "type": "object", + "description": "Container resource metrics (CPU, memory usage)", + "required": [ + "container_id", + "container_name", + "cpu_percent", + "memory_bytes", + "network_rx_bytes", + "network_tx_bytes", + "timestamp" + ], + "properties": { + "container_id": { + "type": "string" + }, + "container_name": { + "type": "string" + }, + "cpu_limit_cores": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "CPU limit in whole cores (e.g. 1.0). None = no limit." + }, + "cpu_percent": { + "type": "number", + "format": "double", + "description": "CPU usage as a multi-core percentage (Docker convention: 200 = 2 cores\nfully pinned). Divide by 100 to get cores used." + }, + "memory_bytes": { + "type": "integer", + "format": "int64", + "description": "Memory usage in bytes", + "minimum": 0 + }, + "memory_limit_bytes": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Memory limit in bytes (if set)", + "minimum": 0 + }, + "memory_percent": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Memory usage percentage (0-100) if limit is set" + }, + "network_rx_bytes": { + "type": "integer", + "format": "int64", + "description": "Network bytes received", + "minimum": 0 + }, + "network_tx_bytes": { + "type": "integer", + "format": "int64", + "description": "Network bytes transmitted", + "minimum": 0 + }, + "timestamp": { + "type": "string", + "description": "Timestamp of metrics collection", + "example": "2025-10-12T12:15:47.609192Z" + } + } + }, + "ContainerResponse": { + "type": "object", + "required": [ + "name", + "container_type", + "can_contain_containers", + "can_contain_entities", + "metadata" + ], + "properties": { + "can_contain_containers": { + "type": "boolean", + "description": "Can this container hold other containers?", + "example": true + }, + "can_contain_entities": { + "type": "boolean", + "description": "Can this container hold entities (tables, collections, etc.)?", + "example": false + }, + "child_container_type": { + "type": [ + "string", + "null" + ], + "description": "Type of child containers (if can_contain_containers is true)", + "example": "schema" + }, + "container_type": { + "type": "string", + "description": "Container type (database, schema, keyspace, bucket, etc.)", + "example": "database" + }, + "entity_count_hint": { + "type": [ + "string", + "null" + ], + "description": "Hint for UI on expected entity count (small = sidebar, large = pagination)", + "example": "large" + }, + "entity_type_label": { + "type": [ + "string", + "null" + ], + "description": "Label for entity type (if can_contain_entities is true)", + "example": "table" + }, + "metadata": { + "description": "Additional metadata" + }, + "name": { + "type": "string", + "description": "Container name", + "example": "mydb" + } + } + }, + "ContainerRuntimeInfo": { + "type": "object", + "description": "Snapshot of a container's lifecycle state from `docker inspect`.\n`restart_count` and `oom_killed` are the load-bearing fields when\ndiagnosing crash loops \u2014 the kernel OOM killer never reaches the\napplication's logs, so seeing `oom_killed=true` is the only signal\nthat a memory limit was the cause.", + "required": [ + "role", + "container_name", + "resource_limits" + ], + "properties": { + "container_id": { + "type": [ + "string", + "null" + ], + "description": "Container Docker id, when present. None = container does not exist\n(was never created or was removed externally)." + }, + "container_name": { + "type": "string", + "description": "Stable name of the Docker container (e.g. `postgres-mydb`)." + }, + "exit_code": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Last container exit code, when known. Non-zero = unclean stop." + }, + "finished_at": { + "type": [ + "string", + "null" + ], + "description": "ISO-8601 timestamp of the most recent termination, when known." + }, + "image": { + "type": [ + "string", + "null" + ], + "description": "Currently-effective Docker image (e.g. `gotempsh/postgres-walg:18-bookworm`)." + }, + "oom_killed": { + "type": [ + "boolean", + "null" + ], + "description": "True when the container's last termination was caused by the\nkernel OOM killer. Set if the user enabled hard memory limits\nand the working set exceeded them." + }, + "resource_limits": { + "$ref": "#/components/schemas/ServiceResourceLimits", + "description": "Currently-applied resource limits read off the container's\n`HostConfig`. Compare this against the user-configured limits to\ndetect drift (an old container that never picked up new caps)." + }, + "restart_count": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Total restarts since the container was created. Useful for\ndetecting crash loops \u2014 a steady stream means something is killing\nthe container repeatedly (frequently OOM)." + }, + "role": { + "type": "string", + "description": "`service_members.role` for cluster members; \"standalone\" otherwise." + }, + "started_at": { + "type": [ + "string", + "null" + ], + "description": "ISO-8601 timestamp of when the container last started. None when\nit has never started (i.e. created but never run)." + }, + "status": { + "type": [ + "string", + "null" + ], + "description": "Bollard container state (\"running\", \"exited\", \"dead\", etc.). None\nwhen the container does not exist." + } + } + }, + "ContainerStatsSample": { + "type": "object", + "description": "Live resource usage sample for a single container.\n\n`cpu_percent` is computed by Docker's standard formula:\n ((cpu_delta / system_delta) * online_cpus) * 100\n`memory_percent` is `(memory_usage / memory_limit) * 100` \u2014 when no\nmemory limit is set the limit reported by Docker is the host's total\nRAM, so a 5% reading means \"5% of host RAM\", not \"5% of allocated\".", + "required": [ + "role", + "container_name" + ], + "properties": { + "container_name": { + "type": "string" + }, + "cpu_percent": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "CPU usage as a percentage. `None` when the container is not running\n(Docker returns no usable counters)." + }, + "memory_limit_bytes": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Memory limit in bytes (host RAM if no limit set).", + "minimum": 0 + }, + "memory_percent": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Memory usage as a percentage of `memory_limit_bytes`." + }, + "memory_usage_bytes": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Resident memory usage in bytes.", + "minimum": 0 + }, + "online_cpus": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Number of cores Docker observed at sample time. Used by the UI\nto label \"x/y cores\" instead of just a percent.", + "minimum": 0 + }, + "role": { + "type": "string" + } + } + }, + "ContentPart": { + "type": "object", + "required": [ + "type" + ], + "properties": { + "image_url": {}, + "text": { + "type": [ + "string", + "null" + ] + }, + "type": { + "type": "string" + } + } + }, + "ContextLine": { + "type": "object", + "description": "A line in context response", + "required": [ + "timestamp", + "level", + "message", + "line_offset", + "is_match" + ], + "properties": { + "fields": {}, + "is_match": { + "type": "boolean", + "description": "Whether this line matched the original search" + }, + "level": { + "$ref": "#/components/schemas/LogLevel" + }, + "line_offset": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "timestamp": { + "type": "string" + } + } + }, + "ContextLogsRequest": { + "type": "object", + "required": [ + "chunk_id", + "line_offset" + ], + "properties": { + "chunk_id": { + "type": "string" + }, + "line_offset": { + "type": "integer", + "format": "int32" + }, + "lines": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Number of context lines before and after (default: 25)", + "minimum": 0 + } + } + }, + "ContextLogsResponse": { + "type": "object", + "required": [ + "lines", + "target_index" + ], + "properties": { + "lines": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ContextLine" + } + }, + "target_index": { + "type": "integer", + "minimum": 0 + } + } + }, + "ConversationDetailResponse": { + "allOf": [ + { + "$ref": "#/components/schemas/ConversationResponse" + }, + { + "type": "object", + "required": [ + "messages" + ], + "properties": { + "messages": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MessageResponse" + }, + "description": "Turns oldest-first. The `system` seed message is omitted (internal)." + } + } + } + ] + }, + "ConversationResponse": { + "type": "object", + "required": [ + "public_id", + "context_type", + "context_id", + "status", + "created_at", + "last_activity_at" + ], + "properties": { + "context_id": { + "type": "string" + }, + "context_type": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "last_activity_at": { + "type": "string" + }, + "public_id": { + "type": "string" + }, + "status": { + "type": "string" + }, + "title": { + "type": [ + "string", + "null" + ] + } + } + }, + "ConversationSummary": { + "type": "object", + "description": "A conversation summary grouping related AI invocations.", + "required": [ + "conversation_id", + "message_count", + "total_input_tokens", + "total_output_tokens", + "total_tokens", + "total_cost_microcents", + "avg_latency_ms", + "models_used", + "first_at", + "last_at" + ], + "properties": { + "avg_latency_ms": { + "type": "number", + "format": "double" + }, + "conversation_id": { + "type": "string" + }, + "first_at": { + "type": "string" + }, + "last_at": { + "type": "string" + }, + "message_count": { + "type": "integer", + "format": "int64" + }, + "models_used": { + "type": "array", + "items": { + "type": "string" + } + }, + "total_cost_microcents": { + "type": "integer", + "format": "int64" + }, + "total_input_tokens": { + "type": "integer", + "format": "int64" + }, + "total_output_tokens": { + "type": "integer", + "format": "int64" + }, + "total_tokens": { + "type": "integer", + "format": "int64" + } + } + }, + "ConversationsQueryParams": { + "type": "object", + "properties": { + "from": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 start time (defaults to 24h ago)" + }, + "limit": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Max results (defaults to 50, max 100)", + "minimum": 0 + }, + "model": { + "type": [ + "string", + "null" + ], + "description": "Filter by model name" + }, + "tags": { + "type": [ + "string", + "null" + ], + "description": "Filter by tags (comma-separated, AND logic)" + }, + "to": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 end time (defaults to now)" + }, + "user_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Filter by user ID" + } + } + }, + "CopyBlobRequest": { + "type": "object", + "description": "Request to copy a blob", + "required": [ + "fromUrl", + "toPathname" + ], + "properties": { + "fromUrl": { + "type": "string", + "description": "Source blob URL or pathname", + "example": "/api/blob/10/images/avatar.png" + }, + "projectId": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Project ID (required for API key/session auth, optional for deployment tokens)", + "example": 1 + }, + "toPathname": { + "type": "string", + "description": "Destination pathname", + "example": "images/avatar-copy.png" + } + } + }, + "CostAnalysis": { + "type": "object", + "description": "Full cluster cost + rightsizing analysis attached to an import plan.", + "required": [ + "nodes", + "capacity", + "requested", + "usage_source", + "overprovisioning", + "recommendation", + "notes" + ], + "properties": { + "actual_usage": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/ResourceFootprint", + "description": "Measured usage from the metrics API (`metrics.k8s.io`).\n`None` when metrics-server is not installed." + } + ] + }, + "capacity": { + "$ref": "#/components/schemas/ClusterCapacity", + "description": "Total cluster capacity (sum of node allocatable resources)" + }, + "control_plane_monthly_usd": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Managed control-plane fee included in `current_monthly_usd` (EKS/GKE\ncharge ~$73/mo per cluster). `None` when not applicable/unknown." + }, + "current_monthly_usd": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Estimated total infrastructure cost per month in USD (compute nodes +\ncontrol-plane fee). `None` when no node could be priced." + }, + "nodes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NodeCostInfo" + }, + "description": "Per-node inventory with price estimates where the instance type is known" + }, + "notes": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Honesty notes: what could not be measured, which numbers are\nestimates, and any assumptions made. Always shown to the user." + }, + "overprovisioning": { + "$ref": "#/components/schemas/OverprovisioningAssessment", + "description": "Requests-vs-capacity-vs-usage assessment" + }, + "provider": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/CloudProvider", + "description": "Detected cloud provider (from node `providerID` prefixes)" + } + ] + }, + "recommendation": { + "$ref": "#/components/schemas/TargetRecommendation", + "description": "The temps/Hetzner target sizing and savings estimate" + }, + "requested": { + "$ref": "#/components/schemas/ResourceFootprint", + "description": "Sum of pod resource *requests* across running pods \u2014 what the\nscheduler has reserved, i.e. what the cluster is sized for." + }, + "usage_source": { + "$ref": "#/components/schemas/UsageSource", + "description": "How the usage numbers were obtained (drives UI wording)" + } + } + }, + "CreateAlertRuleRequest": { + "type": "object", + "required": [ + "name", + "trigger_type" + ], + "properties": { + "cooldown_minutes": { + "type": "integer", + "format": "int32", + "description": "Minimum minutes between notifications for same rule+group" + }, + "enabled": { + "type": "boolean" + }, + "environment_filter": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Optional environment ID to filter alerts" + }, + "error_level_filter": { + "type": [ + "string", + "null" + ], + "description": "Optional error type/level filter" + }, + "name": { + "type": "string" + }, + "notification_priority": { + "type": "string", + "description": "Notification priority: Low, Normal, High, Critical" + }, + "trigger_config": { + "description": "Trigger-specific configuration (e.g., {\"count\": 100, \"window_minutes\": 60} for frequency)" + }, + "trigger_type": { + "type": "string", + "description": "Trigger type: new_issue, regression, frequency, new_user, user_count, status_change" + } + } + }, + "CreateApiKeyRequest": { + "type": "object", + "required": [ + "name", + "role_type" + ], + "properties": { + "expires_at": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "example": "2024-12-31T23:59:59Z" + }, + "name": { + "type": "string" + }, + "permissions": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + }, + "example": [ + "projects:read", + "deployments:read" + ] + }, + "role_type": { + "type": "string", + "example": "admin" + } + } + }, + "CreateApiKeyResponse": { + "type": "object", + "required": [ + "id", + "name", + "key_prefix", + "role_type", + "api_key", + "created_at" + ], + "properties": { + "api_key": { + "type": "string" + }, + "created_at": { + "type": "string", + "format": "date-time", + "example": "2024-01-01T00:00:00Z" + }, + "expires_at": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "example": "2024-12-31T23:59:59Z" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "key_prefix": { + "type": "string" + }, + "name": { + "type": "string" + }, + "permissions": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "role_type": { + "type": "string" + } + } + }, + "CreateBackupScheduleRequest": { + "type": "object", + "required": [ + "name", + "backup_type", + "retention_period", + "schedule_expression", + "enabled", + "tags" + ], + "properties": { + "backup_type": { + "type": "string" + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "enabled": { + "type": "boolean" + }, + "include_control_plane": { + "type": [ + "boolean", + "null" + ], + "description": "When `true` (default), every run also produces a `control_plane`\nbackup of Temps's own database. Operators who use Temps purely as\na backup orchestrator for external DBs can set this to `false` to\nkeep the run history focused on those services." + }, + "max_runtime_secs": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Optional wall-clock timeout override for jobs created by this schedule\n(seconds). When set, overrides the engine-family default. `null` means\n\"use engine default.\" The per-job `max_runtime_secs` in\n`EnqueueJobParams` can still override this for ad-hoc triggers." + }, + "name": { + "type": "string" + }, + "retention_period": { + "type": "integer", + "format": "int32" + }, + "s3_source_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Optional S3 source. If omitted, the current default S3 source is used." + }, + "schedule_expression": { + "type": "string" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + } + }, + "target_all_services": { + "type": [ + "boolean", + "null" + ], + "description": "When `true` (default), the schedule backs up every external service\non the host \u2014 including databases created in the future. When\n`false`, the schedule backs up only the services explicitly attached\nvia `POST /backups/schedules/{id}/services`. Omit to use the default." + } + } + }, + "CreateBitbucketRequest": { + "type": "object", + "required": [ + "name", + "auth" + ], + "properties": { + "auth": { + "$ref": "#/components/schemas/BitbucketAuthInput", + "description": "Authentication credentials \u2014 either an access token or an app password." + }, + "name": { + "type": "string", + "description": "Display name for this provider." + } + } + }, + "CreateCloudflareProviderRequest": { + "type": "object", + "required": [ + "name", + "config" + ], + "properties": { + "config": { + "$ref": "#/components/schemas/CloudflareConfig" + }, + "enabled": { + "type": [ + "boolean", + "null" + ] + }, + "name": { + "type": "string" + } + } + }, + "CreateConversationRequest": { + "type": "object", + "required": [ + "context_type", + "context_id" + ], + "properties": { + "context_id": { + "type": "string", + "description": "The entity id (ints stringified)." + }, + "context_type": { + "type": "string", + "description": "e.g. `\"deployment\"`." + } + } + }, + "CreateDSNRequest": { + "type": "object", + "properties": { + "base_url": { + "type": [ + "string", + "null" + ] + }, + "deployment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "name": { + "type": [ + "string", + "null" + ] + } + } + }, + "CreateDashboardRequest": { + "type": "object", + "required": [ + "project_id", + "name", + "layout" + ], + "properties": { + "layout": { + "$ref": "#/components/schemas/DashboardLayout" + }, + "name": { + "type": "string" + }, + "project_id": { + "type": "integer", + "format": "int32" + } + } + }, + "CreateDeploymentTokenRequest": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "deployment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Optional deployment ID - if set, token is scoped to a specific deployment" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Optional environment ID - if not set, token applies to all environments" + }, + "expires_at": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "example": "2024-12-31T23:59:59Z" + }, + "name": { + "type": "string" + }, + "permissions": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + }, + "description": "List of permissions (e.g., [\"visitors:enrich\", \"emails:send\"])\nIf not provided, defaults to full access", + "example": [ + "visitors:enrich", + "emails:send" + ] + } + } + }, + "CreateDeploymentTokenResponse": { + "type": "object", + "required": [ + "id", + "project_id", + "name", + "token_prefix", + "token", + "created_at" + ], + "properties": { + "created_at": { + "type": "string", + "format": "date-time", + "example": "2024-01-01T00:00:00Z" + }, + "deployment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "expires_at": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "example": "2024-12-31T23:59:59Z" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "permissions": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "token": { + "type": "string", + "description": "The full token value - only returned on creation" + }, + "token_prefix": { + "type": "string" + } + } + }, + "CreateDnsProviderRequest": { + "type": "object", + "description": "Request to create a new DNS provider", + "required": [ + "name", + "provider_type", + "credentials" + ], + "properties": { + "credentials": { + "$ref": "#/components/schemas/DnsProviderCredentials", + "description": "Provider credentials" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Optional description" + }, + "name": { + "type": "string", + "description": "User-friendly name", + "example": "My Cloudflare" + }, + "provider_type": { + "$ref": "#/components/schemas/DnsProviderType", + "description": "Provider type" + } + } + }, + "CreateDomainRequest": { + "type": "object", + "required": [ + "domain" + ], + "properties": { + "challenge_type": { + "type": "string", + "description": "Challenge type for Let's Encrypt validation. Options: \"http-01\" (default) or \"dns-01\"" + }, + "domain": { + "type": "string" + } + } + }, + "CreateEmailDomainRequest": { + "type": "object", + "required": [ + "provider_id", + "domain" + ], + "properties": { + "domain": { + "type": "string", + "description": "Domain name (e.g., \"updates.example.com\")", + "example": "updates.example.com" + }, + "provider_id": { + "type": "integer", + "format": "int32", + "description": "Provider ID to use for this domain" + } + } + }, + "CreateEmailProviderRequest": { + "type": "object", + "required": [ + "name", + "provider_type", + "region" + ], + "properties": { + "name": { + "type": "string", + "description": "User-friendly name for the provider", + "example": "My AWS SES" + }, + "provider_type": { + "$ref": "#/components/schemas/EmailProviderTypeRoute", + "description": "Provider type" + }, + "region": { + "type": "string", + "description": "Cloud region. For SMTP this is informational only \u2014 the host/port carry the real routing.", + "example": "us-east-1" + }, + "scaleway_credentials": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/ScalewayCredentialsRequest", + "description": "Scaleway credentials (required if provider_type is scaleway)" + } + ] + }, + "ses_credentials": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/SesCredentialsRequest", + "description": "AWS SES credentials (required if provider_type is ses)" + } + ] + }, + "smtp_credentials": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/SmtpCredentialsRequest", + "description": "Generic SMTP credentials (required if provider_type is smtp). Use when\nyou only have SMTP creds and want to import an already-set-up domain." + } + ] + }, + "sns_topic_arn": { + "type": [ + "string", + "null" + ], + "description": "Exact SNS topic allowed to deliver SES events for this provider." + } + } + }, + "CreateEnvironmentRequest": { + "type": "object", + "required": [ + "name", + "branch" + ], + "properties": { + "branch": { + "type": "string" + }, + "name": { + "type": "string" + }, + "set_as_preview": { + "type": "boolean", + "description": "If true, set this environment as the preview environment for the project" + } + } + }, + "CreateEnvironmentVariableRequest": { + "type": "object", + "required": [ + "key", + "value", + "environment_ids" + ], + "properties": { + "environment_ids": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + }, + "include_in_preview": { + "type": "boolean", + "description": "Include this environment variable in preview environments (default: true)" + }, + "is_secret": { + "type": "boolean", + "description": "When true the variable is treated as write-only: never returned in\nplaintext from the API, masked in the UI, and updates that omit the\nvalue preserve the existing ciphertext. The flag is one-way \u2014 secret\nvars cannot be demoted back to regular vars." + }, + "key": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, + "CreateExternalServiceRequest": { + "type": "object", + "required": [ + "name", + "service_type", + "parameters" + ], + "properties": { + "members": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ClusterMemberRequest" + }, + "description": "Cluster member specifications. Required when topology is \"cluster\"." + }, + "name": { + "type": "string" + }, + "node_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Target node ID for the service. Omit or null to run on the control plane." + }, + "parameters": { + "type": "object", + "additionalProperties": {}, + "propertyNames": { + "type": "string" + } + }, + "service_type": { + "$ref": "#/components/schemas/ServiceTypeRoute" + }, + "topology": { + "type": "string", + "description": "Service topology: \"standalone\" (default) or \"cluster\" (HA multi-member).", + "example": "standalone" + }, + "version": { + "type": [ + "string", + "null" + ] + } + } + }, + "CreateFlagRequest": { + "type": "object", + "required": [ + "key", + "value_type", + "default_value" + ], + "properties": { + "client_visible": { + "type": "boolean", + "description": "Whether the flag may be exposed on the unauthenticated same-origin\nevaluation endpoint. Defaults to `false`: flags are server-only unless\nexplicitly opted in, because targeting rules can encode business logic." + }, + "default_value": { + "description": "Served whenever evaluation cannot do better. Must match `value_type`.\n\nLeft unannotated so utoipa emits a free-form schema: a bool flag's\ndefault is `false`, not an object, and `value_type = Object` would tell\nevery generated client otherwise." + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "key": { + "type": "string", + "description": "Stable key used in application code. Immutable after create.", + "example": "checkout.v2" + }, + "value_type": { + "$ref": "#/components/schemas/FlagValueType", + "description": "Fixed at create: retyping would invalidate every stored value and every\ncall site." + } + } + }, + "CreateFunnelRequest": { + "type": "object", + "required": [ + "name", + "steps" + ], + "properties": { + "description": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": "string" + }, + "steps": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CreateFunnelStep" + } + } + } + }, + "CreateFunnelResponse": { + "type": "object", + "required": [ + "funnel_id", + "message" + ], + "properties": { + "funnel_id": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } + }, + "CreateFunnelStep": { + "type": "object", + "required": [ + "event_name" + ], + "properties": { + "event_filter": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SmartFilter" + } + }, + "event_name": { + "type": "string" + } + } + }, + "CreateGenericRequest": { + "type": "object", + "required": [ + "name", + "clone_url" + ], + "properties": { + "base_url": { + "type": [ + "string", + "null" + ], + "description": "Optional base URL of the git host for display purposes (no API is called)." + }, + "clone_url": { + "type": "string", + "description": "HTTPS clone URL for the repository, e.g. `https://git.example.com/org/repo.git`." + }, + "name": { + "type": "string", + "description": "Display name for this provider." + }, + "token": { + "type": [ + "string", + "null" + ], + "description": "Access token or password. Omit (or set to `null`) for public repositories." + }, + "token_username": { + "type": [ + "string", + "null" + ], + "description": "HTTP Basic username used with the token. Defaults to `x-access-token` when\nabsent or empty. Ignored for public (unauthenticated) repositories." + } + } + }, + "CreateGitHubPATRequest": { + "type": "object", + "required": [ + "name", + "token" + ], + "properties": { + "name": { + "type": "string" + }, + "token": { + "type": "string" + } + } + }, + "CreateGitLabOAuthRequest": { + "type": "object", + "required": [ + "name", + "client_id", + "client_secret", + "redirect_uri" + ], + "properties": { + "base_url": { + "type": [ + "string", + "null" + ] + }, + "client_id": { + "type": "string" + }, + "client_secret": { + "type": "string" + }, + "name": { + "type": "string" + }, + "redirect_uri": { + "type": "string" + } + } + }, + "CreateGitLabPATRequest": { + "type": "object", + "required": [ + "name", + "token" + ], + "properties": { + "base_url": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": "string" + }, + "token": { + "type": "string" + } + } + }, + "CreateGiteaPATRequest": { + "type": "object", + "required": [ + "name", + "token", + "base_url" + ], + "properties": { + "base_url": { + "type": "string", + "description": "HTTPS base URL of the Gitea instance, e.g. `https://git.example.com`." + }, + "name": { + "type": "string", + "description": "Display name for this provider." + }, + "token": { + "type": "string", + "description": "Personal access token issued by the Gitea instance." + } + } + }, + "CreateIncidentRequest": { + "type": "object", + "required": [ + "title", + "severity" + ], + "properties": { + "description": { + "type": [ + "string", + "null" + ] + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "monitor_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "severity": { + "type": "string" + }, + "title": { + "type": "string" + } + } + }, + "CreateIntegrationBody": { + "type": "object", + "required": [ + "provider", + "signing_secret" + ], + "properties": { + "provider": { + "type": "string", + "description": "Registered provider name, e.g. \"stripe\"." + }, + "signing_secret": { + "type": "string", + "description": "Signing secret from the provider's dashboard." + } + } + }, + "CreateIpAccessControlRequest": { + "type": "object", + "description": "Request to create an IP access control rule", + "required": [ + "ip_address", + "action" + ], + "properties": { + "action": { + "type": "string", + "description": "Action to take: \"block\" or \"allow\"", + "example": "block" + }, + "ip_address": { + "type": "string", + "description": "IP address in CIDR notation (e.g., \"192.168.1.1\" or \"10.0.0.0/24\")", + "example": "192.168.1.100" + }, + "reason": { + "type": [ + "string", + "null" + ], + "description": "Optional reason for the action", + "example": "Malicious activity detected" + } + } + }, + "CreateMcpRequest": { + "type": "object", + "required": [ + "slug", + "name", + "config" + ], + "properties": { + "config": { + "type": "object" + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": "string" + }, + "slug": { + "type": "string" + } + } + }, + "CreateMetricAlertRequest": { + "type": "object", + "required": [ + "project_id", + "name", + "metric_name", + "aggregation", + "detection_config", + "window_secs", + "for_duration_secs", + "severity", + "enabled" + ], + "properties": { + "aggregation": { + "type": "string", + "description": "One of `avg|sum|min|max|count|rate|p50|p90|p95|p99`." + }, + "detection_config": { + "$ref": "#/components/schemas/DetectionConfig", + "description": "The detector: a discriminated union keyed by `kind`. Today only\n`{ \"kind\": \"static\", \"comparator\": \"gt\", \"threshold\": 500 }` is evaluable." + }, + "dynamic_alerts": { + "type": "boolean", + "description": "When true (and `group_by` is set) fire one independent alarm per breaching\nseries. Static detectors only. Default false." + }, + "enabled": { + "type": "boolean" + }, + "for_duration_secs": { + "type": "integer", + "format": "int32" + }, + "group_by": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Label keys to break the metric down by, e.g. `[\"endpoint\",\"region\"]`. Empty\n(the default) = one aggregate stream. Max 2 keys; keys must match\n`[a-zA-Z0-9_.:-]`." + }, + "grouped_notification_threshold": { + "type": "integer", + "format": "int32", + "description": "When more than this many series transition to firing in the same tick, only\nthe first gets the expensive chart/AI enrichment. Range 1\u20131000, default 5." + }, + "label_filters": { + "type": "array", + "items": { + "type": "array", + "items": false, + "prefixItems": [ + { + "type": "string" + }, + { + "type": "string" + } + ] + }, + "description": "AND-combined label equality filters: `[[\"key\",\"value\"],\u2026]`. Empty = no\nfiltering (the default). Max 10 pairs; keys must match `[a-zA-Z0-9_.:-]`;\nvalues capped at 500 characters." + }, + "max_series": { + "type": "integer", + "format": "int32", + "description": "Cardinality cap for dynamic alerting: at most this many series (top by\n`|value|`). Range 1\u2013100, default 20." + }, + "metric_name": { + "type": "string" + }, + "name": { + "type": "string" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "severity": { + "type": "string", + "description": "One of `info|warning|critical`." + }, + "window_secs": { + "type": "integer", + "format": "int32" + } + } + }, + "CreateMonitorRequest": { + "type": "object", + "required": [ + "name", + "monitor_type", + "environment_id" + ], + "properties": { + "check_interval_seconds": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "check_path": { + "type": [ + "string", + "null" + ] + }, + "environment_id": { + "type": "integer", + "format": "int32" + }, + "monitor_type": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "CreateNotificationEmailProviderRequest": { + "type": "object", + "required": [ + "name", + "config" + ], + "properties": { + "config": { + "$ref": "#/components/schemas/EmailConfig" + }, + "enabled": { + "type": [ + "boolean", + "null" + ] + }, + "name": { + "type": "string" + } + } + }, + "CreateOidcProviderRequest": { + "type": "object", + "required": [ + "name", + "issuer_url", + "client_id", + "client_secret" + ], + "properties": { + "client_id": { + "type": "string" + }, + "client_secret": { + "type": "string" + }, + "default_role": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "group_claim": { + "type": "string" + }, + "issuer_url": { + "type": "string" + }, + "jit_provisioning": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "role_claim": { + "type": "string" + }, + "scopes": { + "type": "string" + }, + "template": { + "type": "string" + }, + "trust_idp_email": { + "type": "boolean", + "description": "Defaults false. Set to true only for IdPs where an admin\ncontrols user provisioning (corporate Okta, Azure AD) and\nself-signup of arbitrary emails is not possible \u2014 see the\n`trust_idp_email` field on `oidc_providers::Model` for the\nsecurity tradeoff this enables." + } + } + }, + "CreateOidcRoleMappingRequest": { + "type": "object", + "required": [ + "priority", + "idp_group", + "role" + ], + "properties": { + "idp_group": { + "type": "string" + }, + "priority": { + "type": "integer", + "format": "int32" + }, + "role": { + "type": "string" + } + } + }, + "CreatePlanRequest": { + "type": "object", + "description": "Request to create an import plan", + "required": [ + "source", + "workload_id" + ], + "properties": { + "credentials": { + "$ref": "#/components/schemas/ImportCredentials", + "description": "Platform credentials (required for cloud platforms like Vercel, Railway)" + }, + "repository_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Optional repository ID to associate with the import\nIf provided, preset will be detected from the repository" + }, + "source": { + "$ref": "#/components/schemas/ImportSource", + "description": "Source to import from" + }, + "workload_id": { + "$ref": "#/components/schemas/WorkloadId", + "description": "Workload ID to import" + } + } + }, + "CreatePlanResponse": { + "type": "object", + "description": "Response with created plan", + "required": [ + "session_id", + "plan", + "validation", + "can_execute" + ], + "properties": { + "can_execute": { + "type": "boolean", + "description": "Whether the plan can be executed" + }, + "plan": { + "$ref": "#/components/schemas/ImportPlan", + "description": "Generated import plan" + }, + "session_id": { + "type": "string", + "description": "Session ID for tracking" + }, + "validation": { + "$ref": "#/components/schemas/ValidationReport", + "description": "Validation report" + } + } + }, + "CreatePrResponse": { + "type": "object", + "required": [ + "run", + "pr_url", + "pr_number", + "branch_name" + ], + "properties": { + "branch_name": { + "type": "string" + }, + "pr_number": { + "type": "integer", + "format": "int32" + }, + "pr_url": { + "type": "string" + }, + "run": { + "$ref": "#/components/schemas/AutofixerRunResponse" + } + } + }, + "CreateProjectAccessRequest": { + "type": "object", + "required": [ + "team_id", + "role" + ], + "properties": { + "role": { + "$ref": "#/components/schemas/TeamRole" + }, + "team_id": { + "type": "integer", + "format": "int32" + } + } + }, + "CreateProjectFromTemplateRequest": { + "type": "object", + "description": "Request to create a project from a template\n\nSupports two deploy modes:\n * **Fork mode** \u2014 when `git_provider_connection_id` is set, the template\n repo is cloned into a new repository under the user's Git account and the\n project tracks that fork (git-push deploys, automatic deploy on push).\n * **One-click public-repo mode** \u2014 when `git_provider_connection_id` is\n omitted, the project deploys directly from the template's public source\n repository (no fork, no Git account required). This is the activation\n path: a brand-new user with no Git provider connected can still deploy a\n demo in one click. `repository_name` / `repository_owner` are ignored in\n this mode, and automatic-deploy-on-push is unavailable (there is no fork\n to receive webhooks).", + "required": [ + "template_slug", + "project_name" + ], + "properties": { + "automatic_deploy": { + "type": "boolean", + "description": "Enable automatic deployment on push (defaults to true). Only honoured in\nfork mode; public-repo deploys cannot receive push webhooks." + }, + "environment_variables": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EnvVarInput" + }, + "description": "Environment variables to set (key-value pairs)" + }, + "git_provider_connection_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Git provider connection ID. When omitted, the project deploys directly\nfrom the template's public source repository instead of forking it." + }, + "private": { + "type": "boolean", + "description": "Whether to make the repository private (defaults to true)" + }, + "project_name": { + "type": "string", + "description": "Name for the new project" + }, + "repository_name": { + "type": [ + "string", + "null" + ], + "description": "Name for the new repository to create. Required in fork mode; ignored in\none-click public-repo mode." + }, + "repository_owner": { + "type": [ + "string", + "null" + ], + "description": "Owner/organization for the new repository (defaults to authenticated user)" + }, + "storage_service_ids": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "description": "External storage service IDs to attach to the project" + }, + "template_slug": { + "type": "string", + "description": "Template slug to use as the base" + } + } + }, + "CreateProjectFromTemplateResponse": { + "type": "object", + "description": "Response after creating a project from template", + "required": [ + "project_id", + "project_slug", + "project_name", + "repository_url", + "template_slug", + "message" + ], + "properties": { + "message": { + "type": "string", + "description": "Message with additional info" + }, + "project_id": { + "type": "integer", + "format": "int32", + "description": "ID of the created project" + }, + "project_name": { + "type": "string", + "description": "Name of the created project" + }, + "project_slug": { + "type": "string", + "description": "Slug of the created project" + }, + "repository_url": { + "type": "string", + "description": "URL of the created repository" + }, + "template_slug": { + "type": "string", + "description": "Template that was used" + } + } + }, + "CreateProjectRequest": { + "type": "object", + "required": [ + "name", + "directory", + "main_branch", + "preset", + "storage_service_ids" + ], + "properties": { + "automatic_deploy": { + "type": [ + "boolean", + "null" + ] + }, + "build_command": { + "type": [ + "string", + "null" + ] + }, + "custom_domain": { + "type": [ + "string", + "null" + ] + }, + "directory": { + "type": "string" + }, + "environment_variables": { + "type": [ + "array", + "null" + ], + "items": { + "type": "array", + "items": false, + "prefixItems": [ + { + "type": "string" + }, + { + "type": "string" + } + ] + } + }, + "exposed_port": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Port exposed by the container (fallback when image has no EXPOSE directive)\n\nPriority order for port resolution:\n1. Image EXPOSE directive (auto-detected from built image)\n2. Environment-level exposed_port (overrides this value per environment)\n3. This project-level exposed_port (fallback)\n4. Default: 3000\n\nOnly set this if your image doesn't use EXPOSE directive.", + "example": 8080 + }, + "git_provider_connection_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "git_url": { + "type": [ + "string", + "null" + ] + }, + "install_command": { + "type": [ + "string", + "null" + ] + }, + "is_on_demand": { + "type": [ + "boolean", + "null" + ] + }, + "is_public_repo": { + "type": [ + "boolean", + "null" + ] + }, + "is_web_app": { + "type": [ + "boolean", + "null" + ] + }, + "main_branch": { + "type": "string" + }, + "name": { + "type": "string" + }, + "output_dir": { + "type": [ + "string", + "null" + ] + }, + "performance_metrics_enabled": { + "type": "boolean" + }, + "preset": { + "type": "string" + }, + "preset_config": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/PresetConfigSchema", + "description": "Preset-specific configuration\n\nDifferent presets accept different configuration options:\n- **Dockerfile preset**: Accepts `DockerfilePresetConfig` with `dockerfile_path` and `build_context`\n- **Nixpacks preset**: Accepts ordered `providers` (for example `[\"...\", \"python\"]`)\n and optional inline `nixpacksConfig` TOML\n- **Static presets** (Vite, Next.js, etc.): Accept `StaticPresetConfig` with build commands and output dir\n\nExample for Dockerfile preset:\n```json\n{\n \"dockerfilePath\": \"docker/Dockerfile\",\n \"buildContext\": \"./api\"\n}\n```" + } + ] + }, + "project_type": { + "type": [ + "string", + "null" + ] + }, + "repo_name": { + "type": [ + "string", + "null" + ] + }, + "repo_owner": { + "type": [ + "string", + "null" + ] + }, + "source_type": { + "$ref": "#/components/schemas/SourceType", + "description": "Source type for deployments\n\nDetermines how the project is deployed:\n- **git** (default): Traditional Git-based deployments - source code is pulled, built, and deployed\n- **docker_image**: Deploy pre-built Docker images from external registries (DockerHub, GHCR, etc.)\n- **static_files**: Deploy pre-built static files uploaded as tar.gz or zip bundles\n\nFor `docker_image` and `static_files` source types, `repo_name` and `repo_owner` are optional." + }, + "storage_service_ids": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + }, + "use_default_wildcard": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "CreateProjectSecretRequest": { + "type": "object", + "description": "Request to create a new project secret.\n\nProject secrets are mounted into the container as files under\n`/run/secrets/` (mode 0400, tmpfs) instead of as environment variables.\nValues are always encrypted at rest and never returned in plaintext from\nthe API after create. Distinct from agent secrets (global `/settings/secrets`).", + "required": [ + "key", + "value" + ], + "properties": { + "environment_ids": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + }, + "include_in_preview": { + "type": "boolean", + "description": "Include this secret in preview environments." + }, + "key": { + "type": "string", + "description": "Identifier for the secret. Becomes the filename at `/run/secrets/`.\nMust start with a letter or underscore and contain only A-Z, a-z, 0-9, _." + }, + "value": { + "type": "string", + "description": "Plaintext value, <= 1 MiB." + } + } + }, + "CreateProviderKeyRequest": { + "type": "object", + "required": [ + "provider", + "display_name", + "api_key" + ], + "properties": { + "api_key": { + "type": "string" + }, + "base_url": { + "type": [ + "string", + "null" + ] + }, + "default_model": { + "type": [ + "string", + "null" + ], + "description": "Optional model id to pin for this provider (e.g. \"gpt-4o-mini\")." + }, + "display_name": { + "type": "string" + }, + "provider": { + "type": "string" + } + } + }, + "CreateProviderRequest": { + "type": "object", + "required": [ + "name", + "provider_type", + "config" + ], + "properties": { + "config": {}, + "enabled": { + "type": [ + "boolean", + "null" + ] + }, + "name": { + "type": "string" + }, + "provider_type": { + "type": "string" + } + } + }, + "CreateRouteRequest": { + "type": "object", + "required": [ + "domain", + "host", + "port" + ], + "properties": { + "domain": { + "type": "string" + }, + "host": { + "type": "string" + }, + "port": { + "type": "integer", + "format": "int32" + }, + "route_type": { + "type": [ + "string", + "null" + ], + "description": "Route type: \"http\" (default) matches on HTTP Host header,\n\"tls\" matches on TLS SNI hostname for TCP passthrough" + } + } + }, + "CreateS3SourceRequest": { + "type": "object", + "required": [ + "name", + "bucket_name", + "bucket_path", + "access_key_id", + "secret_key", + "region" + ], + "properties": { + "access_key_id": { + "type": "string" + }, + "bucket_name": { + "type": "string" + }, + "bucket_path": { + "type": "string" + }, + "endpoint": { + "type": [ + "string", + "null" + ], + "description": "Optional endpoint URL for S3-compatible services like MinIO", + "example": "http://minio.example.com:9000" + }, + "force_path_style": { + "type": [ + "boolean", + "null" + ], + "description": "Whether to use path-style addressing (default: true)", + "example": true + }, + "is_default": { + "type": [ + "boolean", + "null" + ], + "description": "When true, make this the default source (will swap out any existing default).\nThe very first S3 source is always created as default regardless of this flag.", + "example": false + }, + "name": { + "type": "string" + }, + "region": { + "type": "string" + }, + "secret_key": { + "type": "string" + } + } + }, + "CreateSandboxBody": { + "type": "object", + "properties": { + "_runtime": { + "type": [ + "string", + "null" + ] + }, + "backend": { + "type": [ + "string", + "null" + ], + "description": "Isolation backend: `\"docker\"` (default) or `\"firecracker\"` (ADR-029,\nhardware-virtualized microVM \u2014 requires a host provisioned with\n`temps firecracker setup`). Omit for the platform default; existing\nclients are unaffected. Requesting an unavailable backend fails with\n400 rather than silently downgrading isolation." + }, + "cpu_limit": { + "type": [ + "number", + "null" + ], + "format": "double" + }, + "disk_size_mb": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Root disk size in MB (Firecracker only; Docker ignores it). Omit for\nthe platform default (1 GiB).", + "minimum": 0 + }, + "env": { + "type": "object", + "description": "Extra env vars baked into the container on create.", + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + } + }, + "image": { + "type": [ + "string", + "null" + ], + "description": "Docker image override. `null` uses the platform default." + }, + "memory_limit_mb": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "networkPolicy": {}, + "pids_limit": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "ports": { + "type": "array", + "items": { + "type": "integer", + "format": "int32", + "minimum": 0 + }, + "description": "Ports the sandbox will listen on. Each port becomes a `routes[]`\nentry in the create/get response so `@vercel/sandbox`'s\n`sandbox.domain(port)` can resolve it client-side without an\nextra round-trip." + }, + "preview_password": { + "type": [ + "string", + "null" + ], + "description": "Optional preview-URL password. When set, every preview URL served\nfor this sandbox is gated behind a login form. 8\u2013256 characters.\nOmit to leave preview URLs open (the sandbox ID remains the only\ngate). The plaintext is never returned; only the last-4 hint is\nsurfaced in `SandboxResponse.preview_password_hint`." + }, + "projectId": { + "type": [ + "string", + "null" + ] + }, + "resources": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/ResourcesBody", + "description": "`@vercel/sandbox`'s nested resources object. When present, its\n`memory` / `vcpus` populate `memory_limit_mb` / `cpu_limit` if those\nweren't sent directly." + } + ] + }, + "source": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/SourceBody", + "description": "Optional initial content to seed into the work dir. Clones a\nrepo or extracts a tarball after the sandbox is created." + } + ] + }, + "timeout": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Idle timeout as sent by `@vercel/sandbox` (milliseconds). Converted\nto seconds when `timeout_secs` is absent.", + "minimum": 0 + }, + "timeout_secs": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Idle timeout in seconds (temps-native). Clamped to `[60, 86400]`.", + "minimum": 0 + } + } + }, + "CreateSkillRequest": { + "type": "object", + "required": [ + "slug", + "name", + "content" + ], + "properties": { + "content": { + "type": "string" + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": "string" + }, + "slug": { + "type": "string" + } + } + }, + "CreateSlackProviderRequest": { + "type": "object", + "required": [ + "name", + "config" + ], + "properties": { + "config": { + "$ref": "#/components/schemas/SlackConfig" + }, + "enabled": { + "type": [ + "boolean", + "null" + ] + }, + "name": { + "type": "string" + } + } + }, + "CreateTeamMemberRequest": { + "type": "object", + "required": [ + "user_id", + "role" + ], + "properties": { + "role": { + "$ref": "#/components/schemas/TeamRole" + }, + "user_id": { + "type": "integer", + "format": "int32" + } + } + }, + "CreateTeamRequest": { + "type": "object", + "required": [ + "name", + "slug" + ], + "properties": { + "description": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": "string" + }, + "slug": { + "type": "string" + } + } + }, + "CreateUserRequest": { + "type": "object", + "required": [ + "username", + "roles" + ], + "properties": { + "email": { + "type": [ + "string", + "null" + ] + }, + "password": { + "type": [ + "string", + "null" + ] + }, + "roles": { + "type": "array", + "items": { + "type": "string" + } + }, + "username": { + "type": "string" + } + } + }, + "CreateWebhookProviderRequest": { + "type": "object", + "required": [ + "name", + "config" + ], + "properties": { + "config": { + "$ref": "#/components/schemas/WebhookConfig" + }, + "enabled": { + "type": [ + "boolean", + "null" + ] + }, + "name": { + "type": "string" + } + } + }, + "CreateWebhookRequestBody": { + "type": "object", + "required": [ + "url", + "events" + ], + "properties": { + "enabled": { + "type": [ + "boolean", + "null" + ], + "description": "Whether the webhook is enabled", + "default": true + }, + "events": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Event types to subscribe to", + "example": [ + "deployment.created", + "deployment.succeeded" + ] + }, + "secret": { + "type": [ + "string", + "null" + ], + "description": "Secret for HMAC signature verification (optional)" + }, + "url": { + "type": "string", + "description": "Target URL for webhook delivery", + "example": "https://example.com/webhook" + } + } + }, + "CreatedResource": { + "type": "object", + "description": "Resource created during import (for rollback / audit)", + "required": [ + "resource_type", + "resource_id", + "resource_name" + ], + "properties": { + "resource_id": { + "type": "integer", + "format": "int32", + "description": "Resource ID" + }, + "resource_name": { + "type": "string", + "description": "Resource name" + }, + "resource_type": { + "type": "string", + "description": "Resource type (project, environment, deployment, service, domain, etc.)" + } + } + }, + "CronExecutionInfo": { + "type": "object", + "required": [ + "id", + "cron_id", + "executed_at", + "url", + "status_code", + "headers", + "response_time_ms" + ], + "properties": { + "cron_id": { + "type": "integer", + "format": "int32" + }, + "error_message": { + "type": [ + "string", + "null" + ] + }, + "executed_at": { + "type": "string" + }, + "headers": { + "type": "string" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "response_time_ms": { + "type": "integer", + "format": "int32" + }, + "status_code": { + "type": "integer", + "format": "int32" + }, + "url": { + "type": "string" + } + } + }, + "CronInfo": { + "type": "object", + "required": [ + "id", + "project_id", + "environment_id", + "path", + "schedule", + "created_at", + "updated_at" + ], + "properties": { + "created_at": { + "type": "string" + }, + "deleted_at": { + "type": [ + "string", + "null" + ] + }, + "environment_id": { + "type": "integer", + "format": "int32" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "next_run": { + "type": [ + "string", + "null" + ] + }, + "path": { + "type": "string" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "schedule": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + } + }, + "CrossProjectSiblingRef": { + "type": "object", + "description": "A sibling project that shares the same `trace_id`, returned by the\nPhase 1 cross-project banner endpoint.", + "required": [ + "project_id", + "project_name", + "project_slug", + "first_seen" + ], + "properties": { + "first_seen": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 timestamp (UTC, `Z` suffix) of first span ingest for this\n`(trace_id, project_id)` pair." + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "project_name": { + "type": "string" + }, + "project_slug": { + "type": "string", + "description": "URL slug used to link into the sibling project's single-project trace view." + } + } + }, + "CrossProjectTraceResponse": { + "type": "object", + "description": "Response body for `GET /otel/traces/cross-project/{trace_id}`.\n\nAn empty `siblings` vec is the normal single-project case \u2014 never 404.", + "required": [ + "trace_id", + "siblings" + ], + "properties": { + "siblings": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CrossProjectSiblingRef" + }, + "description": "Projects other than the caller's that hold spans for this trace,\nordered by `first_seen ASC`." + }, + "trace_id": { + "type": "string", + "description": "The trace_id that was queried (echoed back for client convenience)." + } + } + }, + "CurrentStatusResponse": { + "type": "object", + "required": [ + "monitor_id", + "current_status", + "uptime_percentage" + ], + "properties": { + "avg_response_time_ms": { + "type": [ + "number", + "null" + ], + "format": "double" + }, + "current_status": { + "type": "string" + }, + "last_check_at": { + "type": [ + "string", + "null" + ], + "format": "date-time" + }, + "monitor_id": { + "type": "integer", + "format": "int32" + }, + "uptime_percentage": { + "type": "number", + "format": "double" + } + } + }, + "CustomDomainRequest": { + "type": "object", + "required": [ + "domain", + "environment_id" + ], + "properties": { + "branch": { + "type": [ + "string", + "null" + ] + }, + "domain": { + "type": "string" + }, + "environment_id": { + "type": "integer", + "format": "int32" + }, + "redirect_to": { + "type": [ + "string", + "null" + ] + }, + "service_name": { + "type": [ + "string", + "null" + ], + "description": "Docker Compose service name this domain routes to (only for docker-compose projects)" + }, + "status_code": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + } + }, + "CustomDomainResponse": { + "type": "object", + "required": [ + "id", + "project_id", + "domain", + "status", + "created_at", + "updated_at" + ], + "properties": { + "branch": { + "type": [ + "string", + "null" + ] + }, + "created_at": { + "type": "integer", + "format": "int64" + }, + "domain": { + "type": "string" + }, + "domain_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "environment": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/DomainEnvironmentResponse" + } + ] + }, + "expiration_time": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "last_renewed": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "message": { + "type": [ + "string", + "null" + ] + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "redirect_to": { + "type": [ + "string", + "null" + ] + }, + "service_name": { + "type": [ + "string", + "null" + ], + "description": "Docker Compose service name this domain routes to" + }, + "status": { + "type": "string" + }, + "status_code": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "updated_at": { + "type": "integer", + "format": "int64" + } + } + }, + "CustomerMovementResponse": { + "type": "object", + "required": [ + "bucket", + "new_customers", + "churned_customers" + ], + "properties": { + "bucket": { + "type": "string", + "format": "date-time" + }, + "churned_customers": { + "type": "integer", + "format": "int64" + }, + "new_customers": { + "type": "integer", + "format": "int64" + } + } + }, + "DashboardLayout": { + "type": "object", + "description": "The typed layout persisted (as JSONB) in `metric_dashboards.layout`.", + "required": [ + "sections" + ], + "properties": { + "sections": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DashboardSection" + }, + "description": "Ordered sections that make up the dashboard." + } + } + }, + "DashboardProjectsAnalyticsQuery": { + "type": "object", + "description": "Query parameters for batch dashboard analytics", + "required": [ + "project_ids", + "start_date", + "end_date" + ], + "properties": { + "end_date": { + "type": "string", + "format": "date-time", + "description": "End date for the query range" + }, + "project_ids": { + "type": "string", + "description": "Comma-separated list of project IDs" + }, + "start_date": { + "type": "string", + "format": "date-time", + "description": "Start date for the query range" + } + } + }, + "DashboardProjectsAnalyticsResponse": { + "type": "object", + "description": "Batch response for dashboard project analytics", + "required": [ + "projects" + ], + "properties": { + "projects": { + "type": "object", + "description": "Map of project_id -> analytics data", + "additionalProperties": { + "$ref": "#/components/schemas/ProjectDashboardAnalytics" + }, + "propertyNames": { + "type": "string" + } + } + } + }, + "DashboardSection": { + "type": "object", + "description": "A titled group of tiles within a dashboard.", + "required": [ + "id", + "title", + "tiles" + ], + "properties": { + "id": { + "type": "string", + "description": "Stable client-generated section id." + }, + "tiles": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DashboardTile" + }, + "description": "Tiles rendered within this section." + }, + "title": { + "type": "string", + "description": "Section heading." + } + } + }, + "DashboardTile": { + "type": "object", + "description": "A single metric tile within a dashboard section.", + "required": [ + "id", + "metric_name", + "aggregation" + ], + "properties": { + "aggregation": { + "type": "string", + "description": "Aggregation applied per bucket: one of\n`avg|sum|min|max|count|rate|p50|p90|p95|p99`." + }, + "group_by": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Label keys to break the metric down by (group-by / multi-series view).\nEmpty = single aggregated series (current behavior). Max 2 keys \u2014 more\ndimensions are unreadable in a chart (ADR-026 Phase 2). Each key must\nmatch `[a-zA-Z0-9_.:-]`. Wired directly to `MetricQuery.group_by` by\nthe tile query path (separate frontend task)." + }, + "id": { + "type": "string", + "description": "Stable client-generated tile id (used as a React key / for reordering)." + }, + "label_filters": { + "type": "array", + "items": { + "type": "array", + "items": false, + "prefixItems": [ + { + "type": "string" + }, + { + "type": "string" + } + ] + }, + "description": "AND-combined label equality filters: `[[\"key\",\"value\"],\u2026]`. Empty = no\nfiltering. Max 10 pairs; keys must match `[a-zA-Z0-9_.:-]`; values\ncapped at 500 characters. Not yet wired into the tile query path\n(Phase 1 ADR-026 \u2014 field round-trips and validates; query wiring is\na separate frontend task)." + }, + "metric_name": { + "type": "string", + "description": "The metric name to chart (e.g. `http.server.duration`)." + }, + "title": { + "type": [ + "string", + "null" + ], + "description": "Optional display title; falls back to the metric name in the UI." + } + } + }, + "DataImplication": { + "type": "object", + "description": "A specific data implication the user needs to understand", + "required": [ + "severity", + "message" + ], + "properties": { + "message": { + "type": "string", + "description": "Human-readable description of what could happen" + }, + "recommended_action": { + "type": [ + "string", + "null" + ], + "description": "What the user should do about it (if anything)" + }, + "severity": { + "$ref": "#/components/schemas/DataImplicationSeverity", + "description": "Severity of this implication" + } + } + }, + "DataImplicationSeverity": { + "type": "string", + "description": "Severity of a data implication", + "enum": [ + "info", + "warning", + "data-not-migrated", + "potential-data-loss" + ] + }, + "DatabaseMetricsResponse": { + "type": "object", + "description": "Response for the per-database metrics breakdown.", + "required": [ + "databases" + ], + "properties": { + "databases": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DatabaseMetricsRow" + }, + "description": "One entry per database, sorted by the first metric descending\n(largest first) so the biggest database leads the table." + } + } + }, + "DatabaseMetricsRow": { + "type": "object", + "description": "Per-database metric values for a Postgres service.\n\nA Postgres instance can host many databases (some unrelated to this\nservice). The collector records per-`datname` series; this groups the\nlatest value of each requested metric by database so the UI can render a\n\"Databases\" breakdown table instead of one collapsed number.", + "required": [ + "database", + "metrics" + ], + "properties": { + "database": { + "type": "string", + "description": "Database name (`datname`)." + }, + "metrics": { + "type": "object", + "description": "Latest value of each requested metric for this database\n(e.g. `{\"pg.database_size_bytes\": 7943871, \"pg.cache_hit_ratio\": 0.99}`).", + "additionalProperties": { + "type": "number", + "format": "double" + }, + "propertyNames": { + "type": "string" + } + } + } + }, + "DelRequest": { + "type": "object", + "description": "Request to delete keys", + "required": [ + "keys" + ], + "properties": { + "keys": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The key(s) to delete", + "example": [ + "user:123", + "user:456" + ] + }, + "project_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Project ID (required for API key/session auth, optional for deployment tokens)", + "example": 1 + } + } + }, + "DelResponse": { + "type": "object", + "description": "Response for delete operation", + "required": [ + "deleted" + ], + "properties": { + "deleted": { + "type": "integer", + "format": "int64", + "description": "Number of keys deleted", + "example": 2 + } + } + }, + "DeleteBlobRequest": { + "type": "object", + "description": "Request to delete blobs", + "required": [ + "pathnames" + ], + "properties": { + "pathnames": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Pathnames to delete (relative to project)", + "example": [ + "images/avatar.png", + "documents/file.pdf" + ] + }, + "projectId": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Project ID (required for API key/session auth, optional for deployment tokens)", + "example": 1 + } + } + }, + "DeleteBlobResponse": { + "type": "object", + "description": "Response after deleting blobs", + "required": [ + "deleted" + ], + "properties": { + "deleted": { + "type": "integer", + "format": "int64", + "description": "Number of blobs deleted", + "example": 2 + } + } + }, + "DeleteResponse": { + "type": "object", + "required": [ + "deleted" + ], + "properties": { + "deleted": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + }, + "DeployFromImageRequest": { + "type": "object", + "properties": { + "external_image_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "External image ID (if already registered). If provided without image_ref,\nthe image reference will be fetched from the registered external image." + }, + "health_check_path": { + "type": [ + "string", + "null" + ], + "description": "Optional HTTP health-check path override (e.g. \"/api/healthz\").\nImage deploys can't read `.temps.yaml`, so this sets the path the deployer\nprobes after the container starts and the path the environment's uptime\nmonitor checks. Must start with '/'. When omitted, defaults to \"/\".", + "example": "/api/healthz" + }, + "image_ref": { + "type": [ + "string", + "null" + ], + "description": "Docker image reference (e.g., \"ghcr.io/org/app:v1.0\")\nRequired if external_image_id is not provided", + "example": "ghcr.io/myorg/myapp:v1.0" + }, + "metadata": { + "description": "Optional deployment metadata" + } + } + }, + "DeployFromImageUploadQuery": { + "type": "object", + "description": "Query parameters for deploying from an uploaded image tarball", + "properties": { + "health_check_path": { + "type": [ + "string", + "null" + ], + "description": "Optional HTTP health-check path override (e.g. \"/api/healthz\").\nMust start with '/'. When omitted, defaults to \"/\".", + "example": "/api/healthz" + }, + "tag": { + "type": [ + "string", + "null" + ], + "description": "Tag to apply to the imported image (e.g., \"myapp:v1.0\")\nIf not provided, a unique tag will be generated", + "example": "myapp:v1.0" + } + } + }, + "DeployFromStaticRequest": { + "type": "object", + "required": [ + "static_bundle_id" + ], + "properties": { + "health_check_path": { + "type": [ + "string", + "null" + ], + "description": "Optional HTTP health-check path override (e.g. \"/api/healthz\").\nStatic deploys can't read `.temps.yaml`, so this sets the path the deployer\nprobes after the container starts and the path the environment's uptime\nmonitor checks. Must start with '/'. When omitted, defaults to \"/\".", + "example": "/api/healthz" + }, + "metadata": { + "description": "Optional deployment metadata" + }, + "static_bundle_id": { + "type": "integer", + "format": "int32", + "description": "Static bundle ID (required)" + } + } + }, + "DeploymentConfig": { + "type": "object", + "description": "Deployment configuration shared between projects and environments\n\nThis configuration can be set at the project level (as defaults) and\noverridden at the environment level for specific deployments.\n\nNote: Environment variables are managed separately and are not part of this config.", + "properties": { + "antiAffinity": { + "type": "boolean", + "description": "Anti-affinity: spread replicas across different nodes.\n\nWhen enabled, the scheduler avoids placing two replicas of the same\nenvironment on the same node. If there are fewer eligible nodes than\nreplicas, remaining replicas wrap around (best-effort spreading).\n\nDefaults to `true` \u2014 replicas spread by default." + }, + "automaticDeploy": { + "type": [ + "boolean", + "null" + ], + "description": "Enable automatic deployments on git push.\n`None` = inherit from project config; `Some(true/false)` = explicit override.\nStored as JSONB so absent key \u2192 `None` (inherit), never silently defaults to false." + }, + "containerExecEnabled": { + "type": "boolean", + "description": "Enable container exec/shell access (disabled by default for security)" + }, + "cpuLimit": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "CPU limit in microcores, where 1_000_000 = 1 full CPU core\n(e.g., 2_000_000 = 2 CPUs). NOT millicores. `None` = uncapped." + }, + "cpuRequest": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "CPU request in microcores, where 1_000_000 = 1 full CPU core\n(e.g., 100_000 = 0.1 CPU, 500_000 = 0.5 CPU, 2_000_000 = 2 CPUs).\nNOT millicores \u2014 the deployer formats this as `{n}u` and converts\n`n / 1_000_000` cores into Docker nano_cpus." + }, + "crossArchitectureBuilds": { + "type": [ + "boolean", + "null" + ], + "description": "Build one image per architecture the eligible nodes run.\n\n`None`/`false` (the default) builds exactly once, on the control\nplane's native platform \u2014 byte-for-byte the behaviour of a\nsingle-architecture cluster. When enabled and the nodes this\ndeployment could land on span more than one architecture, the build\njob produces one image per architecture; the non-native ones go\nthrough the daemon's `platform` option, which requires QEMU binfmt\nhandlers registered on the control plane.\n\n**Opt-in on purpose.** Cross-architecture builds are emulated and\nsubstantially slower, and deriving them from cluster topology would\nmean a single node joining silently changes build behaviour for every\ndeployment in the cluster. It also keeps the decision on operator\nconfig rather than on a value each node reports about itself.\n\n`Option` so an environment inherits the project's setting\n(`None`) or overrides it, matching `automatic_deploy`." + }, + "exposedPort": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Port exposed by the container\nIf not specified, will be auto-detected from Docker image or default to 3000" + }, + "idleTimeoutSeconds": { + "type": "integer", + "format": "int32", + "description": "Seconds of inactivity before containers are stopped in on-demand mode.\nOnly used when `on_demand` is true. Min: 60, Max: 86400 (24h).\nDefault: 300 (5 minutes)." + }, + "memoryLimit": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Memory limit in megabytes. Three-state semantics:\n- `None` \u2192 inherit the parent layer (env inherits project, project\n inherits the seeded default); used by the settings UI's \"Use default\".\n- `Some(0)` \u2192 explicit **uncapped**: stop inheriting and run with no\n memory limit. This is the deliberate escape hatch for dedicated\n workloads, distinct from `None`.\n- `Some(n)` \u2192 hard cap of `n` MB.\n\n`merge`/resolution keep `Some(0)` as a present value (it wins precedence\nover a parent cap), and the deployer collapses it to \"no limit\" before\ntalking to Docker." + }, + "memoryRequest": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Memory request in megabytes (e.g., 128 = 128MB)" + }, + "onDemand": { + "type": "boolean", + "description": "Enable on-demand mode (scale-to-zero).\nWhen enabled, containers are stopped after `idle_timeout_seconds` of no traffic\nand automatically started when a new request arrives." + }, + "performanceMetricsEnabled": { + "type": "boolean", + "description": "Enable performance metrics collection (speed insights)" + }, + "replicas": { + "type": "integer", + "format": "int32", + "description": "Number of replicas/instances to run\nDefaults to 1 replica" + }, + "security": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/SecurityConfig", + "description": "Security configuration (headers, rate limiting, attack mode, etc.)\nThese settings inherit and override from parent level (Environment > Project > Global)" + } + ] + }, + "sessionRecordingEnabled": { + "type": "boolean", + "description": "Enable session recording for analytics" + }, + "targetLabels": { + "description": "Label selector for node-based scheduling. Replicas are only deployed to\nnodes whose labels match the selector.\n\nMatching rules:\n- **Same key, array value** \u2192 OR: node must match any value\n- **Different keys** \u2192 AND: node must satisfy all keys\n\nExample: `{\"region\": [\"us\", \"asia\"], \"gpu\": \"true\"}`\n\u2192 (region=us OR region=asia) AND gpu=true\n\nApplied after `target_nodes` filtering (they stack)." + }, + "targetNodes": { + "type": [ + "array", + "null" + ], + "items": { + "type": "integer", + "format": "int32" + }, + "description": "Optional list of node IDs to deploy to. When set, replicas are distributed\nonly across these nodes (round-robin). When None, the scheduler distributes\nacross all active nodes (or deploys locally if no nodes exist)." + }, + "wakeTimeoutSeconds": { + "type": "integer", + "format": "int32", + "description": "Max seconds to wait for containers to start when waking from on-demand sleep.\nRequests return 503 if exceeded. Default: 30." + } + } + }, + "DeploymentConfigSnapshot": { + "type": "object", + "description": "Deployment configuration snapshot for deployments\n\nThis extends DeploymentConfig with environment variables to capture\nthe complete state of a deployment at the time it was created.", + "properties": { + "automaticDeploy": { + "type": "boolean", + "description": "Enable automatic deployments on git push" + }, + "containerExecEnabled": { + "type": "boolean", + "description": "Enable container exec/shell access" + }, + "cpuLimit": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "CPU limit in millicores" + }, + "cpuRequest": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "CPU request in millicores" + }, + "environmentVariables": { + "type": "object", + "description": "Environment variables used for this deployment", + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + } + }, + "exposedPort": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Port exposed by the container" + }, + "memoryLimit": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Memory limit in megabytes" + }, + "memoryRequest": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Memory request in megabytes" + }, + "performanceMetricsEnabled": { + "type": "boolean", + "description": "Enable performance metrics collection" + }, + "replicas": { + "type": "integer", + "format": "int32", + "description": "Number of replicas" + }, + "sessionRecordingEnabled": { + "type": "boolean", + "description": "Enable session recording" + } + } + }, + "DeploymentConfiguration": { + "type": "object", + "description": "Deployment-level configuration", + "required": [ + "image", + "strategy", + "env_vars", + "ports", + "volumes", + "network", + "resources" + ], + "properties": { + "build": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/BuildConfiguration", + "description": "Build configuration (if building from source)" + } + ] + }, + "command": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + }, + "description": "Command override" + }, + "entrypoint": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + }, + "description": "Entrypoint override" + }, + "env_vars": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EnvironmentVariable" + }, + "description": "Environment variables" + }, + "git": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/GitSourcePlan", + "description": "Where the application's source code lives, when the source platform\nbuilds from a git repository. Execution uses this to link the temps\nproject to the same repository so the real deployment pipeline can\nclone and build it." + } + ] + }, + "health_check": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/HealthCheckConfiguration", + "description": "Health check configuration" + } + ] + }, + "image": { + "type": "string", + "description": "Image to deploy" + }, + "network": { + "$ref": "#/components/schemas/NetworkConfiguration", + "description": "Network configuration" + }, + "ports": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PortMapping" + }, + "description": "Port mappings" + }, + "resources": { + "$ref": "#/components/schemas/ResourceLimits", + "description": "Resource limits" + }, + "strategy": { + "$ref": "#/components/schemas/DeploymentStrategy", + "description": "Deployment strategy" + }, + "volumes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/VolumeMount" + }, + "description": "Volume mounts" + }, + "working_dir": { + "type": [ + "string", + "null" + ], + "description": "Working directory" + } + } + }, + "DeploymentContainerLogContentResponse": { + "type": "object", + "description": "A single captured container-log dump, including its full text content.", + "required": [ + "id", + "container_name", + "size_bytes", + "truncated", + "captured_at", + "content" + ], + "properties": { + "captured_at": { + "type": "integer", + "format": "int64" + }, + "container_name": { + "type": "string" + }, + "content": { + "type": "string", + "description": "The captured plain-text log content." + }, + "id": { + "type": "integer", + "format": "int32" + }, + "service_name": { + "type": [ + "string", + "null" + ] + }, + "size_bytes": { + "type": "integer", + "format": "int64" + }, + "truncated": { + "type": "boolean" + } + } + }, + "DeploymentContainerLogResponse": { + "type": "object", + "description": "Metadata for one captured (historical) container-log dump. Listed on the\ndeployment detail page so a user can pick which past container's logs to read.", + "required": [ + "id", + "deployment_id", + "container_id", + "container_name", + "size_bytes", + "truncated", + "captured_at" + ], + "properties": { + "captured_at": { + "type": "integer", + "format": "int64", + "description": "Unix epoch milliseconds of when the logs were captured (just before\nteardown). Matches the timestamp convention used by `DeploymentResponse`." + }, + "container_id": { + "type": "string" + }, + "container_name": { + "type": "string" + }, + "deployment_id": { + "type": "integer", + "format": "int32" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "node_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "service_name": { + "type": [ + "string", + "null" + ] + }, + "size_bytes": { + "type": "integer", + "format": "int64" + }, + "truncated": { + "type": "boolean" + } + } + }, + "DeploymentContainerLogsListResponse": { + "type": "object", + "description": "The list of captured container-log dumps for a deployment.", + "required": [ + "logs" + ], + "properties": { + "logs": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DeploymentContainerLogResponse" + } + } + } + }, + "DeploymentEnvironmentResponse": { + "type": "object", + "required": [ + "id", + "name", + "slug", + "domains" + ], + "properties": { + "domains": { + "type": "array", + "items": { + "type": "string" + } + }, + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "slug": { + "type": "string" + } + } + }, + "DeploymentJobResponse": { + "type": "object", + "required": [ + "id", + "deployment_id", + "job_id", + "job_type", + "name", + "status", + "created_at", + "updated_at", + "log_id" + ], + "properties": { + "created_at": { + "type": "integer", + "format": "int64" + }, + "dependencies": {}, + "deployment_id": { + "type": "integer", + "format": "int32" + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "error_message": { + "type": [ + "string", + "null" + ] + }, + "execution_order": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "finished_at": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "job_config": { + "description": "Internal workflow configuration is intentionally redacted. It can\ncontain legacy plaintext secrets or encrypted secret envelopes." + }, + "job_id": { + "type": "string" + }, + "job_type": { + "type": "string" + }, + "log_id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "outputs": {}, + "started_at": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "status": { + "type": "string" + }, + "updated_at": { + "type": "integer", + "format": "int64" + } + } + }, + "DeploymentJobsResponse": { + "type": "object", + "required": [ + "jobs", + "total" + ], + "properties": { + "jobs": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DeploymentJobResponse" + } + }, + "total": { + "type": "integer", + "minimum": 0 + } + } + }, + "DeploymentListResponse": { + "type": "object", + "required": [ + "deployments", + "total", + "page", + "per_page" + ], + "properties": { + "deployments": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DeploymentResponse" + } + }, + "page": { + "type": "integer", + "format": "int64" + }, + "per_page": { + "type": "integer", + "format": "int64" + }, + "total": { + "type": "integer", + "format": "int64" + } + } + }, + "DeploymentMetadata": { + "type": "object", + "description": "Deployment metadata - typed information about the deployment", + "properties": { + "buildDurationMs": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Build duration in milliseconds" + }, + "builder": { + "type": [ + "string", + "null" + ], + "description": "Docker builder used (e.g., \"nixpacks\", \"dockerfile\")" + }, + "deploymentDurationMs": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Deployment duration in milliseconds" + }, + "deploymentSourceType": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/SourceType", + "description": "Source type for THIS specific deployment (for Manual/flexible projects)\nThis allows Manual projects to have deployments via different methods\n(docker_image, static_files, or git) while keeping per-deployment tracking" + } + ] + }, + "dockerfilePath": { + "type": [ + "string", + "null" + ], + "description": "Dockerfile path if using Dockerfile builder" + }, + "externalImageId": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "External image ID (reference to external_images table)" + }, + "externalImageRef": { + "type": [ + "string", + "null" + ], + "description": "External Docker image reference (for docker_image source type)\ne.g., \"ghcr.io/org/app:v1.0\" or \"docker.io/myapp:sha-abc123\"" + }, + "fileCount": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Number of files in the build output" + }, + "gitPushEvent": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/GitPushEvent", + "description": "Git push event that triggered this deployment (if from webhook)" + } + ] + }, + "healthCheckPath": { + "type": [ + "string", + "null" + ], + "description": "Explicit deploy-time HTTP health-check path override.\nImage/static deploys can't read `.temps.yaml`, so this lets the deploy\nrequest set a custom path (e.g. \"/api/healthz\"). When present it takes\npriority over any `.temps.yaml` `health.path` value. Always starts with '/'." + }, + "imageSizeBytes": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Total size of the built image in bytes" + }, + "imageUploadedLocally": { + "type": "boolean", + "description": "Whether the image was uploaded directly (via docker save/load) rather than pulled from registry\nWhen true, the PullExternalImageJob is skipped since the image is already loaded locally" + }, + "isRollback": { + "type": "boolean", + "description": "Whether this is a rollback deployment" + }, + "labels": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Custom labels/tags for the deployment" + }, + "rolledBackFromId": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "ID of the deployment this was rolled back from (if applicable)" + }, + "staticBundleContentType": { + "type": [ + "string", + "null" + ], + "description": "Static bundle content type (for proper extraction: application/gzip or application/zip)" + }, + "staticBundleId": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Static bundle ID (reference to static_bundles table, for static_files source type)" + }, + "staticBundlePath": { + "type": [ + "string", + "null" + ], + "description": "Static bundle path in blob storage (for static_files source type)" + }, + "uploadedImageId": { + "type": [ + "string", + "null" + ], + "description": "Docker image ID of the locally uploaded image (sha256:...)\nUsed to verify the image exists before deployment" + } + } + }, + "DeploymentResponse": { + "type": "object", + "required": [ + "id", + "project_id", + "environment_id", + "environment", + "status", + "url", + "created_at", + "is_current" + ], + "properties": { + "branch": { + "type": [ + "string", + "null" + ] + }, + "cancelled_reason": { + "type": [ + "string", + "null" + ] + }, + "commit_author": { + "type": [ + "string", + "null" + ] + }, + "commit_date": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "commit_hash": { + "type": [ + "string", + "null" + ] + }, + "commit_message": { + "type": [ + "string", + "null" + ] + }, + "created_at": { + "type": "integer", + "format": "int64" + }, + "deployment_config": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/DeploymentConfigSnapshot", + "description": "Deployment configuration snapshot (CPU, memory, replicas, environment variables, etc.)" + } + ] + }, + "environment": { + "$ref": "#/components/schemas/DeploymentEnvironmentResponse" + }, + "environment_id": { + "type": "integer", + "format": "int32" + }, + "finished_at": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "is_current": { + "type": "boolean" + }, + "metadata": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/DeploymentMetadata", + "description": "Deployment metadata (build info, git event, etc.)" + } + ] + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "screenshot_location": { + "type": [ + "string", + "null" + ] + }, + "started_at": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "status": { + "type": "string" + }, + "tag": { + "type": [ + "string", + "null" + ] + }, + "url": { + "type": "string" + } + } + }, + "DeploymentStateResponse": { + "type": "object", + "required": [ + "id", + "state", + "message" + ], + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "state": { + "type": "string" + } + } + }, + "DeploymentStrategy": { + "type": "string", + "description": "Deployment strategy", + "enum": [ + "replace", + "blue-green", + "rolling" + ] + }, + "DeploymentTokenListResponse": { + "type": "object", + "required": [ + "tokens", + "total" + ], + "properties": { + "tokens": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DeploymentTokenResponse" + } + }, + "total": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + }, + "DeploymentTokenResponse": { + "type": "object", + "required": [ + "id", + "project_id", + "name", + "token_prefix", + "is_active", + "created_at" + ], + "properties": { + "created_at": { + "type": "string", + "format": "date-time", + "example": "2024-01-01T00:00:00Z" + }, + "created_by": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "deployment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "expires_at": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "example": "2024-12-31T23:59:59Z" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "is_active": { + "type": "boolean" + }, + "last_used_at": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "example": "2024-01-01T00:00:00Z" + }, + "name": { + "type": "string" + }, + "permissions": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "token_prefix": { + "type": "string" + } + } + }, + "DetectionConfig": { + "oneOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/StaticParams", + "description": "v0 (shipping): static threshold comparison of the aggregated value." + }, + { + "type": "object", + "required": [ + "kind" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "static" + ] + } + } + } + ], + "description": "v0 (shipping): static threshold comparison of the aggregated value." + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/AnomalyParams", + "description": "Seasonal anomaly band (basic/agile/robust/ewma share this variant \u2014 the\nalgorithm is a field, not a new kind). Creation rejected until evaluated." + }, + { + "type": "object", + "required": [ + "kind" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "anomaly" + ] + } + } + } + ], + "description": "Seasonal anomaly band (basic/agile/robust/ewma share this variant \u2014 the\nalgorithm is a field, not a new kind). Creation rejected until evaluated." + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/ForecastParams", + "description": "Predict a future threshold breach (capacity planning). Stub." + }, + { + "type": "object", + "required": [ + "kind" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "forecast" + ] + } + } + } + ], + "description": "Predict a future threshold breach (capacity planning). Stub." + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/OutlierParams", + "description": "Cross-series population outlier (one host misbehaving vs its peers). Stub." + }, + { + "type": "object", + "required": [ + "kind" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "outlier" + ] + } + } + } + ], + "description": "Cross-series population outlier (one host misbehaving vs its peers). Stub." + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/AutoWatchParams", + "description": "Watchdog-style self-tuning auto-watch (engine picks bounds). Stub." + }, + { + "type": "object", + "required": [ + "kind" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "auto_watch" + ] + } + } + } + ], + "description": "Watchdog-style self-tuning auto-watch (engine picks bounds). Stub." + } + ], + "description": "The typed detector definition stored (as jsonb) in\n`metric_alert_rules.detection_config`.\n\nToday only [`DetectionConfig::Static`] is evaluable; the other variants are\nschema-present (so the SDK/UI and storage are already future-shaped) but\nrejected by [`DetectionConfig::validate`] until their evaluator lands. Each is\nthen enabled code-only, with no schema migration." + }, + "DeviceCount": { + "type": "object", + "required": [ + "device_type", + "count", + "percentage" + ], + "properties": { + "count": { + "type": "integer", + "format": "int64" + }, + "device_type": { + "type": "string" + }, + "percentage": { + "type": "number", + "format": "double" + } + } + }, + "DigestSections": { + "type": "object", + "description": "Sections that can be included in the weekly digest\nNote: `#[serde(default)]` allows backward compatibility when deserializing\nold data that may have `security` and `resources` fields instead of `projects`", + "properties": { + "deployments": { + "type": "boolean", + "default": true + }, + "errors": { + "type": "boolean", + "default": true + }, + "funnels": { + "type": "boolean", + "default": true + }, + "performance": { + "type": "boolean", + "default": true + }, + "projects": { + "type": "boolean", + "default": true + } + } + }, + "Direction": { + "type": "string", + "description": "Which side(s) of an anomaly band count as a deviation.", + "enum": [ + "both", + "above", + "below" + ] + }, + "DisableBlobResponse": { + "type": "object", + "description": "Response after disabling Blob service", + "required": [ + "success", + "message" + ], + "properties": { + "message": { + "type": "string", + "description": "Human-readable message", + "example": "Blob service disabled successfully" + }, + "success": { + "type": "boolean", + "description": "Whether the operation succeeded", + "example": true + } + } + }, + "DisableKvResponse": { + "type": "object", + "description": "Response after disabling KV service", + "required": [ + "success", + "message" + ], + "properties": { + "message": { + "type": "string", + "description": "Status message", + "example": "KV service disabled successfully" + }, + "success": { + "type": "boolean", + "description": "Whether the service was successfully disabled" + } + } + }, + "DisableMfaRequest": { + "type": "object", + "required": [ + "code" + ], + "properties": { + "code": { + "type": "string" + } + } + }, + "DiscoverRequest": { + "type": "object", + "description": "Request to discover workloads", + "required": [ + "source" + ], + "properties": { + "credentials": { + "$ref": "#/components/schemas/ImportCredentials", + "description": "Platform credentials (required for cloud platforms like Vercel, Railway)" + }, + "selector": { + "$ref": "#/components/schemas/ImportSelector", + "description": "Optional selector to filter workloads" + }, + "source": { + "$ref": "#/components/schemas/ImportSource", + "description": "Source to discover from" + } + } + }, + "DiscoverResponse": { + "type": "object", + "description": "Response with discovered workloads", + "required": [ + "workloads" + ], + "properties": { + "workloads": { + "type": "array", + "items": { + "$ref": "#/components/schemas/WorkloadDescriptor" + }, + "description": "Discovered workloads" + } + } + }, + "DiskInfo": { + "type": "object", + "description": "Disk space information for a single disk/partition", + "required": [ + "mount_point", + "total_bytes", + "used_bytes", + "available_bytes", + "usage_percent", + "file_system" + ], + "properties": { + "available_bytes": { + "type": "integer", + "format": "int64", + "description": "Available space in bytes", + "minimum": 0 + }, + "file_system": { + "type": "string", + "description": "File system type (e.g., \"ext4\", \"apfs\")" + }, + "mount_point": { + "type": "string", + "description": "Mount point of the disk" + }, + "total_bytes": { + "type": "integer", + "format": "int64", + "description": "Total space in bytes", + "minimum": 0 + }, + "usage_percent": { + "type": "number", + "format": "double", + "description": "Usage percentage (0-100)" + }, + "used_bytes": { + "type": "integer", + "format": "int64", + "description": "Used space in bytes", + "minimum": 0 + } + } + }, + "DiskSpaceAlert": { + "type": "object", + "description": "Alert for a disk that exceeds the threshold", + "required": [ + "mount_point", + "usage_percent", + "threshold_percent", + "available_bytes", + "available_human" + ], + "properties": { + "available_bytes": { + "type": "integer", + "format": "int64", + "description": "Available space in bytes", + "minimum": 0 + }, + "available_human": { + "type": "string", + "description": "Human-readable available space" + }, + "mount_point": { + "type": "string", + "description": "Mount point of the disk" + }, + "threshold_percent": { + "type": "integer", + "format": "int32", + "description": "Configured threshold percentage", + "minimum": 0 + }, + "usage_percent": { + "type": "number", + "format": "double", + "description": "Current usage percentage" + } + } + }, + "DiskSpaceAlertSettings": { + "type": "object", + "description": "Disk space alert settings for monitoring disk usage", + "properties": { + "check_interval_seconds": { + "type": "integer", + "format": "int64", + "description": "Interval in seconds between disk space checks", + "default": 300, + "example": 300, + "minimum": 60 + }, + "enabled": { + "type": "boolean", + "description": "Whether disk space alerts are enabled", + "default": true + }, + "monitor_path": { + "type": [ + "string", + "null" + ], + "description": "Restrict monitoring to the disk backing this path. When unset (the\ndefault), every mounted writable volume is monitored \u2014 including\ndedicated volumes such as `/var/lib/docker`.", + "default": null + }, + "threshold_percent": { + "type": "integer", + "format": "int32", + "description": "Threshold percentage (0-100) at which to trigger alerts", + "default": 80, + "example": 80, + "maximum": 100, + "minimum": 0 + } + } + }, + "DiskSpaceCheckResult": { + "type": "object", + "description": "Result of a disk space check", + "required": [ + "checked_at", + "enabled", + "threshold_percent", + "disks", + "alerts" + ], + "properties": { + "alerts": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DiskSpaceAlert" + }, + "description": "Disks that meet or exceed the threshold" + }, + "checked_at": { + "type": "string", + "format": "date-time", + "description": "Timestamp of the check (ISO 8601, UTC)", + "example": "2026-05-28T12:15:47.609192Z" + }, + "disks": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DiskInfo" + }, + "description": "List of all monitored disks" + }, + "enabled": { + "type": "boolean", + "description": "Whether disk space monitoring is enabled in settings" + }, + "threshold_percent": { + "type": "integer", + "format": "int32", + "description": "Configured alert threshold percentage (0-100)", + "minimum": 0 + } + } + }, + "DnsAckRequest": { + "type": "object", + "required": [ + "applied_generation" + ], + "properties": { + "applied_generation": { + "type": "integer", + "format": "int64", + "description": "Highest generation the agent has actually applied locally." + } + } + }, + "DnsAckResponse": { + "type": "object", + "required": [ + "node_id", + "applied_generation", + "server_generation" + ], + "properties": { + "applied_generation": { + "type": "integer", + "format": "int64" + }, + "node_id": { + "type": "integer", + "format": "int32" + }, + "server_generation": { + "type": "integer", + "format": "int64" + } + } + }, + "DnsChallengeRecordResult": { + "type": "object", + "description": "Result of a single DNS TXT record creation for ACME challenge", + "required": [ + "name", + "value", + "success", + "message" + ], + "properties": { + "message": { + "type": "string", + "description": "Human-readable message about the operation" + }, + "name": { + "type": "string", + "description": "TXT record name (e.g., \"_acme-challenge.example.com\")", + "example": "_acme-challenge.example.com" + }, + "success": { + "type": "boolean", + "description": "Whether the record was created successfully" + }, + "value": { + "type": "string", + "description": "TXT record value (the ACME challenge token)", + "example": "abc123..." + } + } + }, + "DnsChangesResponse": { + "type": "object", + "required": [ + "generation", + "full_snapshot", + "records", + "removed_ids" + ], + "properties": { + "full_snapshot": { + "type": "boolean", + "description": "`true` \u21d2 replace the local zone with `records`. `false` \u21d2 merge\n`records` into the existing zone (and remove `removed_ids`)." + }, + "generation": { + "type": "integer", + "format": "int64", + "description": "Highest generation included in this response. Agent ACKs this back." + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EndpointDto" + } + }, + "removed_ids": { + "type": "array", + "items": { + "type": "integer", + "format": "int64" + }, + "description": "IDs the agent should remove from its zone. Always empty in the v1\nprotocol \u2014 the resolver reconciles by name on snapshot mode. Kept\nin the wire format so a future tombstone-based protocol doesn't\nrequire a breaking change." + } + } + }, + "DnsCompletionResponse": { + "type": "object", + "required": [ + "domain", + "status" + ], + "properties": { + "domain": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "DnsLookupError": { + "type": "object", + "description": "Error response for DNS lookup failures", + "required": [ + "error", + "domain" + ], + "properties": { + "domain": { + "type": "string", + "description": "Domain name that failed", + "example": "nonexistent.com" + }, + "error": { + "type": "string", + "description": "Error message", + "example": "DNS lookup failed: domain not found" + } + } + }, + "DnsLookupRequest": { + "type": "object", + "description": "Request to lookup DNS A records for a domain", + "required": [ + "domain" + ], + "properties": { + "domain": { + "type": "string", + "description": "Domain name to lookup", + "example": "example.com" + } + } + }, + "DnsLookupResponse": { + "type": "object", + "description": "Response containing DNS A records", + "required": [ + "domain", + "records", + "count", + "dns_servers" + ], + "properties": { + "count": { + "type": "integer", + "description": "Number of records found", + "example": 1, + "minimum": 0 + }, + "dns_servers": { + "type": "array", + "items": { + "type": "string" + }, + "description": "DNS servers used for the lookup", + "example": [ + "8.8.8.8", + "8.8.4.4" + ] + }, + "domain": { + "type": "string", + "description": "Domain name that was queried", + "example": "example.com" + }, + "records": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of A record IP addresses", + "example": [ + "93.184.216.34" + ] + } + } + }, + "DnsProviderCredentials": { + "oneOf": [ + { + "type": "object", + "required": [ + "api_token", + "type" + ], + "properties": { + "account_id": { + "type": [ + "string", + "null" + ] + }, + "api_token": { + "type": "string", + "example": "your-api-token" + }, + "type": { + "type": "string", + "enum": [ + "cloudflare" + ] + } + } + }, + { + "type": "object", + "required": [ + "api_user", + "api_key", + "type" + ], + "properties": { + "api_key": { + "type": "string", + "example": "your-api-key" + }, + "api_user": { + "type": "string", + "example": "your-username" + }, + "client_ip": { + "type": [ + "string", + "null" + ] + }, + "sandbox": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "namecheap" + ] + } + } + }, + { + "type": "object", + "required": [ + "access_key_id", + "secret_access_key", + "type" + ], + "properties": { + "access_key_id": { + "type": "string", + "example": "AKIAIOSFODNN7EXAMPLE" + }, + "region": { + "type": [ + "string", + "null" + ], + "example": "us-east-1" + }, + "secret_access_key": { + "type": "string", + "example": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" + }, + "session_token": { + "type": [ + "string", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "route53" + ] + } + } + }, + { + "type": "object", + "required": [ + "api_token", + "type" + ], + "properties": { + "api_token": { + "type": "string", + "example": "dop_v1_your-token" + }, + "type": { + "type": "string", + "enum": [ + "digitalocean" + ] + } + } + }, + { + "type": "object", + "required": [ + "service_account_email", + "private_key", + "project_id", + "type" + ], + "properties": { + "private_key": { + "type": "string", + "example": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----" + }, + "project_id": { + "type": "string", + "example": "my-gcp-project" + }, + "service_account_email": { + "type": "string", + "example": "dns-admin@myproject.iam.gserviceaccount.com" + }, + "type": { + "type": "string", + "enum": [ + "gcp" + ] + } + } + }, + { + "type": "object", + "required": [ + "tenant_id", + "client_id", + "client_secret", + "subscription_id", + "resource_group", + "type" + ], + "properties": { + "client_id": { + "type": "string", + "example": "00000000-0000-0000-0000-000000000000" + }, + "client_secret": { + "type": "string" + }, + "resource_group": { + "type": "string", + "example": "my-resource-group" + }, + "subscription_id": { + "type": "string", + "example": "00000000-0000-0000-0000-000000000000" + }, + "tenant_id": { + "type": "string", + "example": "00000000-0000-0000-0000-000000000000" + }, + "type": { + "type": "string", + "enum": [ + "azure" + ] + } + } + }, + { + "type": "object", + "description": "Pebble challtestsrv mock DNS (LOCAL DEV/TEST ONLY)", + "required": [ + "management_url", + "type" + ], + "properties": { + "management_url": { + "type": "string", + "example": "http://localhost:8055" + }, + "type": { + "type": "string", + "enum": [ + "pebble" + ] + } + } + } + ], + "description": "DNS provider credentials (API-facing)" + }, + "DnsProviderResponse": { + "type": "object", + "description": "DNS provider response", + "required": [ + "id", + "name", + "provider_type", + "credentials", + "is_active", + "flat_hostnames_supported", + "created_at", + "updated_at" + ], + "properties": { + "created_at": { + "type": "string" + }, + "credentials": { + "description": "Masked credentials for display" + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "flat_hostnames_supported": { + "type": "boolean", + "description": "Whether this provider benefits from the flat hostname mode (e.g. Cloudflare\nUniversal SSL). The UI surfaces/recommends the Flat toggle when true." + }, + "id": { + "type": "integer", + "format": "int32" + }, + "is_active": { + "type": "boolean" + }, + "last_error": { + "type": [ + "string", + "null" + ] + }, + "last_used_at": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": "string" + }, + "provider_type": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + } + }, + "DnsProviderSettings": { + "type": "object", + "properties": { + "cloudflare_api_key": { + "type": [ + "string", + "null" + ], + "default": null + }, + "provider": { + "type": "string", + "default": "manual" + } + } + }, + "DnsProviderSettingsMasked": { + "type": "object", + "description": "DNS provider settings with masked sensitive fields", + "required": [ + "provider" + ], + "properties": { + "cloudflare_api_key": { + "type": [ + "string", + "null" + ] + }, + "provider": { + "type": "string" + } + } + }, + "DnsProviderType": { + "type": "string", + "description": "Supported DNS provider types", + "enum": [ + "cloudflare", + "namecheap", + "route53", + "digitalocean", + "gcp", + "azure", + "manual", + "pebble" + ] + }, + "DnsRecord": { + "type": "object", + "description": "A DNS record", + "required": [ + "zone", + "name", + "fqdn", + "content", + "ttl" + ], + "properties": { + "content": { + "$ref": "#/components/schemas/DnsRecordContent", + "description": "Record content" + }, + "fqdn": { + "type": "string", + "description": "Fully qualified domain name", + "example": "www.example.com" + }, + "id": { + "type": [ + "string", + "null" + ], + "description": "Provider-specific record ID (if exists)", + "example": "abc123" + }, + "metadata": { + "type": "object", + "description": "Provider-specific metadata", + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + } + }, + "name": { + "type": "string", + "description": "Record name (without zone, e.g., \"www\" or \"@\" for root)", + "example": "www" + }, + "proxied": { + "type": "boolean", + "description": "Whether this record is proxied (Cloudflare-specific)" + }, + "ttl": { + "type": "integer", + "format": "int32", + "description": "Time to live in seconds", + "example": 300, + "minimum": 0 + }, + "zone": { + "type": "string", + "description": "Zone/domain this record belongs to", + "example": "example.com" + } + } + }, + "DnsRecordChange": { + "type": "object", + "description": "A single DNS record change the Cloudflare sync would make.", + "required": [ + "action", + "name", + "record_type", + "value" + ], + "properties": { + "action": { + "type": "string", + "description": "`\"create\"`, `\"update\"`, or `\"delete\"`." + }, + "name": { + "type": "string" + }, + "record_type": { + "type": "string", + "description": "Record type, e.g. `\"A\"` or `\"CNAME\"`." + }, + "value": { + "type": "string" + } + } + }, + "DnsRecordContent": { + "oneOf": [ + { + "type": "object", + "description": "A record - IPv4 address (as string, e.g., \"192.0.2.1\")", + "required": [ + "value", + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "A" + ] + }, + "value": { + "type": "object", + "description": "A record - IPv4 address (as string, e.g., \"192.0.2.1\")", + "required": [ + "address" + ], + "properties": { + "address": { + "type": "string", + "example": "192.0.2.1" + } + } + } + } + }, + { + "type": "object", + "description": "AAAA record - IPv6 address (as string, e.g., \"2001:db8::1\")", + "required": [ + "value", + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "AAAA" + ] + }, + "value": { + "type": "object", + "description": "AAAA record - IPv6 address (as string, e.g., \"2001:db8::1\")", + "required": [ + "address" + ], + "properties": { + "address": { + "type": "string", + "example": "2001:db8::1" + } + } + } + } + }, + { + "type": "object", + "description": "CNAME record - canonical name", + "required": [ + "value", + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "CNAME" + ] + }, + "value": { + "type": "object", + "description": "CNAME record - canonical name", + "required": [ + "target" + ], + "properties": { + "target": { + "type": "string" + } + } + } + } + }, + { + "type": "object", + "description": "TXT record - text content", + "required": [ + "value", + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "TXT" + ] + }, + "value": { + "type": "object", + "description": "TXT record - text content", + "required": [ + "content" + ], + "properties": { + "content": { + "type": "string" + } + } + } + } + }, + { + "type": "object", + "description": "MX record - mail exchange", + "required": [ + "value", + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "MX" + ] + }, + "value": { + "type": "object", + "description": "MX record - mail exchange", + "required": [ + "priority", + "target" + ], + "properties": { + "priority": { + "type": "integer", + "format": "int32", + "minimum": 0 + }, + "target": { + "type": "string" + } + } + } + } + }, + { + "type": "object", + "description": "NS record - nameserver", + "required": [ + "value", + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "NS" + ] + }, + "value": { + "type": "object", + "description": "NS record - nameserver", + "required": [ + "nameserver" + ], + "properties": { + "nameserver": { + "type": "string" + } + } + } + } + }, + { + "type": "object", + "description": "SRV record - service", + "required": [ + "value", + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "SRV" + ] + }, + "value": { + "type": "object", + "description": "SRV record - service", + "required": [ + "priority", + "weight", + "port", + "target" + ], + "properties": { + "port": { + "type": "integer", + "format": "int32", + "minimum": 0 + }, + "priority": { + "type": "integer", + "format": "int32", + "minimum": 0 + }, + "target": { + "type": "string" + }, + "weight": { + "type": "integer", + "format": "int32", + "minimum": 0 + } + } + } + } + }, + { + "type": "object", + "description": "CAA record - certification authority authorization", + "required": [ + "value", + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "CAA" + ] + }, + "value": { + "type": "object", + "description": "CAA record - certification authority authorization", + "required": [ + "flags", + "tag", + "value" + ], + "properties": { + "flags": { + "type": "integer", + "format": "int32", + "minimum": 0 + }, + "tag": { + "type": "string" + }, + "value": { + "type": "string" + } + } + } + } + }, + { + "type": "object", + "description": "PTR record - pointer", + "required": [ + "value", + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "PTR" + ] + }, + "value": { + "type": "object", + "description": "PTR record - pointer", + "required": [ + "target" + ], + "properties": { + "target": { + "type": "string" + } + } + } + } + } + ], + "description": "DNS record content - varies by record type" + }, + "DnsRecordResponse": { + "type": "object", + "required": [ + "record_type", + "name", + "value", + "status" + ], + "properties": { + "name": { + "type": "string", + "description": "DNS record name (host)", + "example": "temps._domainkey.example.com" + }, + "priority": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Priority (for MX records)", + "example": "10", + "minimum": 0 + }, + "record_type": { + "type": "string", + "description": "Record type: TXT, CNAME, MX", + "example": "TXT" + }, + "status": { + "$ref": "#/components/schemas/DnsRecordStatusResponse", + "description": "Verification status: unknown, verified, pending, failed" + }, + "value": { + "type": "string", + "description": "DNS record value", + "example": "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3..." + } + } + }, + "DnsRecordSetupResult": { + "type": "object", + "description": "Result of a single DNS record creation", + "required": [ + "record_type", + "name", + "success", + "automatic", + "message" + ], + "properties": { + "automatic": { + "type": "boolean", + "description": "Whether the operation was automatic or manual" + }, + "message": { + "type": "string", + "description": "Human-readable message" + }, + "name": { + "type": "string", + "description": "Record name" + }, + "record_type": { + "type": "string", + "description": "Record type (TXT, CNAME, MX)" + }, + "success": { + "type": "boolean", + "description": "Whether the record was created successfully" + } + } + }, + "DnsRecordStatusResponse": { + "type": "string", + "description": "DNS record verification status", + "enum": [ + "unknown", + "verified", + "pending", + "failed" + ] + }, + "DnsZone": { + "type": "object", + "description": "A DNS zone (domain managed by the provider)", + "required": [ + "id", + "name", + "status", + "nameservers" + ], + "properties": { + "id": { + "type": "string", + "description": "Provider-specific zone ID", + "example": "zone123" + }, + "metadata": { + "type": "object", + "description": "Provider-specific metadata", + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + } + }, + "name": { + "type": "string", + "description": "Zone name (domain)", + "example": "example.com" + }, + "nameservers": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Nameservers for this zone" + }, + "status": { + "type": "string", + "description": "Zone status", + "example": "active" + } + } + }, + "DockerComposePresetConfig": { + "type": "object", + "description": "Configuration for Docker Compose deployments.", + "properties": { + "composeOverride": { + "type": [ + "string", + "null" + ], + "description": "User-provided docker-compose.override.yml content." + }, + "composePath": { + "type": [ + "string", + "null" + ], + "description": "Path to the Compose file relative to the project directory." + }, + "publicPorts": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ComposePublicPort" + }, + "description": "Compose service ports that should be publicly routed." + } + } + }, + "DockerRegistrySettings": { + "type": "object", + "properties": { + "ca_certificate": { + "type": [ + "string", + "null" + ], + "default": null + }, + "enabled": { + "type": "boolean", + "default": false + }, + "password": { + "type": [ + "string", + "null" + ], + "default": null + }, + "registry_url": { + "type": [ + "string", + "null" + ], + "default": null + }, + "tls_verify": { + "type": "boolean", + "default": true + }, + "username": { + "type": [ + "string", + "null" + ], + "default": null + } + } + }, + "DockerRegistrySettingsMasked": { + "type": "object", + "description": "Docker registry settings with masked sensitive fields", + "required": [ + "enabled", + "tls_verify" + ], + "properties": { + "ca_certificate": { + "type": [ + "string", + "null" + ] + }, + "enabled": { + "type": "boolean" + }, + "password": { + "type": [ + "string", + "null" + ] + }, + "registry_url": { + "type": [ + "string", + "null" + ] + }, + "tls_verify": { + "type": "boolean" + }, + "username": { + "type": [ + "string", + "null" + ] + } + } + }, + "DockerfilePresetConfig": { + "type": "object", + "description": "Configuration for Dockerfile preset\nAllows customizing the Dockerfile path and build context for Docker-based deployments", + "properties": { + "buildContext": { + "type": [ + "string", + "null" + ], + "description": "Custom build context path (relative to repository root)\nIf not specified, uses the project's directory setting", + "example": "./api" + }, + "dockerfilePath": { + "type": [ + "string", + "null" + ], + "description": "Custom Dockerfile path (relative to build context)\nIf not specified, defaults to \"Dockerfile\" in the build context", + "example": "docker/Dockerfile" + }, + "variant": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/DockerfileVariant", + "description": "Catalog variant. Normally omitted; `custom` selects the generated\nDockerfile compatibility preset." + } + ] + } + } + }, + "DockerfileVariant": { + "type": "string", + "description": "Catalog variant persisted under the canonical Dockerfile preset.\n\nExisting rows predate this discriminator and therefore deserialize as\n[`DockerfileVariant::File`].", + "enum": [ + "file", + "custom" + ] + }, + "DomainAction": { + "type": "string", + "description": "What to do with a domain during migration", + "enum": [ + "import", + "skip" + ] + }, + "DomainChallengeResponse": { + "type": "object", + "required": [ + "domain", + "txt_records", + "status" + ], + "properties": { + "domain": { + "type": "string" + }, + "status": { + "type": "string" + }, + "txt_records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TxtRecord" + }, + "description": "Array of TXT records to add to DNS. For wildcards, multiple records are required." + } + } + }, + "DomainEnvironmentResponse": { + "type": "object", + "required": [ + "id", + "name", + "slug" + ], + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "slug": { + "type": "string" + } + } + }, + "DomainError": { + "type": "object", + "required": [ + "message", + "code" + ], + "properties": { + "code": { + "type": "string" + }, + "details": { + "type": [ + "string", + "null" + ] + }, + "message": { + "type": "string" + } + } + }, + "DomainPlan": { + "type": "object", + "description": "Plan for migrating a single custom domain", + "required": [ + "domain", + "environment", + "action", + "action_description" + ], + "properties": { + "action": { + "$ref": "#/components/schemas/DomainAction", + "description": "What to do with this domain" + }, + "action_description": { + "type": "string", + "description": "Human-readable explanation" + }, + "domain": { + "type": "string", + "description": "Full domain name" + }, + "environment": { + "type": "string", + "description": "Which environment to associate with (\"production\")" + }, + "redirect_to": { + "type": [ + "string", + "null" + ], + "description": "Redirect target (if this is a redirect domain)" + }, + "replacement": { + "type": [ + "string", + "null" + ], + "description": "The temps-side address that replaces this domain when it is skipped.\n\nSource-generated domains (sslip.io / traefik.me / platform subdomains)\nembed the source server's IP and would keep pointing at the old\nmachine \u2014 this tells the user where the app will be reachable on\ntemps instead." + }, + "status_code": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Redirect status code" + } + } + }, + "DomainResponse": { + "type": "object", + "required": [ + "id", + "domain", + "status", + "is_wildcard", + "verification_method", + "created_at", + "updated_at" + ], + "properties": { + "certificate": { + "type": [ + "string", + "null" + ], + "description": "The PEM-encoded certificate chain (can be displayed in browser or downloaded)" + }, + "created_at": { + "type": "integer", + "format": "int64" + }, + "dns_challenge_token": { + "type": [ + "string", + "null" + ] + }, + "dns_challenge_value": { + "type": [ + "string", + "null" + ] + }, + "domain": { + "type": "string" + }, + "expiration_time": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "is_wildcard": { + "type": "boolean" + }, + "last_error": { + "type": [ + "string", + "null" + ] + }, + "last_error_type": { + "type": [ + "string", + "null" + ] + }, + "last_renewed": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "on_demand_backoff_until": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "On-demand TLS negative-cache deadline (epoch millis), when this hostname's\non-demand HTTP-01 issuance is in backoff after a failure (ADR-018 \u00a74).\n`None` means no active backoff." + }, + "status": { + "type": "string" + }, + "updated_at": { + "type": "integer", + "format": "int64" + }, + "verification_method": { + "type": "string" + } + } + }, + "DrainNodeResponse": { + "type": "object", + "required": [ + "id", + "name", + "status", + "affected_environments", + "message" + ], + "properties": { + "affected_environments": { + "type": "integer", + "minimum": 0 + }, + "id": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "name": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "DrainStatusResponse": { + "type": "object", + "description": "Progress of a node drain operation.", + "required": [ + "node_id", + "node_name", + "status", + "remaining_containers", + "drain_complete", + "can_remove", + "message" + ], + "properties": { + "can_remove": { + "type": "boolean", + "description": "Can the node be safely removed?" + }, + "drain_complete": { + "type": "boolean", + "description": "Whether the drain is complete (all containers migrated)" + }, + "message": { + "type": "string" + }, + "node_id": { + "type": "integer", + "format": "int32" + }, + "node_name": { + "type": "string" + }, + "remaining_containers": { + "type": "integer", + "description": "Number of containers still on this node", + "minimum": 0 + }, + "status": { + "type": "string" + } + } + }, + "DropArchiveUpload": { + "type": "object", + "required": [ + "file" + ], + "properties": { + "file": { + "type": "string", + "format": "binary" + } + } + }, + "DropInspectionResponse": { + "type": "object", + "required": [ + "suggestedName", + "candidates" + ], + "properties": { + "candidates": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DropPresetCandidate" + } + }, + "suggestedName": { + "type": "string" + } + } + }, + "DropOffPoint": { + "type": "object", + "description": "Drop-off point: pages where visitors leave the site", + "required": [ + "page_path", + "exit_count", + "total_views", + "exit_rate" + ], + "properties": { + "exit_count": { + "type": "integer", + "format": "int64", + "description": "Number of exits from this page" + }, + "exit_rate": { + "type": "number", + "format": "double", + "description": "Exit rate for this page (exit_count / total_views)" + }, + "page_path": { + "type": "string", + "description": "The page path where visitors drop off" + }, + "total_views": { + "type": "integer", + "format": "int64", + "description": "Total views of this page" + } + } + }, + "DropPresetCandidate": { + "type": "object", + "required": [ + "directory", + "preset", + "label", + "confidence", + "reason", + "isStatic" + ], + "properties": { + "confidence": { + "type": "string" + }, + "directory": { + "type": "string" + }, + "isStatic": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "preset": { + "type": "string" + }, + "reason": { + "type": "string" + } + } + }, + "EmailConfig": { + "type": "object", + "required": [ + "smtp_host", + "smtp_port", + "username", + "password", + "from_address", + "to_addresses" + ], + "properties": { + "accept_invalid_certs": { + "type": "boolean" + }, + "from_address": { + "type": "string" + }, + "from_name": { + "type": [ + "string", + "null" + ] + }, + "password": { + "type": "string" + }, + "smtp_host": { + "type": "string" + }, + "smtp_port": { + "type": "integer", + "format": "int32", + "minimum": 0 + }, + "starttls_required": { + "type": "boolean" + }, + "tls_mode": { + "$ref": "#/components/schemas/TlsMode" + }, + "to_addresses": { + "type": "array", + "items": { + "type": "string" + } + }, + "username": { + "type": "string" + } + } + }, + "EmailDomainResponse": { + "type": "object", + "required": [ + "id", + "provider_id", + "domain", + "status", + "created_at", + "updated_at" + ], + "properties": { + "created_at": { + "type": "string", + "example": "2025-12-03T10:30:00Z" + }, + "domain": { + "type": "string", + "example": "updates.example.com" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "last_verified_at": { + "type": [ + "string", + "null" + ] + }, + "provider_id": { + "type": "integer", + "format": "int32" + }, + "status": { + "type": "string", + "example": "verified" + }, + "updated_at": { + "type": "string", + "example": "2025-12-03T10:30:00Z" + }, + "verification_error": { + "type": [ + "string", + "null" + ] + } + } + }, + "EmailDomainWithDnsResponse": { + "type": "object", + "required": [ + "domain", + "dns_records" + ], + "properties": { + "dns_records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DnsRecordResponse" + } + }, + "domain": { + "$ref": "#/components/schemas/EmailDomainResponse" + } + } + }, + "EmailProviderResponse": { + "type": "object", + "required": [ + "id", + "name", + "provider_type", + "region", + "is_active", + "credentials", + "created_at", + "updated_at" + ], + "properties": { + "created_at": { + "type": "string", + "example": "2025-12-03T10:30:00Z" + }, + "credentials": { + "description": "Masked credentials for display" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "is_active": { + "type": "boolean" + }, + "name": { + "type": "string", + "example": "My AWS SES" + }, + "provider_type": { + "$ref": "#/components/schemas/EmailProviderTypeRoute" + }, + "region": { + "type": "string", + "example": "us-east-1" + }, + "sns_topic_arn": { + "type": [ + "string", + "null" + ] + }, + "updated_at": { + "type": "string", + "example": "2025-12-03T10:30:00Z" + } + } + }, + "EmailProviderTypeRoute": { + "type": "string", + "enum": [ + "ses", + "scaleway", + "smtp" + ] + }, + "EmailRequest": { + "type": "object", + "description": "Request body carrying just an email address (password-reset request).", + "required": [ + "email" + ], + "properties": { + "email": { + "type": "string" + } + } + }, + "EmailResponse": { + "type": "object", + "required": [ + "id", + "from_address", + "to_addresses", + "subject", + "status", + "created_at", + "track_opens", + "track_clicks", + "open_count", + "click_count" + ], + "properties": { + "bcc_addresses": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "cc_addresses": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "click_count": { + "type": "integer", + "format": "int32", + "description": "Number of times links in the email were clicked" + }, + "created_at": { + "type": "string", + "example": "2025-12-03T10:30:00Z" + }, + "domain_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "error_message": { + "type": [ + "string", + "null" + ] + }, + "first_clicked_at": { + "type": [ + "string", + "null" + ], + "description": "When a link was first clicked" + }, + "first_opened_at": { + "type": [ + "string", + "null" + ], + "description": "When the email was first opened" + }, + "from_address": { + "type": "string", + "example": "hello@updates.example.com" + }, + "from_name": { + "type": [ + "string", + "null" + ] + }, + "headers": { + "type": [ + "object", + "null" + ], + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + } + }, + "html_body": { + "type": [ + "string", + "null" + ] + }, + "id": { + "type": "string", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "open_count": { + "type": "integer", + "format": "int32", + "description": "Number of times the email was opened" + }, + "project_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "provider_message_id": { + "type": [ + "string", + "null" + ] + }, + "reply_to": { + "type": [ + "string", + "null" + ] + }, + "sent_at": { + "type": [ + "string", + "null" + ] + }, + "status": { + "type": "string", + "example": "sent" + }, + "subject": { + "type": "string" + }, + "tags": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "text_body": { + "type": [ + "string", + "null" + ] + }, + "to_addresses": { + "type": "array", + "items": { + "type": "string" + } + }, + "track_clicks": { + "type": "boolean", + "description": "Whether click tracking is enabled" + }, + "track_opens": { + "type": "boolean", + "description": "Whether open tracking is enabled" + }, + "tracked_html_body": { + "type": [ + "string", + "null" + ], + "description": "The final HTML sent to the provider (with tracking pixel and rewritten links)" + } + } + }, + "EmailStatsResponse": { + "type": "object", + "required": [ + "total", + "sent", + "failed", + "queued", + "captured" + ], + "properties": { + "captured": { + "type": "integer", + "format": "int64", + "description": "Emails captured without sending (Mailhog mode - no provider configured)", + "minimum": 0 + }, + "failed": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "queued": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "sent": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "total": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + }, + "EmailStatusResponse": { + "type": "object", + "required": [ + "email_configured", + "password_reset_available", + "oidc_providers" + ], + "properties": { + "email_configured": { + "type": "boolean" + }, + "oidc_providers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OidcProviderSummary" + } + }, + "password_reset_available": { + "type": "boolean" + } + } + }, + "EmailTrackingResponse": { + "type": "object", + "description": "Email tracking summary", + "required": [ + "email_id", + "track_opens", + "track_clicks", + "open_count", + "click_count", + "unique_opens", + "unique_clicks", + "links" + ], + "properties": { + "click_count": { + "type": "integer", + "format": "int32" + }, + "email_id": { + "type": "string" + }, + "first_clicked_at": { + "type": [ + "string", + "null" + ] + }, + "first_opened_at": { + "type": [ + "string", + "null" + ] + }, + "links": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TrackedLinkResponse" + } + }, + "open_count": { + "type": "integer", + "format": "int32" + }, + "track_clicks": { + "type": "boolean" + }, + "track_opens": { + "type": "boolean" + }, + "unique_clicks": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "unique_opens": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + }, + "EmailTrackingSetupResponse": { + "type": "object", + "description": "Result of the one-click AWS-side event-tracking setup.", + "required": [ + "topic_arn", + "webhook_url", + "subscription_requested", + "event_destination_attached" + ], + "properties": { + "event_destination_attached": { + "type": "boolean", + "description": "The SESv2 event destination (bounce/complaint/delivery) is attached\nto the `temps-tracking` configuration set." + }, + "subscription_requested": { + "type": "boolean", + "description": "The webhook subscription was requested; SNS confirms it\nasynchronously through the webhook itself." + }, + "topic_arn": { + "type": "string", + "example": "arn:aws:sns:us-east-1:123456789012:temps-email-events-1" + }, + "webhook_url": { + "type": "string" + } + } + }, + "EmailTrackingStatusResponse": { + "type": "object", + "description": "Live status of the SES event-tracking pipeline for one provider.", + "required": [ + "webhook_url", + "supports_event_tracking" + ], + "properties": { + "last_event_at": { + "type": [ + "string", + "null" + ], + "description": "Most recent delivered/bounced/complained event recorded for an email\nsent through this provider. `null` means no provider feedback has\narrived yet.", + "example": "2026-07-18T10:31:00Z" + }, + "sns_topic_arn": { + "type": [ + "string", + "null" + ] + }, + "subscription_confirmed_at": { + "type": [ + "string", + "null" + ], + "description": "When the SNS subscription for the current topic was confirmed.\n`null` with a topic set usually means the subscription is still\npending \u2014 most often because the endpoint was subscribed before the\ntopic ARN was saved here.", + "example": "2026-07-18T10:30:00Z" + }, + "supports_event_tracking": { + "type": "boolean", + "description": "Only SES providers support SNS event tracking." + }, + "webhook_url": { + "type": "string", + "description": "Public webhook endpoint SNS must deliver events to.", + "example": "https://temps.example.com/api/t/webhook/ses" + } + } + }, + "EmbeddingData": { + "type": "object", + "required": [ + "object", + "embedding", + "index" + ], + "properties": { + "embedding": { + "type": "array", + "items": { + "type": "number", + "format": "double" + } + }, + "index": { + "type": "integer", + "format": "int32" + }, + "object": { + "type": "string" + } + } + }, + "EmbeddingInput": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "EmbeddingRequest": { + "type": "object", + "required": [ + "model", + "input" + ], + "properties": { + "dimensions": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "encoding_format": { + "type": [ + "string", + "null" + ] + }, + "input": { + "$ref": "#/components/schemas/EmbeddingInput" + }, + "model": { + "type": "string" + } + } + }, + "EmbeddingResponse": { + "type": "object", + "required": [ + "object", + "data", + "model", + "usage" + ], + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EmbeddingData" + } + }, + "model": { + "type": "string" + }, + "object": { + "type": "string" + }, + "usage": { + "$ref": "#/components/schemas/EmbeddingUsage" + } + } + }, + "EmbeddingUsage": { + "type": "object", + "required": [ + "prompt_tokens", + "total_tokens" + ], + "properties": { + "prompt_tokens": { + "type": "integer", + "format": "int64" + }, + "total_tokens": { + "type": "integer", + "format": "int64" + } + } + }, + "EnableBlobRequest": { + "type": "object", + "description": "Request to enable Blob service", + "properties": { + "docker_image": { + "type": [ + "string", + "null" + ], + "description": "Docker image to use (optional, defaults to RustFS)", + "example": "ghcr.io/rustfs/rustfs:0.5.0" + }, + "root_password": { + "type": [ + "string", + "null" + ], + "description": "Root password for S3 access" + }, + "root_user": { + "type": [ + "string", + "null" + ], + "description": "Root user for S3 access" + } + } + }, + "EnableBlobResponse": { + "type": "object", + "description": "Response after enabling Blob service", + "required": [ + "success", + "message", + "status" + ], + "properties": { + "message": { + "type": "string", + "description": "Human-readable message", + "example": "Blob service enabled successfully" + }, + "status": { + "$ref": "#/components/schemas/BlobStatusResponse", + "description": "Current status" + }, + "success": { + "type": "boolean", + "description": "Whether the operation succeeded", + "example": true + } + } + }, + "EnableKvRequest": { + "type": "object", + "description": "Request to enable the KV service", + "properties": { + "docker_image": { + "type": [ + "string", + "null" + ], + "description": "Docker image to use (optional, uses default if not provided)", + "example": "gotempsh/redis-walg:8-bookworm" + }, + "max_memory": { + "type": [ + "string", + "null" + ], + "description": "Maximum memory allocation (e.g., \"256mb\", \"1gb\")", + "example": "256mb" + }, + "persistence": { + "type": "boolean", + "description": "Enable data persistence" + } + } + }, + "EnableKvResponse": { + "type": "object", + "description": "Response after enabling KV service", + "required": [ + "success", + "message", + "status" + ], + "properties": { + "message": { + "type": "string", + "description": "Status message", + "example": "KV service enabled successfully" + }, + "status": { + "$ref": "#/components/schemas/KvStatusResponse", + "description": "Current service status" + }, + "success": { + "type": "boolean", + "description": "Whether the service was successfully enabled" + } + } + }, + "EnablePgStatStatementsResponse": { + "type": "object", + "description": "Response for the enable pg_stat_statements endpoint.", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string", + "description": "Human-readable message confirming the action." + } + } + }, + "EndpointDto": { + "type": "object", + "description": "One DNS record on the wire. Mirrors `service_endpoints::Model` but\nkeeps the API stable across entity evolution. `target_ip` is a string\n(v4 or v6 literal, or CNAME target hostname) parsed by the resolver.", + "required": [ + "id", + "fqdn", + "record_type", + "ttl", + "owner_kind", + "owner_id", + "generation" + ], + "properties": { + "fqdn": { + "type": "string" + }, + "generation": { + "type": "integer", + "format": "int64" + }, + "id": { + "type": "integer", + "format": "int64" + }, + "node_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "owner_id": { + "type": "integer", + "format": "int64" + }, + "owner_kind": { + "type": "string" + }, + "record_type": { + "type": "string" + }, + "target_ip": { + "type": [ + "string", + "null" + ] + }, + "target_port": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "ttl": { + "type": "integer", + "format": "int32" + } + } + }, + "EnqueuedJob": { + "type": "object", + "description": "A single job that was successfully enqueued during a fan-out run.", + "required": [ + "backup_id", + "job_id", + "engine" + ], + "properties": { + "backup_id": { + "type": "integer", + "format": "int32", + "description": "FK to `backups.id` for this job." + }, + "engine": { + "type": "string", + "description": "Engine key (e.g. `\"control_plane\"`, `\"redis\"`, `\"postgres_pgdump\"`)." + }, + "job_id": { + "type": "integer", + "format": "int64", + "description": "FK to `backup_jobs.id` for this job." + }, + "target_service_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "FK to `external_services.id` when this is an external-service job.\n`None` for the control-plane job." + } + } + }, + "EnrichVisitorRequest": { + "type": "object", + "required": [ + "custom_data" + ], + "properties": { + "custom_data": { + "type": "object" + } + } + }, + "EnrichVisitorResponse": { + "type": "object", + "required": [ + "success", + "visitor_id", + "message" + ], + "properties": { + "message": { + "type": "string" + }, + "success": { + "type": "boolean" + }, + "visitor_id": { + "type": "string" + } + } + }, + "EnrollmentTokenInfo": { + "type": "object", + "required": [ + "id", + "expires_at", + "used_count", + "max_uses", + "created_at" + ], + "properties": { + "bound_node_name": { + "type": [ + "string", + "null" + ] + }, + "created_at": { + "type": "string" + }, + "expires_at": { + "type": "string" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "max_uses": { + "type": "integer", + "format": "int32" + }, + "used_count": { + "type": "integer", + "format": "int32" + } + } + }, + "EnrollmentTokenListResponse": { + "type": "object", + "required": [ + "tokens" + ], + "properties": { + "tokens": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EnrollmentTokenInfo" + } + } + } + }, + "EntityInfoResponse": { + "type": "object", + "required": [ + "container_path", + "entity", + "entity_type", + "fields" + ], + "properties": { + "container_path": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Full container path", + "example": [ + "mydb", + "public" + ] + }, + "entity": { + "type": "string", + "description": "Entity name", + "example": "users" + }, + "entity_type": { + "type": "string", + "description": "Entity type", + "example": "table" + }, + "fields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldResponse" + }, + "description": "Field definitions" + }, + "metadata": { + "description": "Additional metadata (content_type, last_modified, etag, etc.)" + }, + "row_count": { + "type": [ + "integer", + "null" + ], + "description": "Approximate row count (for tables/collections)", + "example": 1234, + "minimum": 0 + }, + "size_bytes": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Size in bytes (for objects/files)", + "example": 1048576, + "minimum": 0 + }, + "sort_schema": { + "description": "JSON Schema for sort options (if supported)" + } + } + }, + "EntityResponse": { + "type": "object", + "required": [ + "name", + "entity_type" + ], + "properties": { + "entity_type": { + "type": "string", + "description": "Entity type (table, view, collection, etc.)", + "example": "table" + }, + "name": { + "type": "string", + "description": "Entity name (table/collection)", + "example": "users" + }, + "row_count": { + "type": [ + "integer", + "null" + ], + "description": "Approximate row count", + "example": 1234, + "minimum": 0 + }, + "size_bytes": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Size in bytes (for files/objects)", + "example": 1048576, + "minimum": 0 + } + } + }, + "EnvVarInput": { + "type": "object", + "description": "Input for environment variable", + "required": [ + "name", + "value" + ], + "properties": { + "name": { + "type": "string", + "description": "Variable name" + }, + "value": { + "type": "string", + "description": "Variable value" + } + } + }, + "EnvVarIntegrationInfo": { + "type": "object", + "required": [ + "service_id", + "service_name", + "service_type", + "service_updated_at" + ], + "properties": { + "service_id": { + "type": "integer", + "format": "int32" + }, + "service_name": { + "type": "string" + }, + "service_slug": { + "type": [ + "string", + "null" + ] + }, + "service_type": { + "type": "string" + }, + "service_updated_at": { + "type": "string" + } + } + }, + "EnvVarResponse": { + "type": "object", + "description": "Environment variable with masked sensitive values", + "required": [ + "key", + "value", + "is_masked" + ], + "properties": { + "is_masked": { + "type": "boolean", + "description": "Whether this is a sensitive/masked value" + }, + "key": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, + "EnvVarTemplateResponse": { + "type": "object", + "description": "Environment variable template response", + "required": [ + "name", + "required" + ], + "properties": { + "default": { + "type": [ + "string", + "null" + ], + "description": "Default value if not provided by user" + }, + "default_generator": { + "type": [ + "string", + "null" + ], + "description": "Frontend-side generator hint for the default value\n(e.g. `app_url`, `random_secret`, `random_hex_32`)" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Description of what this variable is used for" + }, + "example": { + "type": [ + "string", + "null" + ], + "description": "Example value for documentation" + }, + "name": { + "type": "string", + "description": "Name of the environment variable" + }, + "required": { + "type": "boolean", + "description": "Whether this variable is required" + } + } + }, + "EnvironmentConfiguration": { + "type": "object", + "description": "Environment-level configuration", + "required": [ + "name", + "subdomain", + "resources" + ], + "properties": { + "name": { + "type": "string", + "description": "Environment name" + }, + "resources": { + "$ref": "#/components/schemas/ResourceLimits", + "description": "Resource limits for environment" + }, + "subdomain": { + "type": "string", + "description": "Proposed subdomain" + } + } + }, + "EnvironmentDomainResponse": { + "type": "object", + "required": [ + "id", + "environment_id", + "domain", + "created_at", + "url" + ], + "properties": { + "created_at": { + "type": "integer", + "format": "int64" + }, + "domain": { + "type": "string" + }, + "environment_id": { + "type": "integer", + "format": "int32" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "url": { + "type": "string", + "description": "Full URL for this domain (e.g., https://buildtolearndev-production.example.com)", + "example": "https://buildtolearndev-production.example.com" + } + } + }, + "EnvironmentInfo": { + "type": "object", + "required": [ + "id", + "name", + "main_url" + ], + "properties": { + "current_deployment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "main_url": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "EnvironmentResponse": { + "type": "object", + "required": [ + "id", + "project_id", + "name", + "slug", + "main_url", + "subdomain", + "created_at", + "updated_at", + "is_preview", + "protected", + "sleeping" + ], + "properties": { + "attack_mode": { + "type": [ + "boolean", + "null" + ], + "description": "Per-environment CAPTCHA attack-mode override.\n`null` means inherit the project-level `attack_mode`; `true`/`false`\nexplicitly enable/disable the challenge for this environment. Always\nserialized (NOT skipped) so the UI can distinguish `null` from `false`." + }, + "branch": { + "type": [ + "string", + "null" + ] + }, + "created_at": { + "type": "integer", + "format": "int64" + }, + "current_deployment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "deployment_config": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/DeploymentConfig", + "description": "Deployment configuration for this environment (overrides project-level config)" + } + ] + }, + "estimated_sleep_at": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Estimated time (epoch millis) when the environment will go to sleep\nbased on last activity + idle timeout. NULL when sleeping or on-demand disabled." + }, + "force_https": { + "type": [ + "boolean", + "null" + ], + "description": "Per-environment HTTP\u2192HTTPS redirect override.\n`null` means inherit the proxy default (redirect only when the host has\nan active TLS certificate); `true` always redirects plain HTTP for this\nenvironment, `false` never does. Always serialized (NOT skipped) so the\nUI can distinguish `null` from `false`." + }, + "id": { + "type": "integer", + "format": "int32" + }, + "is_preview": { + "type": "boolean", + "description": "Indicates if this is a preview environment (auto-created per branch)\nFor preview environments, 'branch' contains the feature branch name" + }, + "last_activity_at": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Last proxied request timestamp (epoch millis) for on-demand environments.\nNULL when on-demand is disabled or no traffic has been received yet." + }, + "main_url": { + "type": "string" + }, + "name": { + "type": "string" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "protected": { + "type": "boolean", + "description": "When true, git pushes do NOT auto-deploy to this environment.\nDeployments must be promoted from another environment." + }, + "sleeping": { + "type": "boolean", + "description": "When true, the environment's containers are currently stopped due to\ninactivity (on-demand mode) and will start on the next request." + }, + "slug": { + "type": "string" + }, + "subdomain": { + "type": "string", + "description": "The host label stored for this environment (e.g.\n`myproject-production`). This is the prefix that is combined with the\nplatform's preview domain at request time to produce `main_url`. Edit\nthis via the rename-subdomain endpoint, not the full URL." + }, + "updated_at": { + "type": "integer", + "format": "int64" + } + } + }, + "EnvironmentVariable": { + "type": "object", + "description": "Environment variable", + "required": [ + "key", + "value", + "is_secret" + ], + "properties": { + "is_secret": { + "type": "boolean", + "description": "Whether this is a secret (should be encrypted)" + }, + "key": { + "type": "string", + "description": "Variable name" + }, + "source_description": { + "type": [ + "string", + "null" + ], + "description": "Where this env var originates from (for traceability)" + }, + "value": { + "type": "string", + "description": "Variable value (may be redacted for secrets)" + } + } + }, + "EnvironmentVariableInfo": { + "type": "object", + "required": [ + "name", + "value", + "sensitive" + ], + "properties": { + "name": { + "type": "string" + }, + "sensitive": { + "type": "boolean", + "description": "Whether this variable contains sensitive data (passwords, keys, tokens)", + "example": false + }, + "value": { + "type": "string" + } + } + }, + "EnvironmentVariableResponse": { + "type": "object", + "required": [ + "id", + "key", + "created_at", + "updated_at", + "environments", + "include_in_preview", + "is_secret" + ], + "properties": { + "created_at": { + "type": "integer", + "format": "int64" + }, + "environments": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EnvironmentInfo" + } + }, + "id": { + "type": "integer", + "format": "int32" + }, + "include_in_preview": { + "type": "boolean", + "description": "Include this environment variable in preview environments" + }, + "is_secret": { + "type": "boolean", + "description": "Whether the variable is a write-only secret. Secrets always have\n`value: None` in responses." + }, + "key": { + "type": "string" + }, + "updated_at": { + "type": "integer", + "format": "int64" + }, + "value": { + "type": [ + "string", + "null" + ], + "description": "Plaintext value for non-secret vars (or `\"***\"` mask for list responses).\n`None` for secret vars \u2014 secrets are write-only." + } + } + }, + "EnvironmentVariableValueResponse": { + "type": "object", + "required": [ + "value" + ], + "properties": { + "value": { + "type": "string" + } + } + }, + "ErrorDashboardStatsQuery": { + "type": "object", + "required": [ + "start_time", + "end_time" + ], + "properties": { + "compare_to_previous": { + "type": [ + "boolean", + "null" + ] + }, + "end_time": { + "type": "string", + "format": "date-time" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "start_time": { + "type": "string", + "format": "date-time" + } + } + }, + "ErrorDashboardStatsResponse": { + "type": "object", + "required": [ + "total_errors", + "total_errors_previous_period", + "total_errors_change_percent", + "error_groups", + "error_groups_previous_period", + "start_time", + "end_time" + ], + "properties": { + "comparison_end_time": { + "type": [ + "string", + "null" + ], + "format": "date-time" + }, + "comparison_start_time": { + "type": [ + "string", + "null" + ], + "format": "date-time" + }, + "end_time": { + "type": "string", + "format": "date-time" + }, + "error_groups": { + "type": "integer", + "format": "int64" + }, + "error_groups_previous_period": { + "type": "integer", + "format": "int64" + }, + "start_time": { + "type": "string", + "format": "date-time" + }, + "total_errors": { + "type": "integer", + "format": "int64" + }, + "total_errors_change_percent": { + "type": "number", + "format": "double" + }, + "total_errors_previous_period": { + "type": "integer", + "format": "int64" + } + } + }, + "ErrorEventResponse": { + "type": "object", + "required": [ + "id", + "error_group_id", + "timestamp", + "created_at" + ], + "properties": { + "created_at": { + "type": "string" + }, + "data": { + "description": "Full error event data (contains raw Sentry event or custom error data)" + }, + "error_group_id": { + "type": "integer", + "format": "int32" + }, + "id": { + "type": "integer", + "format": "int64" + }, + "source": { + "type": [ + "string", + "null" + ], + "description": "Source of the error event (e.g., \"sentry\", \"custom\", \"bugsnag\")" + }, + "timestamp": { + "type": "string" + } + } + }, + "ErrorGroupResponse": { + "type": "object", + "required": [ + "id", + "title", + "error_type", + "first_seen", + "last_seen", + "total_count", + "status", + "project_id", + "created_at", + "updated_at" + ], + "properties": { + "assigned_to": { + "type": [ + "string", + "null" + ] + }, + "created_at": { + "type": "string" + }, + "deployment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "error_type": { + "type": "string" + }, + "first_seen": { + "type": "string" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "last_seen": { + "type": "string" + }, + "message_template": { + "type": [ + "string", + "null" + ] + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "status": { + "type": "string" + }, + "title": { + "type": "string" + }, + "total_count": { + "type": "integer", + "format": "int32" + }, + "updated_at": { + "type": "string" + }, + "visitor_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + } + }, + "ErrorGroupStatsResponse": { + "type": "object", + "required": [ + "total_groups", + "unresolved_groups", + "resolved_groups", + "ignored_groups" + ], + "properties": { + "ignored_groups": { + "type": "integer", + "format": "int64" + }, + "resolved_groups": { + "type": "integer", + "format": "int64" + }, + "total_groups": { + "type": "integer", + "format": "int64" + }, + "unresolved_groups": { + "type": "integer", + "format": "int64" + } + } + }, + "ErrorResponse": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "details": { + "type": [ + "string", + "null" + ] + }, + "error": { + "type": "string" + } + } + }, + "ErrorRow": { + "type": "object", + "required": [ + "id", + "ts", + "error_group_id", + "fingerprint", + "error_class", + "stacktrace_preview", + "stacktrace_truncated" + ], + "properties": { + "deployment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "error_class": { + "type": "string" + }, + "error_group_id": { + "type": "integer", + "format": "int32" + }, + "fingerprint": { + "type": "string" + }, + "id": { + "type": "integer", + "format": "int64" + }, + "message": { + "type": [ + "string", + "null" + ] + }, + "stacktrace_preview": {}, + "stacktrace_truncated": { + "type": "boolean" + }, + "trace_id": { + "type": [ + "string", + "null" + ] + }, + "ts": { + "type": "string", + "format": "date-time" + } + } + }, + "ErrorTimeSeriesDataResponse": { + "type": "object", + "required": [ + "timestamp", + "count" + ], + "properties": { + "count": { + "type": "integer", + "format": "int64" + }, + "timestamp": { + "type": "string" + } + } + }, + "ErrorTimeSeriesQuery": { + "type": "object", + "required": [ + "start_time", + "end_time" + ], + "properties": { + "bucket": { + "type": "string", + "description": "Time bucket size (e.g., \"1h\", \"15m\", \"1d\", \"1 hour\", \"30 minutes\")", + "example": "1h" + }, + "end_time": { + "type": "string", + "format": "date-time" + }, + "start_time": { + "type": "string", + "format": "date-time" + } + } + }, + "EventActivityBucket": { + "type": "object", + "description": "Time bucket data point for event activity graph", + "required": [ + "timestamp", + "count", + "unique_visitors" + ], + "properties": { + "count": { + "type": "integer", + "format": "int64", + "description": "Number of event occurrences in this bucket" + }, + "timestamp": { + "type": "string", + "description": "Timestamp for this bucket (ISO 8601)" + }, + "unique_visitors": { + "type": "integer", + "format": "int64", + "description": "Number of unique visitors in this bucket" + } + } + }, + "EventBreakdown": { + "type": "string", + "enum": [ + "country", + "region", + "city" + ] + }, + "EventBrowserStats": { + "type": "object", + "description": "Browser stats for an event", + "required": [ + "browser", + "count", + "percentage" + ], + "properties": { + "browser": { + "type": "string", + "description": "Browser name" + }, + "count": { + "type": "integer", + "format": "int64", + "description": "Number of event occurrences from this browser" + }, + "percentage": { + "type": "number", + "format": "double", + "description": "Percentage of total events" + } + } + }, + "EventCount": { + "type": "object", + "required": [ + "event_name", + "count", + "percentage" + ], + "properties": { + "count": { + "type": "integer", + "format": "int64" + }, + "event_name": { + "type": "string" + }, + "percentage": { + "type": "number", + "format": "double" + } + } + }, + "EventCountryStats": { + "type": "object", + "description": "Country stats for an event", + "required": [ + "country", + "count", + "percentage" + ], + "properties": { + "count": { + "type": "integer", + "format": "int64", + "description": "Number of event occurrences from this country" + }, + "country": { + "type": "string", + "description": "Country name" + }, + "country_code": { + "type": [ + "string", + "null" + ], + "description": "ISO country code (2-letter)" + }, + "percentage": { + "type": "number", + "format": "double", + "description": "Percentage of total events" + } + } + }, + "EventDetailQuery": { + "type": "object", + "description": "Query parameters for event detail analytics", + "required": [ + "event_name", + "project_id", + "start_date", + "end_date" + ], + "properties": { + "bucket_interval": { + "type": [ + "string", + "null" + ], + "description": "Bucket interval for time series: 'hour', 'day', 'week', 'month' (default: auto)" + }, + "end_date": { + "type": "string", + "format": "date-time" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "event_name": { + "type": "string", + "description": "The specific event name to get details for" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "start_date": { + "type": "string", + "format": "date-time" + } + } + }, + "EventDetailResponse": { + "type": "object", + "description": "Summary response for a specific event's analytics", + "required": [ + "event_name", + "total_count", + "unique_visitors", + "unique_sessions", + "activity_over_time", + "referrers", + "countries", + "browsers", + "bucket_interval" + ], + "properties": { + "activity_over_time": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EventActivityBucket" + }, + "description": "Time series data for event activity graph" + }, + "browsers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EventBrowserStats" + }, + "description": "Browser distribution of visitors who triggered this event" + }, + "bucket_interval": { + "type": "string", + "description": "Bucket interval used for time series ('hour', 'day', etc.)" + }, + "countries": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EventCountryStats" + }, + "description": "Geographic distribution of visitors who triggered this event" + }, + "event_name": { + "type": "string", + "description": "The event name being analyzed" + }, + "referrers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EventReferrerStats" + }, + "description": "Top referrer hostnames for visitors who triggered this event" + }, + "total_count": { + "type": "integer", + "format": "int64", + "description": "Total number of times this event was triggered in the date range" + }, + "unique_sessions": { + "type": "integer", + "format": "int64", + "description": "Number of unique sessions where this event occurred" + }, + "unique_visitors": { + "type": "integer", + "format": "int64", + "description": "Number of unique visitors who triggered this event" + } + } + }, + "EventEntriesQuery": { + "type": "object", + "description": "Query parameters for the raw event entries list", + "required": [ + "event_name", + "project_id", + "start_date", + "end_date" + ], + "properties": { + "end_date": { + "type": "string", + "format": "date-time" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "event_name": { + "type": "string", + "description": "The specific event name to list occurrences for" + }, + "page": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Page number (1-based, default: 1)", + "minimum": 0 + }, + "per_page": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Items per page (default: 20, max: 100)", + "minimum": 0 + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "start_date": { + "type": "string", + "format": "date-time" + } + } + }, + "EventEntriesResponse": { + "type": "object", + "description": "Paginated response for raw event entries", + "required": [ + "event_name", + "total_count", + "page", + "per_page", + "entries" + ], + "properties": { + "entries": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EventEntryInfo" + }, + "description": "Individual event occurrences, most recent first" + }, + "event_name": { + "type": "string", + "description": "The event name" + }, + "page": { + "type": "integer", + "format": "int64", + "description": "Current page number", + "minimum": 0 + }, + "per_page": { + "type": "integer", + "format": "int64", + "description": "Items per page", + "minimum": 0 + }, + "total_count": { + "type": "integer", + "format": "int64", + "description": "Total number of occurrences of this event in the date range" + } + } + }, + "EventEntryInfo": { + "type": "object", + "description": "A single raw occurrence of an event, including its custom JSON properties", + "required": [ + "id", + "timestamp", + "page_path", + "href" + ], + "properties": { + "browser": { + "type": [ + "string", + "null" + ], + "description": "Browser name" + }, + "city": { + "type": [ + "string", + "null" + ], + "description": "City of the visitor at the time of the event" + }, + "country": { + "type": [ + "string", + "null" + ], + "description": "Country of the visitor at the time of the event" + }, + "country_code": { + "type": [ + "string", + "null" + ], + "description": "ISO country code (2-letter)" + }, + "device_type": { + "type": [ + "string", + "null" + ], + "description": "Device type (Desktop, Mobile, Tablet)" + }, + "href": { + "type": "string", + "description": "Full URL where the event was triggered" + }, + "id": { + "type": "integer", + "format": "int64", + "description": "Event row ID" + }, + "page_path": { + "type": "string", + "description": "Page path where the event was triggered" + }, + "props": { + "type": [ + "object", + "null" + ], + "description": "Custom event properties as JSON (null when the event carried no data)" + }, + "session_id": { + "type": [ + "string", + "null" + ], + "description": "Session ID the event belongs to (if any)" + }, + "timestamp": { + "type": "string", + "format": "date-time", + "description": "When the event occurred" + }, + "visitor_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Visitor numeric ID (if known)" + }, + "visitor_uuid": { + "type": [ + "string", + "null" + ], + "description": "Visitor UUID (if known)" + } + } + }, + "EventKind": { + "type": "string", + "description": "Tag enum for filter parameters and routing. Matches the variant\ndiscriminator used by `ObservabilityEvent`.", + "enum": [ + "request", + "span", + "error", + "revenue" + ] + }, + "EventMetricsPayload": { + "type": "object", + "required": [ + "event_name", + "event_data", + "request_path", + "request_query" + ], + "properties": { + "cls": { + "type": [ + "number", + "null" + ], + "format": "float", + "description": "Cumulative Layout Shift (score)" + }, + "event_data": {}, + "event_name": { + "type": "string" + }, + "fcp": { + "type": [ + "number", + "null" + ], + "format": "float", + "description": "First Contentful Paint (milliseconds)" + }, + "fid": { + "type": [ + "number", + "null" + ], + "format": "float", + "description": "First Input Delay (milliseconds)" + }, + "inp": { + "type": [ + "number", + "null" + ], + "format": "float", + "description": "Interaction to Next Paint (milliseconds)" + }, + "language": { + "type": [ + "string", + "null" + ] + }, + "lcp": { + "type": [ + "number", + "null" + ], + "format": "float", + "description": "Largest Contentful Paint (milliseconds)" + }, + "page_title": { + "type": [ + "string", + "null" + ] + }, + "referrer": { + "type": [ + "string", + "null" + ], + "description": "Referrer URL (falls back to Referer header if not provided)" + }, + "request_path": { + "type": "string" + }, + "request_query": { + "type": "string" + }, + "screen_height": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "minimum": 0 + }, + "screen_width": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "minimum": 0 + }, + "ttfb": { + "type": [ + "number", + "null" + ], + "format": "float", + "description": "Time to First Byte (milliseconds)" + }, + "viewport_height": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "minimum": 0 + }, + "viewport_width": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "minimum": 0 + } + } + }, + "EventReferrerStats": { + "type": "object", + "description": "Referrer stats for an event", + "required": [ + "referrer", + "count", + "percentage" + ], + "properties": { + "count": { + "type": "integer", + "format": "int64", + "description": "Number of event occurrences from this referrer" + }, + "percentage": { + "type": "number", + "format": "double", + "description": "Percentage of total events" + }, + "referrer": { + "type": "string", + "description": "Referrer hostname or \"Direct\"" + } + } + }, + "EventTimeline": { + "type": "object", + "required": [ + "date", + "count" + ], + "properties": { + "count": { + "type": "integer", + "format": "int64" + }, + "date": { + "type": "string", + "format": "date-time" + } + } + }, + "EventTimelineQuery": { + "type": "object", + "required": [ + "start_date", + "end_date" + ], + "properties": { + "aggregation_level": { + "$ref": "#/components/schemas/AggregationLevel", + "description": "Aggregation level: events (raw count), sessions (unique sessions), or visitors (unique visitors)" + }, + "bucket_size": { + "type": [ + "string", + "null" + ], + "description": "Bucket size: hour, day, or week (auto-detected if not specified)" + }, + "end_date": { + "type": "string", + "format": "date-time" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "event_name": { + "type": [ + "string", + "null" + ] + }, + "start_date": { + "type": "string", + "format": "date-time" + } + } + }, + "EventType": { + "type": "object", + "required": [ + "name", + "count" + ], + "properties": { + "count": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string" + } + } + }, + "EventTypeBreakdown": { + "type": "object", + "required": [ + "event_type", + "count", + "percentage" + ], + "properties": { + "count": { + "type": "integer", + "format": "int64" + }, + "event_type": { + "type": "string" + }, + "percentage": { + "type": "number", + "format": "double" + } + } + }, + "EventTypeBreakdownQuery": { + "type": "object", + "required": [ + "start_date", + "end_date" + ], + "properties": { + "aggregation_level": { + "$ref": "#/components/schemas/AggregationLevel", + "description": "Aggregation level: events (raw count), sessions (unique sessions), or visitors (unique visitors)" + }, + "end_date": { + "type": "string", + "format": "date-time" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "start_date": { + "type": "string", + "format": "date-time" + } + } + }, + "EventTypeResponse": { + "type": "object", + "required": [ + "event_type", + "description", + "category" + ], + "properties": { + "category": { + "type": "string" + }, + "description": { + "type": "string" + }, + "event_type": { + "type": "string" + } + } + }, + "EventTypesResponse": { + "type": "object", + "required": [ + "events", + "total", + "page", + "page_size" + ], + "properties": { + "events": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EventType" + } + }, + "page": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "page_size": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "total": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + }, + "EventVisitorInfo": { + "type": "object", + "description": "A visitor who triggered a specific event", + "required": [ + "visitor_id", + "visitor_uuid", + "event_count", + "first_triggered", + "last_triggered" + ], + "properties": { + "browser": { + "type": [ + "string", + "null" + ], + "description": "Browser name" + }, + "city": { + "type": [ + "string", + "null" + ], + "description": "Visitor's city" + }, + "country": { + "type": [ + "string", + "null" + ], + "description": "Visitor's country" + }, + "country_code": { + "type": [ + "string", + "null" + ], + "description": "Visitor's country code" + }, + "device_type": { + "type": [ + "string", + "null" + ], + "description": "Device type (Desktop, Mobile, Tablet)" + }, + "event_count": { + "type": "integer", + "format": "int64", + "description": "Number of times this visitor triggered the event" + }, + "first_triggered": { + "type": "string", + "format": "date-time", + "description": "When the visitor first triggered the event in the date range" + }, + "last_triggered": { + "type": "string", + "format": "date-time", + "description": "When the visitor last triggered the event in the date range" + }, + "referrer_hostname": { + "type": [ + "string", + "null" + ], + "description": "Referrer hostname for the event" + }, + "visitor_id": { + "type": "integer", + "format": "int32", + "description": "Visitor numeric ID" + }, + "visitor_uuid": { + "type": "string", + "description": "Visitor UUID" + } + } + }, + "EventVisitorsQuery": { + "type": "object", + "description": "Query parameters for event visitors list", + "required": [ + "event_name", + "project_id", + "start_date", + "end_date" + ], + "properties": { + "end_date": { + "type": "string", + "format": "date-time" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "event_name": { + "type": "string", + "description": "The specific event name to list visitors for" + }, + "page": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Page number (1-based, default: 1)", + "minimum": 0 + }, + "per_page": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Items per page (default: 20, max: 100)", + "minimum": 0 + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "start_date": { + "type": "string", + "format": "date-time" + } + } + }, + "EventVisitorsResponse": { + "type": "object", + "description": "Paginated response for event visitors", + "required": [ + "event_name", + "total_count", + "page", + "per_page", + "visitors" + ], + "properties": { + "event_name": { + "type": "string", + "description": "The event name" + }, + "page": { + "type": "integer", + "format": "int64", + "description": "Current page number", + "minimum": 0 + }, + "per_page": { + "type": "integer", + "format": "int64", + "description": "Items per page", + "minimum": 0 + }, + "total_count": { + "type": "integer", + "format": "int64", + "description": "Total number of unique visitors who triggered this event" + }, + "visitors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EventVisitorInfo" + }, + "description": "Individual visitors who triggered this event" + } + } + }, + "EventsCountQuery": { + "type": "object", + "required": [ + "start_date", + "end_date" + ], + "properties": { + "aggregation_level": { + "$ref": "#/components/schemas/AggregationLevel", + "description": "Aggregation level: events (raw count), sessions (unique sessions), or visitors (unique visitors)" + }, + "custom_events_only": { + "type": [ + "boolean", + "null" + ], + "description": "Only return custom events, excluding system events like page_view, page_leave, heartbeat (default: true)" + }, + "end_date": { + "type": "string", + "format": "date-time" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "limit": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "start_date": { + "type": "string", + "format": "date-time" + } + } + }, + "EventsResponse": { + "type": "object", + "required": [ + "events", + "applied_kinds" + ], + "properties": { + "applied_kinds": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EventKind" + }, + "description": "Echo of the kinds filter actually applied (server-resolved). Useful\nfor clients that pass `kinds=` empty and want to know what they got." + }, + "events": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ObservabilityEvent" + } + } + } + }, + "ExecBody": { + "type": "object", + "required": [ + "cmd" + ], + "properties": { + "cmd": { + "type": "array", + "items": { + "type": "string" + } + }, + "cwd": { + "type": [ + "string", + "null" + ] + }, + "env": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + } + } + }, + "additionalProperties": false + }, + "ExecDetachedResponse": { + "type": "object", + "required": [ + "job_id" + ], + "properties": { + "job_id": { + "type": "string" + } + } + }, + "ExecResponse": { + "type": "object", + "required": [ + "exit_code", + "stdout", + "stderr" + ], + "properties": { + "exit_code": { + "type": "integer", + "format": "int32" + }, + "stderr": { + "type": "string" + }, + "stdout": { + "type": "string" + } + } + }, + "ExecuteImportRequest": { + "type": "object", + "description": "Request to execute an import", + "required": [ + "session_id", + "project_name", + "preset", + "directory", + "main_branch" + ], + "properties": { + "directory": { + "type": "string", + "description": "Project directory", + "example": "." + }, + "dry_run": { + "type": [ + "boolean", + "null" + ], + "description": "Dry run mode (don't create resources)" + }, + "main_branch": { + "type": "string", + "description": "Main branch name", + "example": "main" + }, + "preset": { + "type": "string", + "description": "Preset to use for the project (e.g., \"nextjs\", \"express\", \"docker\")" + }, + "project_name": { + "type": "string", + "description": "Project name to use (overrides the name from the plan)", + "example": "my-app" + }, + "session_id": { + "type": "string", + "description": "Session ID from plan creation" + } + } + }, + "ExecuteImportResponse": { + "type": "object", + "description": "Response from import execution", + "required": [ + "session_id", + "status", + "step_results" + ], + "properties": { + "deployment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Created deployment ID (if completed)" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Created environment ID (if completed)" + }, + "project_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Created project ID (if completed)" + }, + "session_id": { + "type": "string", + "description": "Session ID" + }, + "status": { + "$ref": "#/components/schemas/ImportExecutionStatus", + "description": "Execution status" + }, + "step_results": { + "type": "array", + "items": { + "$ref": "#/components/schemas/StepResult" + }, + "description": "Per-step results (in execution order)" + } + } + }, + "ExecuteOperationRequest": { + "type": "object", + "required": [ + "operation" + ], + "properties": { + "operation": { + "type": "string" + } + } + }, + "ExpireRequest": { + "type": "object", + "description": "Request to set expiration on a key", + "required": [ + "key", + "seconds" + ], + "properties": { + "key": { + "type": "string", + "description": "The key to set expiration on", + "example": "session:abc" + }, + "project_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Project ID (required for API key/session auth, optional for deployment tokens)", + "example": 1 + }, + "seconds": { + "type": "integer", + "format": "int64", + "description": "Expiration time in seconds", + "example": 3600 + } + } + }, + "ExpireResponse": { + "type": "object", + "description": "Response for expire operation", + "required": [ + "success" + ], + "properties": { + "success": { + "type": "boolean", + "description": "True if expiration was set, false if key doesn't exist" + } + } + }, + "ExplorerSupportResponse": { + "type": "object", + "required": [ + "supported", + "service_type", + "capabilities", + "hierarchy" + ], + "properties": { + "capabilities": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Capabilities supported by this service", + "example": [ + "sql" + ] + }, + "filter_schema": { + "description": "JSON Schema for filter format with embedded UI hints (if supported)" + }, + "hierarchy": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HierarchyLevel" + }, + "description": "Hierarchy levels (describes the navigation structure)" + }, + "reason": { + "type": [ + "string", + "null" + ], + "description": "Reason why explorer is not supported (if applicable)" + }, + "service_type": { + "type": "string", + "description": "Service type", + "example": "postgres" + }, + "supported": { + "type": "boolean", + "description": "Whether the service supports query explorer functionality", + "example": true + } + } + }, + "ExtendTimeoutBody": { + "type": "object", + "properties": { + "duration": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "`@vercel/sandbox`-compatible alternative \u2014 duration in milliseconds.\nUsed when `extra_secs` is absent.", + "minimum": 0 + }, + "extra_secs": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Extra seconds to add to the existing `expires_at` (temps-native).", + "minimum": 0 + } + } + }, + "ExternalImageResponse": { + "type": "object", + "required": [ + "id", + "project_id", + "image_ref", + "pushed_at", + "created_at" + ], + "properties": { + "created_at": { + "type": "string", + "format": "date-time", + "example": "2025-10-12T12:15:47.609192Z" + }, + "digest": { + "type": [ + "string", + "null" + ] + }, + "id": { + "type": "integer", + "format": "int32" + }, + "image_ref": { + "type": "string" + }, + "metadata": {}, + "project_id": { + "type": "integer", + "format": "int32" + }, + "pushed_at": { + "type": "string", + "format": "date-time", + "example": "2025-10-12T12:15:47.609192Z" + }, + "size_bytes": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "tag": { + "type": [ + "string", + "null" + ] + } + } + }, + "ExternalServiceBackupResponse": { + "type": "object", + "description": "Response type for external service backup", + "required": [ + "id", + "service_id", + "backup_id", + "backup_type", + "state", + "started_at", + "s3_location", + "metadata", + "compression_type", + "created_by" + ], + "properties": { + "backup_id": { + "type": "integer", + "format": "int32" + }, + "backup_type": { + "type": "string" + }, + "checksum": { + "type": [ + "string", + "null" + ] + }, + "compression_type": { + "type": "string" + }, + "created_by": { + "type": "integer", + "format": "int32" + }, + "error_message": { + "type": [ + "string", + "null" + ] + }, + "expires_at": { + "type": [ + "string", + "null" + ], + "example": "2025-02-15T14:30:00.123Z" + }, + "finished_at": { + "type": [ + "string", + "null" + ], + "example": "2025-01-15T14:35:00.456Z" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "metadata": {}, + "s3_location": { + "type": "string" + }, + "service_id": { + "type": "integer", + "format": "int32" + }, + "size_bytes": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "started_at": { + "type": "string", + "example": "2025-01-15T14:30:00.123Z" + }, + "state": { + "type": "string" + } + } + }, + "ExternalServiceDetails": { + "type": "object", + "required": [ + "service", + "sensitive_parameters" + ], + "properties": { + "current_parameters": { + "type": [ + "object", + "null" + ], + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + } + }, + "parameter_schema": {}, + "sensitive_parameters": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Parameter names whose values are masked in `current_parameters` and\nmay be fetched only through the audited reveal endpoint." + }, + "service": { + "$ref": "#/components/schemas/ExternalServiceInfo" + } + } + }, + "ExternalServiceInfo": { + "type": "object", + "required": [ + "id", + "name", + "service_type", + "status", + "created_at", + "updated_at", + "topology" + ], + "properties": { + "connection_info": { + "type": [ + "string", + "null" + ] + }, + "created_at": { + "type": "string" + }, + "error_message": { + "type": [ + "string", + "null" + ], + "description": "Error message from failed initialization." + }, + "id": { + "type": "integer", + "format": "int32" + }, + "members": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ServiceMemberInfo" + }, + "description": "Cluster members (empty for standalone services)." + }, + "metrics_enabled": { + "type": "boolean", + "description": "Whether metric collection is enabled for this service. The UI uses this\nto decide whether to poll the monitoring endpoints." + }, + "name": { + "type": "string" + }, + "node_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Node ID where the service runs. Null means control plane (local)." + }, + "service_type": { + "$ref": "#/components/schemas/ServiceTypeRoute" + }, + "status": { + "type": "string" + }, + "topology": { + "type": "string", + "description": "Service topology: \"standalone\" (single container) or \"cluster\" (HA multi-member).", + "example": "standalone" + }, + "updated_at": { + "type": "string" + }, + "version": { + "type": [ + "string", + "null" + ] + } + } + }, + "ExternalServiceSummary": { + "type": "object", + "description": "Summary of the external service that owns a backup. Only populated for\nexternal-service backups (Redis, Postgres, etc.); absent for control-plane\nbackups.", + "required": [ + "id", + "name", + "service_type" + ], + "properties": { + "id": { + "type": "integer", + "format": "int32", + "description": "Database id of the external service." + }, + "name": { + "type": "string", + "description": "Human-readable service name (e.g. \"redis-prod\")." + }, + "service_type": { + "type": "string", + "description": "Service type string (e.g. \"postgres\", \"redis\", \"mongodb\").", + "example": "postgres" + } + } + }, + "FieldResponse": { + "type": "object", + "required": [ + "name", + "field_type", + "nullable" + ], + "properties": { + "field_type": { + "type": "string", + "description": "Field type (Int32, String, Timestamp, etc.)", + "example": "Int64" + }, + "name": { + "type": "string", + "description": "Field name", + "example": "id" + }, + "nullable": { + "type": "boolean", + "description": "Whether the field is nullable", + "example": false + } + } + }, + "FiringSeriesEntry": { + "type": "object", + "description": "A single currently-firing series for a dynamic alert rule, snapshotted from\nthe evaluator's in-memory per-series firing map at read time (ADR-026 Phase 3).", + "required": [ + "series_key", + "series_label" + ], + "properties": { + "alarm_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "The open alarm's id, when one was created (absent if suppressed)." + }, + "series_key": { + "type": "array", + "items": { + "type": "array", + "items": false, + "prefixItems": [ + { + "type": "string" + }, + { + "type": "string" + } + ] + }, + "description": "The series' label pairs, e.g. `[[\"endpoint\",\"/checkout\"],[\"region\",\"eu-west\"]]`." + }, + "series_label": { + "type": "string", + "description": "The human-readable joined label, e.g. `endpoint=/checkout, region=eu-west`." + } + } + }, + "FlagEnvironmentResponse": { + "type": "object", + "required": [ + "environment_id", + "enabled" + ], + "properties": { + "enabled": { + "type": "boolean" + }, + "environment_id": { + "type": "integer", + "format": "int32" + }, + "value": {} + } + }, + "FlagListResponse": { + "type": "object", + "description": "Note the absence of `salt`: it is never exposed. Publishing the bucketing\nsalt would let a client predict, and self-select into, a rollout cohort.", + "required": [ + "flags", + "total", + "page", + "page_size", + "total_pages" + ], + "properties": { + "flags": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FlagResponse" + } + }, + "page": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "page_size": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "total": { + "type": "integer", + "format": "int64", + "description": "Total flags matching the filter, across all pages.", + "minimum": 0 + }, + "total_pages": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + }, + "FlagResponse": { + "type": "object", + "required": [ + "id", + "key", + "value_type", + "default_value", + "client_visible", + "created_at", + "updated_at", + "environments" + ], + "properties": { + "archived_at": { + "type": [ + "string", + "null" + ] + }, + "client_visible": { + "type": "boolean" + }, + "created_at": { + "type": "string" + }, + "default_value": {}, + "description": { + "type": [ + "string", + "null" + ] + }, + "environments": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FlagEnvironmentResponse" + }, + "description": "Per-environment overrides. Empty means the flag inherits its default\neverywhere." + }, + "id": { + "type": "integer", + "format": "int32" + }, + "key": { + "type": "string" + }, + "last_evaluated_at": { + "type": [ + "string", + "null" + ], + "description": "When an app last actually evaluated this flag. `None` means never seen,\nwhich is a real answer rather than missing data." + }, + "updated_at": { + "type": "string" + }, + "value_type": { + "type": "string" + } + } + }, + "FlagSnapshot": { + "type": "object", + "description": "A single flag, already resolved down to one environment. This is what the\nevaluator sees and what the SDK caches in memory.", + "required": [ + "key", + "value_type", + "default_value", + "enabled" + ], + "properties": { + "default_value": { + "description": "Served whenever evaluation cannot do better. Genuinely polymorphic by\ndesign \u2014 the surrounding struct carries the type." + }, + "enabled": { + "type": "boolean", + "description": "False means the kill switch is engaged for this environment." + }, + "environment_value": { + "description": "`None` means \"inherit `default_value`\"." + }, + "key": { + "type": "string" + }, + "value_type": { + "$ref": "#/components/schemas/FlagValueType" + } + } + }, + "FlagSnapshotResponse": { + "type": "object", + "required": [ + "environment_id", + "flags" + ], + "properties": { + "environment_id": { + "type": "integer", + "format": "int32" + }, + "flags": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FlagSnapshot" + }, + "description": "Flags collapsed to what the evaluator needs, sorted by key so the\nserialized form \u2014 and therefore the ETag \u2014 is stable." + } + } + }, + "FlagValueType": { + "type": "string", + "description": "The declared type of a flag's value. Fixed at create time.", + "enum": [ + "bool", + "string", + "number", + "json" + ] + }, + "ForecastAlgorithm": { + "type": "string", + "description": "Forecast model family.", + "enum": [ + "linear", + "seasonal" + ] + }, + "ForecastParams": { + "type": "object", + "description": "Forecast detector parameters (stub \u2014 not yet evaluated).", + "required": [ + "forecast_horizon_secs", + "comparator", + "threshold" + ], + "properties": { + "algorithm": { + "$ref": "#/components/schemas/ForecastAlgorithm" + }, + "comparator": { + "$ref": "#/components/schemas/Comparator", + "description": "Comparator + threshold the *forecast* is checked against." + }, + "deviations": { + "type": "number", + "format": "double" + }, + "forecast_horizon_secs": { + "type": "integer", + "format": "int32", + "description": "How far ahead to project before checking the breach condition." + }, + "threshold": { + "type": "number", + "format": "double" + } + } + }, + "FullError": { + "type": "object", + "required": [ + "id", + "ts", + "error_group_id", + "fingerprint", + "error_class" + ], + "properties": { + "data": { + "description": "Full JSONB blob from `error_events.data` \u2014 stack trace, breadcrumbs,\nrequest context, everything. Schema is documented per source SDK." + }, + "deployment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "error_class": { + "type": "string" + }, + "error_group_id": { + "type": "integer", + "format": "int32" + }, + "fingerprint": { + "type": "string" + }, + "id": { + "type": "integer", + "format": "int64" + }, + "message": { + "type": [ + "string", + "null" + ] + }, + "trace_id": { + "type": [ + "string", + "null" + ] + }, + "ts": { + "type": "string", + "format": "date-time" + } + } + }, + "FullEvent": { + "oneOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/FullRequest" + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "request" + ] + } + } + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/FullError" + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "error" + ] + } + } + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/RevenueRow" + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "revenue" + ] + } + } + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/SpanRow", + "description": "`SpanRow.attributes` is the truncated form; re-fetching returns\nthe same shape so the panel has a stable contract." + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "span" + ] + } + } + } + ], + "description": "`SpanRow.attributes` is the truncated form; re-fetching returns\nthe same shape so the panel has a stable contract." + } + ], + "description": "One un-truncated row, returned by the `/full/{type}/{id}` endpoint when\nthe user clicks \"Show full\". Same shape as the list rows, but with the\nraw heavy fields restored (no truncation flags) so the side panel can\nrender the long form." + }, + "FullRequest": { + "type": "object", + "required": [ + "id", + "ts", + "method", + "host", + "path", + "status" + ], + "properties": { + "client_ip": { + "type": [ + "string", + "null" + ] + }, + "deployment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "error_group_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "host": { + "type": "string" + }, + "id": { + "type": "string", + "description": "The request's unique `request_id` \u2014 same identity the list rows carry\n(backend-agnostic; ClickHouse rows have no serial PK)." + }, + "latency_ms": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "method": { + "type": "string" + }, + "path": { + "type": "string" + }, + "referrer": { + "type": [ + "string", + "null" + ] + }, + "request_headers": {}, + "response_headers": {}, + "status": { + "type": "integer", + "format": "int32" + }, + "trace_id": { + "type": [ + "string", + "null" + ] + }, + "ts": { + "type": "string", + "format": "date-time" + }, + "user_agent": { + "type": [ + "string", + "null" + ] + } + } + }, + "FunnelMetricsResponse": { + "type": "object", + "required": [ + "funnel_id", + "funnel_name", + "total_entries", + "step_conversions", + "overall_conversion_rate", + "average_completion_time_seconds" + ], + "properties": { + "average_completion_time_seconds": { + "type": "number", + "format": "double" + }, + "funnel_id": { + "type": "integer", + "format": "int32" + }, + "funnel_name": { + "type": "string" + }, + "overall_conversion_rate": { + "type": "number", + "format": "double" + }, + "step_conversions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/StepConversionResponse" + } + }, + "total_entries": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + }, + "FunnelResponse": { + "type": "object", + "required": [ + "id", + "name", + "is_active", + "created_at", + "updated_at" + ], + "properties": { + "created_at": { + "type": "string" + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "id": { + "type": "integer", + "format": "int32" + }, + "is_active": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + } + }, + "GatewayStatus": { + "type": "object", + "description": "Detailed gateway container status surfaced to the settings UI.", + "required": [ + "present", + "running", + "health", + "container_name", + "expected_image", + "drift", + "auto_upgrade" + ], + "properties": { + "auto_upgrade": { + "type": "boolean", + "description": "True if `auto_upgrade` is enabled in settings." + }, + "container_name": { + "type": "string", + "description": "Container name." + }, + "drift": { + "type": "boolean", + "description": "True when `image != expected_image` and the container is present." + }, + "expected_image": { + "type": "string", + "description": "The image the supervisor *expects* (from settings/constant). If this\ndiffers from `image`, the UI shows a \"drift\" badge." + }, + "health": { + "type": "string", + "description": "Higher-level health label: \"running\" | \"restarting\" | \"crash_looping\"\n| \"stopped\" | \"missing\". UI should prefer this over `running`." + }, + "host_port": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Host port that the container's :8080 is published on.", + "minimum": 0 + }, + "image": { + "type": [ + "string", + "null" + ], + "description": "Image reference the container was created with (e.g.\n`ghcr.io/gotempsh/temps-preview-gateway:latest`)." + }, + "image_digest": { + "type": [ + "string", + "null" + ], + "description": "Image digest if available (e.g. `sha256:\u2026`)." + }, + "last_error": { + "type": [ + "string", + "null" + ], + "description": "Error string Docker recorded for the container (e.g. startup failure)." + }, + "last_exit_code": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Exit code of the last run, if the container is not currently running." + }, + "network": { + "type": [ + "string", + "null" + ], + "description": "Network the container is attached to (should be `temps-sandbox-net`)." + }, + "present": { + "type": "boolean", + "description": "Whether the container exists at all." + }, + "restart_count": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Number of times Docker has restarted the container." + }, + "running": { + "type": "boolean", + "description": "Whether the container is currently running." + }, + "started_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp the container was started at, if running." + } + } + }, + "GenAiEvent": { + "type": "object", + "description": "A GenAI-related event extracted from span events.\n\nCovers `gen_ai.client.inference.operation.details` and `gen_ai.evaluation.result`\nevents per the OTel GenAI semantic conventions.", + "required": [ + "span_id", + "trace_id", + "event_name", + "timestamp", + "attributes" + ], + "properties": { + "attributes": { + "type": "object", + "description": "All event attributes.", + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + } + }, + "event_name": { + "type": "string" + }, + "span_id": { + "type": "string" + }, + "timestamp": { + "type": "string", + "format": "date-time" + }, + "trace_id": { + "type": "string" + } + } + }, + "GenAiSpanDetail": { + "type": "object", + "description": "A single GenAI span with extracted semantic convention fields.\n\nFields are aligned with the OpenTelemetry GenAI Semantic Conventions spec:\n", + "required": [ + "span_id", + "name", + "kind", + "start_time", + "duration_ms", + "status_code", + "attributes" + ], + "properties": { + "agent_description": { + "type": [ + "string", + "null" + ], + "description": "Agent description from `gen_ai.agent.description`." + }, + "agent_id": { + "type": [ + "string", + "null" + ], + "description": "Agent identifier from `gen_ai.agent.id`." + }, + "agent_name": { + "type": [ + "string", + "null" + ], + "description": "Agent name from `gen_ai.agent.name`." + }, + "agent_version": { + "type": [ + "string", + "null" + ], + "description": "Agent version from `gen_ai.agent.version`." + }, + "attributes": { + "type": "object", + "description": "All span attributes for extensibility.", + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + } + }, + "aws_bedrock_guardrail_id": { + "type": [ + "string", + "null" + ], + "description": "AWS Bedrock guardrail ID from `aws.bedrock.guardrail.id`." + }, + "aws_bedrock_knowledge_base_id": { + "type": [ + "string", + "null" + ], + "description": "AWS Bedrock knowledge base ID from `aws.bedrock.knowledge_base.id`." + }, + "azure_resource_provider_namespace": { + "type": [ + "string", + "null" + ], + "description": "Azure resource provider namespace from `azure.resource_provider.namespace`." + }, + "cache_creation_input_tokens": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Tokens written to provider cache from `gen_ai.usage.cache_creation.input_tokens`." + }, + "cache_read_input_tokens": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Tokens served from provider cache from `gen_ai.usage.cache_read.input_tokens`." + }, + "conversation_id": { + "type": [ + "string", + "null" + ], + "description": "Unique conversation/session/thread ID from `gen_ai.conversation.id`." + }, + "data_source_id": { + "type": [ + "string", + "null" + ], + "description": "Data source identifier from `gen_ai.data_source.id`." + }, + "duration_ms": { + "type": "number", + "format": "double" + }, + "embeddings_dimension_count": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Output embedding dimensions from `gen_ai.embeddings.dimension.count`." + }, + "error_type": { + "type": [ + "string", + "null" + ], + "description": "Error type from `error.type` when the span status is ERROR." + }, + "gen_ai_model": { + "type": [ + "string", + "null" + ], + "description": "The requested model from `gen_ai.request.model`." + }, + "gen_ai_operation": { + "type": [ + "string", + "null" + ], + "description": "The operation type from `gen_ai.operation.name` (e.g. \"chat\", \"embeddings\", \"execute_tool\")." + }, + "gen_ai_response_model": { + "type": [ + "string", + "null" + ], + "description": "The model that actually generated the response from `gen_ai.response.model`." + }, + "gen_ai_system": { + "type": [ + "string", + "null" + ], + "description": "The GenAI provider from `gen_ai.provider.name` (falls back to deprecated `gen_ai.system`)." + }, + "input_messages": { + "type": [ + "string", + "null" + ], + "description": "Chat history input from `gen_ai.input.messages` (opt-in, JSON string)." + }, + "input_tokens": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "kind": { + "$ref": "#/components/schemas/SpanKind" + }, + "name": { + "type": "string" + }, + "openai_api_type": { + "type": [ + "string", + "null" + ], + "description": "OpenAI API type from `openai.api.type` (chat_completions, responses)." + }, + "openai_request_service_tier": { + "type": [ + "string", + "null" + ], + "description": "Requested service tier from `openai.request.service_tier`." + }, + "openai_response_service_tier": { + "type": [ + "string", + "null" + ], + "description": "Actual service tier from `openai.response.service_tier`." + }, + "openai_system_fingerprint": { + "type": [ + "string", + "null" + ], + "description": "System fingerprint from `openai.response.system_fingerprint`." + }, + "output_messages": { + "type": [ + "string", + "null" + ], + "description": "Model output from `gen_ai.output.messages` (opt-in, JSON string)." + }, + "output_tokens": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "output_type": { + "type": [ + "string", + "null" + ], + "description": "Output content type from `gen_ai.output.type` (text, json, image, speech)." + }, + "parent_span_id": { + "type": [ + "string", + "null" + ] + }, + "request_choice_count": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Number of choices requested from `gen_ai.request.choice.count`." + }, + "request_encoding_formats": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + }, + "description": "Requested encoding formats from `gen_ai.request.encoding_formats`." + }, + "request_frequency_penalty": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Frequency penalty from `gen_ai.request.frequency_penalty`." + }, + "request_max_tokens": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Max tokens from `gen_ai.request.max_tokens`." + }, + "request_presence_penalty": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Presence penalty from `gen_ai.request.presence_penalty`." + }, + "request_seed": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Seed for reproducibility from `gen_ai.request.seed`." + }, + "request_stop_sequences": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + }, + "description": "Stop sequences from `gen_ai.request.stop_sequences`." + }, + "request_temperature": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Temperature setting from `gen_ai.request.temperature`." + }, + "request_top_k": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Top-k setting from `gen_ai.request.top_k`." + }, + "request_top_p": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Top-p setting from `gen_ai.request.top_p`." + }, + "response_finish_reasons": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + }, + "description": "Reasons the model stopped from `gen_ai.response.finish_reasons` (e.g. [\"stop\"])." + }, + "response_id": { + "type": [ + "string", + "null" + ], + "description": "Unique completion ID from `gen_ai.response.id` (e.g. \"chatcmpl-123\")." + }, + "retrieval_documents": { + "type": [ + "string", + "null" + ], + "description": "Retrieved documents from `gen_ai.retrieval.documents` (opt-in, JSON string)." + }, + "retrieval_query_text": { + "type": [ + "string", + "null" + ], + "description": "Retrieval query text from `gen_ai.retrieval.query.text` (opt-in)." + }, + "server_address": { + "type": [ + "string", + "null" + ], + "description": "GenAI server address from `server.address`." + }, + "server_port": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "GenAI server port from `server.port`." + }, + "span_id": { + "type": "string" + }, + "start_time": { + "type": "string", + "format": "date-time" + }, + "status_code": { + "$ref": "#/components/schemas/SpanStatusCode" + }, + "system_instructions": { + "type": [ + "string", + "null" + ], + "description": "System instructions from `gen_ai.system_instructions` (opt-in, JSON string)." + }, + "tool_call_arguments": { + "type": [ + "string", + "null" + ], + "description": "Tool call arguments from `gen_ai.tool.call.arguments` (opt-in, JSON string)." + }, + "tool_call_id": { + "type": [ + "string", + "null" + ], + "description": "Tool call ID from `gen_ai.tool.call.id`." + }, + "tool_call_result": { + "type": [ + "string", + "null" + ], + "description": "Tool call result from `gen_ai.tool.call.result` (opt-in, JSON string)." + }, + "tool_definitions": { + "type": [ + "string", + "null" + ], + "description": "Tool definitions from `gen_ai.tool.definitions` (opt-in, JSON string)." + }, + "tool_description": { + "type": [ + "string", + "null" + ], + "description": "Tool description from `gen_ai.tool.description`." + }, + "tool_name": { + "type": [ + "string", + "null" + ], + "description": "Tool name from `gen_ai.tool.name`." + }, + "tool_type": { + "type": [ + "string", + "null" + ], + "description": "Tool type from `gen_ai.tool.type` (function, extension, datastore)." + } + } + }, + "GenAiTraceDetailResponse": { + "type": "object", + "required": [ + "trace_id", + "spans", + "span_count", + "events", + "event_count" + ], + "properties": { + "event_count": { + "type": "integer", + "minimum": 0 + }, + "events": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GenAiEvent" + } + }, + "span_count": { + "type": "integer", + "minimum": 0 + }, + "spans": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GenAiSpanDetail" + } + }, + "trace_id": { + "type": "string" + } + } + }, + "GenAiTraceSummariesResponse": { + "type": "object", + "required": [ + "data", + "total" + ], + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GenAiTraceSummary" + } + }, + "total": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + }, + "GenAiTraceSummary": { + "type": "object", + "description": "Summary of a GenAI conversation \u2014 aggregated from OTel spans with `gen_ai.*` attributes.", + "required": [ + "trace_id", + "root_span_name", + "service_name", + "start_time", + "duration_ms", + "span_count", + "error_count" + ], + "properties": { + "duration_ms": { + "type": "number", + "format": "double" + }, + "error_count": { + "type": "integer", + "format": "int64" + }, + "gen_ai_model": { + "type": [ + "string", + "null" + ], + "description": "The requested model from `gen_ai.request.model`." + }, + "gen_ai_operation": { + "type": [ + "string", + "null" + ], + "description": "The operation type from `gen_ai.operation.name` (e.g. \"chat\", \"embeddings\")." + }, + "gen_ai_system": { + "type": [ + "string", + "null" + ], + "description": "The GenAI provider (e.g. \"openai\", \"anthropic\") from `gen_ai.provider.name`." + }, + "root_span_name": { + "type": "string" + }, + "service_name": { + "type": "string" + }, + "span_count": { + "type": "integer", + "format": "int64" + }, + "start_time": { + "type": "string", + "format": "date-time" + }, + "total_cache_creation_input_tokens": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Total cache-creation input tokens across all spans." + }, + "total_cache_read_input_tokens": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Total cache-read input tokens across all spans." + }, + "total_input_tokens": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Total input tokens across all spans in this trace." + }, + "total_output_tokens": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Total output tokens across all spans in this trace." + }, + "trace_id": { + "type": "string" + } + } + }, + "GeneralStatsQuery": { + "type": "object", + "required": [ + "start_date", + "end_date" + ], + "properties": { + "end_date": { + "type": "string", + "format": "date-time" + }, + "start_date": { + "type": "string", + "format": "date-time" + } + } + }, + "GeneralStatsResponse": { + "type": "object", + "required": [ + "total_unique_visitors", + "total_visits", + "total_page_views", + "total_events", + "total_projects", + "avg_bounce_rate", + "avg_engagement_rate", + "project_breakdown" + ], + "properties": { + "avg_bounce_rate": { + "type": "number", + "format": "double" + }, + "avg_engagement_rate": { + "type": "number", + "format": "double" + }, + "page_views_trend_percentage": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Percentage change in page views vs previous period" + }, + "previous_page_views": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Previous period page views" + }, + "previous_unique_visitors": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Previous period unique visitors (same duration, shifted back)" + }, + "project_breakdown": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProjectStatsBreakdown" + } + }, + "total_events": { + "type": "integer", + "format": "int64" + }, + "total_page_views": { + "type": "integer", + "format": "int64" + }, + "total_projects": { + "type": "integer", + "format": "int64" + }, + "total_unique_visitors": { + "type": "integer", + "format": "int64" + }, + "total_visits": { + "type": "integer", + "format": "int64" + }, + "visitors_trend_percentage": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Percentage change in unique visitors vs previous period" + } + } + }, + "GenerateDockerfileRequest": { + "type": "object", + "description": "Request body for generating a Dockerfile from a preset", + "properties": { + "build_command": { + "type": [ + "string", + "null" + ], + "description": "Custom build command (overrides preset default)", + "example": "npm run build" + }, + "install_command": { + "type": [ + "string", + "null" + ], + "description": "Custom install command (overrides preset default)", + "example": "npm ci" + }, + "output_dir": { + "type": [ + "string", + "null" + ], + "description": "Output directory for static builds", + "example": "dist" + }, + "package_manager": { + "type": [ + "string", + "null" + ], + "description": "Package manager used by the project (npm, yarn, pnpm, bun)\nIf not provided, defaults to npm", + "example": "npm" + }, + "project_name": { + "type": [ + "string", + "null" + ], + "description": "Project name/slug used for container naming", + "example": "my-app" + }, + "use_buildkit": { + "type": "boolean", + "description": "Whether to use BuildKit cache mounts for faster builds" + } + } + }, + "GenerateDockerfileResponse": { + "type": "object", + "description": "Response containing a generated Dockerfile and build arguments", + "required": [ + "dockerfile", + "build_args", + "preset" + ], + "properties": { + "build_args": { + "type": "object", + "description": "Build arguments to pass to `docker build --build-arg KEY=VALUE`", + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + } + }, + "dockerfile": { + "type": "string", + "description": "The generated Dockerfile content" + }, + "preset": { + "type": "string", + "description": "The preset slug used for generation" + } + } + }, + "GenerateJoinTokenResponse": { + "type": "object", + "description": "Response returned when a join token is generated (plaintext shown once)", + "required": [ + "token", + "message" + ], + "properties": { + "message": { + "type": "string" + }, + "token": { + "type": "string", + "description": "The plaintext join token \u2014 shown only once, save it now" + } + } + }, + "GeoLocationResponse": { + "type": "object", + "description": "Response containing geolocation information for an IP address", + "required": [ + "ip", + "is_eu" + ], + "properties": { + "city": { + "type": [ + "string", + "null" + ], + "description": "City name", + "example": "Mountain View" + }, + "country": { + "type": [ + "string", + "null" + ], + "description": "Country name", + "example": "United States" + }, + "country_code": { + "type": [ + "string", + "null" + ], + "description": "ISO country code (2 letters)", + "example": "US" + }, + "ip": { + "type": "string", + "description": "IP address that was geolocated", + "example": "8.8.8.8" + }, + "is_eu": { + "type": "boolean", + "description": "Whether the IP is in the European Union", + "example": false + }, + "latitude": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Latitude coordinate", + "example": 37.386 + }, + "longitude": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Longitude coordinate", + "example": -122.0838 + }, + "region": { + "type": [ + "string", + "null" + ], + "description": "Region/state name", + "example": "California" + }, + "timezone": { + "type": [ + "string", + "null" + ], + "description": "Timezone identifier", + "example": "America/Los_Angeles" + } + } + }, + "GeoRestrictionsConfig": { + "type": "object", + "description": "Geographic restrictions configuration (future feature)", + "properties": { + "allowedCountries": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Allow traffic only from specific countries" + }, + "blockedCountries": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Block traffic from specific countries (ISO 3166-1 alpha-2 codes)" + } + } + }, + "GetDeploymentsParams": { + "type": "object", + "properties": { + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "page": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "per_page": { + "type": [ + "integer", + "null" + ], + "format": "int64" + } + } + }, + "GetEnvironmentVariablesQuery": { + "type": "object", + "properties": { + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "service_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Required by integration-value reveals to bind the plaintext response to\nthe exact service displayed by the client." + }, + "var_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Exact manual env-var row to reveal. Required by the dashboard so\nduplicate keys on disjoint environments cannot cross-reveal." + } + } + }, + "GetFunnelMetricsQuery": { + "type": "object", + "properties": { + "country_code": { + "type": [ + "string", + "null" + ] + }, + "end_date": { + "type": [ + "string", + "null" + ], + "format": "date-time" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "start_date": { + "type": [ + "string", + "null" + ], + "format": "date-time" + } + } + }, + "GetOrCreateDSNRequest": { + "type": "object", + "properties": { + "base_url": { + "type": [ + "string", + "null" + ] + }, + "deployment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + } + }, + "GetProjectSecretsQuery": { + "type": "object", + "properties": { + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + } + }, + "GetProjectSessionReplaysQuery": { + "type": "object", + "required": [ + "project_id" + ], + "properties": { + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "page": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + }, + "per_page": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + }, + "project_id": { + "type": "integer", + "format": "int32" + } + } + }, + "GetProjectSessionReplaysResponse": { + "type": "object", + "required": [ + "sessions", + "page", + "per_page", + "total_count" + ], + "properties": { + "page": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "per_page": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "sessions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SessionReplayWithVisitorDto" + } + }, + "total_count": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + }, + "GetRequest": { + "type": "object", + "description": "Request to get a value by key", + "required": [ + "key" + ], + "properties": { + "key": { + "type": "string", + "description": "The key to retrieve", + "example": "user:123" + }, + "project_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Project ID (required for API key/session auth, optional for deployment tokens)", + "example": 1 + } + } + }, + "GetResponse": { + "type": "object", + "description": "Response for get operation", + "properties": { + "value": { + "description": "The value, or null if not found" + } + } + }, + "GetSessionReplayResponse": { + "type": "object", + "required": [ + "session" + ], + "properties": { + "session": { + "$ref": "#/components/schemas/SessionReplayWithVisitorDto" + } + } + }, + "GetUniqueEventsQuery": { + "type": "object", + "properties": { + "page": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + }, + "page_size": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + } + } + }, + "GetVisitorSessionsQuery": { + "type": "object", + "properties": { + "page": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + }, + "per_page": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + } + } + }, + "GetVisitorSessionsResponse": { + "type": "object", + "required": [ + "sessions", + "page", + "per_page", + "total_count" + ], + "properties": { + "page": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "per_page": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "sessions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SessionReplayWithVisitorDto" + } + }, + "total_count": { + "type": "integer", + "minimum": 0 + } + } + }, + "GitPushEvent": { + "type": "object", + "description": "Git push event information that triggered the deployment", + "required": [ + "repo", + "owner", + "branch", + "commit" + ], + "properties": { + "branch": { + "type": "string", + "description": "Branch that was pushed" + }, + "commit": { + "type": "string", + "description": "Commit SHA" + }, + "owner": { + "type": "string", + "description": "Repository owner/organization" + }, + "repo": { + "type": "string", + "description": "Repository name" + } + } + }, + "GitRefResponse": { + "type": "object", + "description": "Git repository reference response", + "required": [ + "url", + "ref" + ], + "properties": { + "path": { + "type": [ + "string", + "null" + ], + "description": "Path within the repository (for monorepos)" + }, + "ref": { + "type": "string", + "description": "Git reference (branch, tag, or commit)" + }, + "url": { + "type": "string", + "description": "Git repository URL" + } + } + }, + "GitSourcePlan": { + "type": "object", + "description": "Git repository the source platform deploys from", + "required": [ + "owner", + "repo", + "branch", + "is_public" + ], + "properties": { + "branch": { + "type": "string", + "description": "Branch the source platform deploys" + }, + "clone_url": { + "type": [ + "string", + "null" + ], + "description": "Full clone URL, e.g. `https://github.com/owner/repo.git`" + }, + "is_public": { + "type": "boolean", + "description": "True when the repository is public (no credentials on the source\nplatform) \u2014 the project can then build without a git provider\nconnection." + }, + "owner": { + "type": "string", + "description": "Repository owner (organization or user)" + }, + "repo": { + "type": "string", + "description": "Repository name" + } + } + }, + "GlobalConversationResponse": { + "type": "object", + "description": "A conversation in the unified cross-project switcher: carries the project it\nbelongs to (name/slug) so the UI can show where the chat was started and\nlink back to the source.", + "required": [ + "public_id", + "project_id", + "context_type", + "context_id", + "status", + "created_at", + "last_activity_at" + ], + "properties": { + "context_id": { + "type": "string" + }, + "context_type": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "last_activity_at": { + "type": "string" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "project_name": { + "type": [ + "string", + "null" + ] + }, + "project_slug": { + "type": [ + "string", + "null" + ] + }, + "public_id": { + "type": "string" + }, + "status": { + "type": "string" + }, + "title": { + "type": [ + "string", + "null" + ] + } + } + }, + "GlobalEventStatsResponse": { + "type": "object", + "required": [ + "delivered", + "opened", + "clicked", + "bounced", + "complained" + ], + "properties": { + "bounce_rate": { + "type": [ + "number", + "null" + ], + "format": "double" + }, + "bounced": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "click_rate": { + "type": [ + "number", + "null" + ], + "format": "double" + }, + "clicked": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "complained": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "delivered": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "open_rate": { + "type": [ + "number", + "null" + ], + "format": "double" + }, + "opened": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + }, + "GlobalMrrResponse": { + "type": "object", + "required": [ + "currency", + "current_mrr_minor", + "previous_mrr_minor" + ], + "properties": { + "change_percentage": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Percentage change vs 24h ago. Null when previous MRR is zero\n(no baseline to compare against)." + }, + "currency": { + "type": "string" + }, + "current_mrr_minor": { + "type": "integer", + "format": "int64" + }, + "previous_mrr_minor": { + "type": "integer", + "format": "int64", + "description": "MRR 24h before now, reconstructed from the event log." + } + } + }, + "GlobalRecentEventResponse": { + "type": "object", + "required": [ + "id", + "project_id", + "project_name", + "occurred_at", + "event_type" + ], + "properties": { + "amount_minor": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "currency": { + "type": [ + "string", + "null" + ] + }, + "customer_ref": { + "type": [ + "string", + "null" + ] + }, + "event_type": { + "type": "string" + }, + "id": { + "type": "integer", + "format": "int64" + }, + "mrr_minor": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "occurred_at": { + "type": "string", + "format": "date-time" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "project_name": { + "type": "string" + } + } + }, + "GlobalRevenueSummaryResponse": { + "type": "object", + "required": [ + "currency", + "current_mrr_minor", + "paid_last_30d_minor", + "refunded_last_30d_minor", + "paid_all_time_minor", + "refunded_all_time_minor", + "active_subscriptions", + "active_customers", + "transactions_last_30d" + ], + "properties": { + "active_customers": { + "type": "integer", + "format": "int64" + }, + "active_subscriptions": { + "type": "integer", + "format": "int64" + }, + "currency": { + "type": "string" + }, + "current_mrr_minor": { + "type": "integer", + "format": "int64" + }, + "paid_all_time_minor": { + "type": "integer", + "format": "int64" + }, + "paid_last_30d_minor": { + "type": "integer", + "format": "int64" + }, + "refunded_all_time_minor": { + "type": "integer", + "format": "int64" + }, + "refunded_last_30d_minor": { + "type": "integer", + "format": "int64" + }, + "transactions_last_30d": { + "type": "integer", + "format": "int64" + } + } + }, + "GroupedPageMetric": { + "type": "object", + "required": [ + "group_key", + "events" + ], + "properties": { + "cls": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "country_code": { + "type": [ + "string", + "null" + ], + "description": "ISO 3166-1 alpha-2 code of the group's country. Populated for the\ngeographic dimensions (country/region/city) so clients can match map\ngeometries without name-based lookups; null otherwise." + }, + "events": { + "type": "integer", + "format": "int64" + }, + "fcp": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "group_key": { + "type": "string" + }, + "inp": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "lcp": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "ttfb": { + "type": [ + "number", + "null" + ], + "format": "float" + } + } + }, + "GroupedPageMetricsQuery": { + "allOf": [ + { + "$ref": "#/components/schemas/SpeedSegmentFilters", + "description": "Segment filters \u2014 same shape as `PerformanceMetricsQuery`." + }, + { + "type": "object", + "required": [ + "start_date", + "end_date", + "project_id", + "group_by" + ], + "properties": { + "deployment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "device_type": { + "type": [ + "string", + "null" + ], + "description": "Device type filter: \"desktop\" or \"mobile\"" + }, + "end_date": { + "type": "string", + "format": "date-time" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "group_by": { + "type": "string" + }, + "include_bots": { + "type": [ + "boolean", + "null" + ], + "description": "Include crawler/datacenter (bot) samples. Defaults to false." + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "start_date": { + "type": "string", + "format": "date-time" + } + } + } + ] + }, + "GroupedPageMetricsResponse": { + "type": "object", + "required": [ + "groups", + "total_events", + "grouped_by" + ], + "properties": { + "grouped_by": { + "type": "string" + }, + "groups": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GroupedPageMetric" + } + }, + "total_events": { + "type": "integer", + "format": "int64" + } + } + }, + "HasAnalyticsEventsResponse": { + "type": "object", + "required": [ + "has_events" + ], + "properties": { + "has_events": { + "type": "boolean" + } + } + }, + "HasErrorGroupsResponse": { + "type": "object", + "required": [ + "has_error_groups" + ], + "properties": { + "has_error_groups": { + "type": "boolean" + } + } + }, + "HasEventsQuery": { + "type": "object", + "required": [ + "project_id" + ], + "properties": { + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "project_id": { + "type": "integer", + "format": "int32" + } + } + }, + "HasEventsResponse": { + "type": "object", + "required": [ + "has_events" + ], + "properties": { + "has_events": { + "type": "boolean" + } + } + }, + "HasMetricsQuery": { + "type": "object", + "required": [ + "project_id" + ], + "properties": { + "project_id": { + "type": "integer", + "format": "int32" + } + } + }, + "HasMetricsResponse": { + "type": "object", + "required": [ + "has_metrics" + ], + "properties": { + "has_metrics": { + "type": "boolean" + } + } + }, + "HealthCheckConfiguration": { + "type": "object", + "description": "Health check configuration", + "required": [ + "port", + "interval", + "timeout", + "retries" + ], + "properties": { + "http_path": { + "type": [ + "string", + "null" + ], + "description": "HTTP path to check (if applicable)" + }, + "interval": { + "type": "integer", + "format": "int32", + "description": "Interval between checks (seconds)", + "minimum": 0 + }, + "port": { + "type": "integer", + "format": "int32", + "description": "Port to check", + "minimum": 0 + }, + "retries": { + "type": "integer", + "format": "int32", + "description": "Number of retries before marking unhealthy", + "minimum": 0 + }, + "timeout": { + "type": "integer", + "format": "int32", + "description": "Timeout for each check (seconds)", + "minimum": 0 + } + } + }, + "HealthCheckEntryResponse": { + "type": "object", + "required": [ + "checked_at", + "status" + ], + "properties": { + "checked_at": { + "type": "string", + "description": "ISO 8601 timestamp of when the probe ran.", + "example": "2026-04-22T11:30:00Z" + }, + "error_message": { + "type": [ + "string", + "null" + ], + "description": "Present only when the probe failed or was degraded." + }, + "response_time_ms": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "TCP connect latency in milliseconds." + }, + "status": { + "type": "string", + "description": "\"operational\" | \"degraded\" | \"down\"", + "example": "operational" + } + } + }, + "HealthResponse": { + "type": "object", + "required": [ + "summaries" + ], + "properties": { + "summaries": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HealthSummary" + } + } + } + }, + "HealthStatus": { + "type": "string", + "description": "Overall health status.", + "enum": [ + "healthy", + "degraded", + "down", + "unknown" + ] + }, + "HealthSummary": { + "type": "object", + "description": "Pre-computed health summary for a project environment.", + "required": [ + "project_id", + "service_name", + "status", + "uptime_pct", + "error_rate", + "p95_latency_ms", + "cpu_usage_pct", + "memory_usage_pct", + "computed_at" + ], + "properties": { + "computed_at": { + "type": "string", + "format": "date-time" + }, + "cpu_usage_pct": { + "type": "number", + "format": "double" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "error_rate": { + "type": "number", + "format": "double" + }, + "last_deploy_at": { + "type": [ + "string", + "null" + ], + "format": "date-time" + }, + "last_deploy_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "memory_usage_pct": { + "type": "number", + "format": "double" + }, + "p95_latency_ms": { + "type": "number", + "format": "double" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "service_name": { + "type": "string" + }, + "status": { + "$ref": "#/components/schemas/HealthStatus" + }, + "uptime_pct": { + "type": "number", + "format": "double" + } + } + }, + "HeartbeatApiRequest": { + "type": "object", + "properties": { + "architecture": { + "type": [ + "string", + "null" + ], + "description": "Container platform of this node's Docker daemon (`linux/amd64`,\n`linux/arm64`), read from `docker info` by the agent. Absent from\npre-multi-arch agents; the stored value is then left untouched." + }, + "capacity": { + "description": "Resource capacity/usage info as JSON (cpu_usage, memory_usage, etc.)" + }, + "containers": { + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/components/schemas/ContainerInventoryItem" + }, + "description": "Container inventory for reconciliation (sent on first heartbeat after agent startup).\nEach entry has `container_id` and `container_name` of temps-managed containers." + }, + "labels": { + "description": "Updated node labels for scheduling (allows runtime label changes)." + } + } + }, + "HeartbeatResponse": { + "type": "object", + "required": [ + "status", + "message" + ], + "properties": { + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "HierarchyLevel": { + "type": "object", + "description": "Describes a level in the data source hierarchy", + "required": [ + "level", + "name", + "container_type", + "can_list_containers", + "can_list_entities" + ], + "properties": { + "can_list_containers": { + "type": "boolean", + "description": "Can list containers at this level?", + "example": true + }, + "can_list_entities": { + "type": "boolean", + "description": "Can list entities at this level?", + "example": false + }, + "container_type": { + "type": "string", + "description": "Type of container at this level", + "example": "database" + }, + "level": { + "type": "integer", + "format": "int32", + "description": "Level number (0 = root)", + "example": 0, + "minimum": 0 + }, + "name": { + "type": "string", + "description": "Human-readable name for this level", + "example": "root" + } + } + }, + "HistogramSummary": { + "type": "object", + "description": "An explicit-bucket histogram aggregated over a time bucket.\n\nCarries the reduced scalars (count/sum/min/max) plus the explicit bucket\nlayout \u2014 `bounds` (the upper bounds) and `bucket_counts` (observation counts,\nsummed element-wise across the window; length is `bounds.len() + 1`, the last\nentry being the +Inf overflow bucket). With these, a caller can reconstruct\nany quantile (e.g. p95) via cumulative-count interpolation.", + "required": [ + "count", + "sum", + "bounds", + "bucket_counts" + ], + "properties": { + "bounds": { + "type": "array", + "items": { + "type": "number", + "format": "double" + }, + "description": "Explicit bucket upper bounds (OTLP `explicit_bounds`), ascending." + }, + "bucket_counts": { + "type": "array", + "items": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "description": "Per-bucket observation counts summed element-wise across the window.\nLength is `bounds.len() + 1` (the trailing element is the +Inf bucket)." + }, + "count": { + "type": "integer", + "format": "int64", + "description": "Total observation count summed across the bucket window.", + "minimum": 0 + }, + "max": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Maximum observed value, when reported by the producer." + }, + "min": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Minimum observed value, when reported by the producer." + }, + "sum": { + "type": "number", + "format": "double", + "description": "Sum of observed values across the bucket window." + } + } + }, + "HostnameChange": { + "type": "object", + "description": "A single generated-hostname change in a flatten preview/apply.", + "required": [ + "kind", + "id", + "old", + "new" + ], + "properties": { + "id": { + "type": "integer", + "format": "int32", + "description": "Row id of the affected record." + }, + "kind": { + "type": "string", + "description": "`\"deployment\"` or `\"environment\"`." + }, + "new": { + "type": "string" + }, + "old": { + "type": "string" + } + } + }, + "HostnamePreviewResponse": { + "type": "object", + "description": "Combined preview of a hostname-mode change.", + "required": [ + "hostname_changes", + "dns_changes", + "total" + ], + "properties": { + "dns_changes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DnsRecordChange" + } + }, + "hostname_changes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HostnameChange" + } + }, + "total": { + "type": "integer", + "minimum": 0 + }, + "zone_access_ok": { + "type": [ + "boolean", + "null" + ], + "description": "Whether the provider token can manage this zone (None if not checked)." + } + } + }, + "HourlyPageSessions": { + "type": "object", + "required": [ + "timestamp", + "session_count", + "event_count", + "avg_duration_seconds" + ], + "properties": { + "avg_duration_seconds": { + "type": "number", + "format": "double" + }, + "event_count": { + "type": "integer", + "format": "int64" + }, + "session_count": { + "type": "integer", + "format": "int64" + }, + "timestamp": { + "type": "string" + } + } + }, + "HourlyVisitsQuery": { + "type": "object", + "required": [ + "start_date", + "end_date" + ], + "properties": { + "aggregation_level": { + "$ref": "#/components/schemas/AggregationLevel", + "description": "Aggregation level: events (page views), sessions (unique sessions), or visitors (unique visitors)" + }, + "end_date": { + "type": "string", + "format": "date-time" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "start_date": { + "type": "string", + "format": "date-time" + } + } + }, + "HttpChallengeDebugResponse": { + "type": "object", + "required": [ + "domain", + "challenge_exists", + "dns_a_records", + "dns_aaaa_records" + ], + "properties": { + "challenge_exists": { + "type": "boolean" + }, + "challenge_token": { + "type": [ + "string", + "null" + ] + }, + "challenge_url": { + "type": [ + "string", + "null" + ], + "description": "The full URL that Let's Encrypt will try to access to validate the challenge" + }, + "dns_a_records": { + "type": "array", + "items": { + "type": "string" + }, + "description": "IPv4 addresses the domain points to" + }, + "dns_aaaa_records": { + "type": "array", + "items": { + "type": "string" + }, + "description": "IPv6 addresses the domain points to" + }, + "dns_error": { + "type": [ + "string", + "null" + ], + "description": "Any DNS resolution errors" + }, + "domain": { + "type": "string" + }, + "validation_url": { + "type": [ + "string", + "null" + ], + "description": "The ACME validation URL (internal to ACME protocol)" + } + } + }, + "ImportCredentials": { + "type": "object", + "description": "Platform-specific credentials for accessing the source system.\n\nFor platforms like Vercel and Railway, this contains the API token.\nFor self-hosted platforms like Coolify and Dokploy, this also contains\nthe `base_url` of the instance.\n\nLocal importers (Docker) can use `ImportCredentials::none()`.", + "properties": { + "base_url": { + "type": [ + "string", + "null" + ], + "description": "Base URL override (for self-hosted platforms like Coolify, Dokploy)\n\nExample: `https://coolify.example.com`" + }, + "extra": { + "type": "object", + "description": "Additional platform-specific parameters", + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + } + }, + "team_id": { + "type": [ + "string", + "null" + ], + "description": "Team or organization ID (for platforms with team scoping like Vercel)" + }, + "token": { + "type": [ + "string", + "null" + ], + "description": "API token / bearer token for the source platform" + } + } + }, + "ImportExecutionStatus": { + "type": "string", + "description": "Import execution status", + "enum": [ + "pending", + "inprogress", + "completed", + "failed" + ] + }, + "ImportExternalServiceRequest": { + "type": "object", + "description": "Request to import a Docker container as a managed service", + "required": [ + "name", + "service_type", + "parameters", + "container_id" + ], + "properties": { + "container_id": { + "type": "string", + "description": "Container ID or name to import", + "example": "abc123def456" + }, + "name": { + "type": "string", + "description": "Name to register the service as in Temps", + "example": "production-database" + }, + "parameters": { + "type": "object", + "description": "Service configuration parameters", + "additionalProperties": {}, + "propertyNames": { + "type": "string" + } + }, + "service_type": { + "$ref": "#/components/schemas/ServiceTypeRoute", + "description": "Service type" + }, + "version": { + "type": [ + "string", + "null" + ], + "description": "Optional version override" + } + } + }, + "ImportOutcomeResponse": { + "type": "object", + "required": [ + "rows_read", + "inserted", + "updated", + "skipped_stale", + "skipped_invalid", + "errors" + ], + "properties": { + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImportRowErrorResponse" + } + }, + "inserted": { + "type": "integer", + "minimum": 0 + }, + "rows_read": { + "type": "integer", + "minimum": 0 + }, + "skipped_invalid": { + "type": "integer", + "minimum": 0 + }, + "skipped_stale": { + "type": "integer", + "minimum": 0 + }, + "updated": { + "type": "integer", + "minimum": 0 + } + } + }, + "ImportPlan": { + "type": "object", + "description": "Complete import plan describing all operations to onboard a workload.\n\nThe plan is generated from a snapshot and presented to the user for review\nbefore any resources are created. Users can modify individual items\n(skip services, change actions) before approving execution.", + "required": [ + "version", + "source", + "source_id", + "project", + "environment", + "deployment", + "summary", + "metadata" + ], + "properties": { + "additional_deployments": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DeploymentConfiguration" + }, + "description": "Additional deployments (workers, cron jobs, etc.)" + }, + "cost_analysis": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/CostAnalysis", + "description": "Cost, overprovisioning, and savings analysis. Populated by importers\nthat can observe the whole source cluster (currently Kubernetes);\n`None` for container/platform imports." + } + ] + }, + "deployment": { + "$ref": "#/components/schemas/DeploymentConfiguration", + "description": "Primary deployment configuration" + }, + "domains": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DomainPlan" + }, + "description": "Custom domains to migrate" + }, + "environment": { + "$ref": "#/components/schemas/EnvironmentConfiguration", + "description": "Environment configuration" + }, + "metadata": { + "$ref": "#/components/schemas/PlanMetadata", + "description": "Plan metadata" + }, + "project": { + "$ref": "#/components/schemas/ProjectConfiguration", + "description": "Project configuration" + }, + "services": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ServicePlan" + }, + "description": "Services to migrate (databases, caches, blob stores)\n\nEach service has an `action` field the user can change before execution." + }, + "source": { + "type": "string", + "description": "Source system this plan was generated from" + }, + "source_id": { + "type": "string", + "description": "Source workload / project ID in the source system" + }, + "steps": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MigrationStep" + }, + "description": "Ordered list of migration steps that will be executed.\n\nThis is the human-readable execution plan. Each step describes what\nwill happen, what risks are involved, and what the user should verify.\nSteps are executed in order. If a step fails, execution stops and\nalready-created resources are reported for manual cleanup." + }, + "summary": { + "$ref": "#/components/schemas/MigrationSummary", + "description": "Human-readable summary of the entire migration" + }, + "version": { + "type": "string", + "description": "Plan version for compatibility tracking" + } + } + }, + "ImportRowErrorResponse": { + "type": "object", + "required": [ + "row", + "reason" + ], + "properties": { + "reason": { + "type": "string" + }, + "row": { + "type": "integer", + "minimum": 0 + } + } + }, + "ImportSelector": { + "type": "object", + "description": "Selector for discovering workloads", + "properties": { + "label_filter": { + "type": [ + "object", + "null" + ], + "description": "Filter by labels/tags", + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + } + }, + "limit": { + "type": [ + "integer", + "null" + ], + "description": "Limit number of results", + "minimum": 0 + }, + "name_pattern": { + "type": [ + "string", + "null" + ], + "description": "Filter by name pattern (glob/regex)" + }, + "status_filter": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + }, + "description": "Filter by status (running, stopped, deployed, etc.)" + }, + "workload_type_filter": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + }, + "description": "Filter by workload type (container, function, static-site, etc.)" + } + } + }, + "ImportSource": { + "type": "string", + "description": "Import source identifier", + "enum": [ + "docker", + "coolify", + "dokploy", + "vercel", + "netlify", + "railway", + "render", + "fly", + "kubernetes", + "caprover", + "portainer", + "kamal", + "custom" + ] + }, + "ImportSourceCapabilities": { + "type": "object", + "description": "Source capabilities", + "required": [ + "supports_volumes", + "supports_networks", + "supports_health_checks", + "supports_resource_limits", + "supports_build", + "supports_services", + "supports_domains", + "supports_project_snapshot", + "supports_cost_analysis", + "requires_credentials" + ], + "properties": { + "requires_credentials": { + "type": "boolean", + "description": "Whether this source requires API credentials (token, base URL)" + }, + "supports_build": { + "type": "boolean" + }, + "supports_cost_analysis": { + "type": "boolean", + "description": "Supports cluster cost + overprovisioning analysis in the plan" + }, + "supports_domains": { + "type": "boolean", + "description": "Supports custom domain migration" + }, + "supports_health_checks": { + "type": "boolean" + }, + "supports_networks": { + "type": "boolean" + }, + "supports_project_snapshot": { + "type": "boolean", + "description": "Supports full project-level snapshots" + }, + "supports_resource_limits": { + "type": "boolean" + }, + "supports_services": { + "type": "boolean", + "description": "Supports service migration (databases, caches, etc.)" + }, + "supports_volumes": { + "type": "boolean" + } + } + }, + "ImportSourceInfo": { + "type": "object", + "description": "Information about an import source", + "required": [ + "source", + "name", + "version", + "available", + "capabilities" + ], + "properties": { + "available": { + "type": "boolean", + "description": "Whether the source is currently available" + }, + "capabilities": { + "$ref": "#/components/schemas/ImportSourceCapabilities", + "description": "Capabilities" + }, + "name": { + "type": "string", + "description": "Human-readable name" + }, + "source": { + "$ref": "#/components/schemas/ImportSource", + "description": "Source identifier" + }, + "version": { + "type": "string", + "description": "Source version" + } + } + }, + "ImportStatusResponse": { + "type": "object", + "description": "Response with import status", + "required": [ + "session_id", + "status", + "errors", + "warnings", + "created_at", + "updated_at" + ], + "properties": { + "created_at": { + "type": "string", + "format": "date-time", + "description": "Created at timestamp" + }, + "deployment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Created deployment ID" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Created environment ID" + }, + "errors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Errors (if any)" + }, + "plan": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/ImportPlan", + "description": "Import plan" + } + ] + }, + "project_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Created project ID" + }, + "session_id": { + "type": "string", + "description": "Session ID" + }, + "status": { + "$ref": "#/components/schemas/ImportExecutionStatus", + "description": "Current status" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "description": "Updated at timestamp" + }, + "validation": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/ValidationReport", + "description": "Validation report" + } + ] + }, + "warnings": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Warnings (if any)" + } + } + }, + "IncidentBucket": { + "type": "object", + "required": [ + "bucket_start", + "total_incidents", + "minor_incidents", + "major_incidents", + "critical_incidents", + "resolved_incidents", + "active_incidents" + ], + "properties": { + "active_incidents": { + "type": "integer", + "format": "int64" + }, + "avg_resolution_time_minutes": { + "type": [ + "number", + "null" + ], + "format": "double" + }, + "bucket_start": { + "type": "string", + "format": "date-time" + }, + "critical_incidents": { + "type": "integer", + "format": "int64" + }, + "major_incidents": { + "type": "integer", + "format": "int64" + }, + "minor_incidents": { + "type": "integer", + "format": "int64" + }, + "resolved_incidents": { + "type": "integer", + "format": "int64" + }, + "total_incidents": { + "type": "integer", + "format": "int64" + } + } + }, + "IncidentBucketedResponse": { + "type": "object", + "required": [ + "project_id", + "interval", + "buckets" + ], + "properties": { + "buckets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IncidentBucket" + } + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "interval": { + "type": "string" + }, + "project_id": { + "type": "integer", + "format": "int32" + } + } + }, + "IncidentResponse": { + "type": "object", + "required": [ + "id", + "project_id", + "title", + "severity", + "status", + "started_at", + "created_at", + "updated_at" + ], + "properties": { + "created_at": { + "type": "string", + "format": "date-time" + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "monitor_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "resolved_at": { + "type": [ + "string", + "null" + ], + "format": "date-time" + }, + "severity": { + "type": "string" + }, + "started_at": { + "type": "string", + "format": "date-time" + }, + "status": { + "type": "string" + }, + "title": { + "type": "string" + }, + "updated_at": { + "type": "string", + "format": "date-time" + } + } + }, + "IncidentUpdateResponse": { + "type": "object", + "required": [ + "id", + "incident_id", + "status", + "message", + "created_at" + ], + "properties": { + "created_at": { + "type": "string", + "format": "date-time" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "incident_id": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "IncrRequest": { + "type": "object", + "description": "Request to increment a value", + "required": [ + "key" + ], + "properties": { + "amount": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Amount to increment by (default: 1)" + }, + "key": { + "type": "string", + "description": "The key to increment", + "example": "counter" + }, + "project_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Project ID (required for API key/session auth, optional for deployment tokens)", + "example": 1 + } + } + }, + "IncrResponse": { + "type": "object", + "description": "Response for increment operation", + "required": [ + "value" + ], + "properties": { + "value": { + "type": "integer", + "format": "int64", + "description": "New value after increment", + "example": 42 + } + } + }, + "InitAuthResponse": { + "type": "object", + "required": [ + "auth_url", + "session_token" + ], + "properties": { + "auth_url": { + "type": "string" + }, + "session_token": { + "type": "string" + } + } + }, + "Insight": { + "type": "object", + "description": "An anomaly insight.", + "required": [ + "id", + "project_id", + "service_name", + "severity", + "status", + "title", + "description", + "anomaly_ids", + "started_at", + "created_at", + "updated_at" + ], + "properties": { + "anomaly_ids": { + "type": "array", + "items": { + "type": "integer", + "format": "int64" + } + }, + "correlated_deploy_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "description": { + "type": "string" + }, + "environment": { + "type": [ + "string", + "null" + ] + }, + "id": { + "type": "integer", + "format": "int64" + }, + "metric_name": { + "type": [ + "string", + "null" + ] + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "resolved_at": { + "type": [ + "string", + "null" + ], + "format": "date-time" + }, + "service_name": { + "type": "string" + }, + "severity": { + "$ref": "#/components/schemas/InsightSeverity" + }, + "started_at": { + "type": "string", + "format": "date-time" + }, + "status": { + "$ref": "#/components/schemas/InsightStatus" + }, + "title": { + "type": "string" + }, + "updated_at": { + "type": "string", + "format": "date-time" + } + } + }, + "InsightSeverity": { + "type": "string", + "description": "Severity of an anomaly insight.", + "enum": [ + "low", + "medium", + "high", + "critical" + ] + }, + "InsightStatus": { + "type": "string", + "description": "Status of an insight.", + "enum": [ + "active", + "resolved" + ] + }, + "InsightsResponse": { + "type": "object", + "required": [ + "data", + "count" + ], + "properties": { + "count": { + "type": "integer", + "minimum": 0 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Insight" + } + } + } + }, + "IntegrationResponse": { + "type": "object", + "required": [ + "id", + "project_id", + "provider", + "webhook_path_token", + "webhook_path", + "status", + "has_secret", + "created_at" + ], + "properties": { + "config": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/ProviderConfig", + "description": "Typed provider config \u2014 allowlist and metered-billing mode. Null\nwhen the operator hasn't configured one yet (accept everything)." + } + ] + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "has_secret": { + "type": "boolean" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "last_event_at": { + "type": [ + "string", + "null" + ], + "format": "date-time" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "provider": { + "type": "string" + }, + "status": { + "type": "string" + }, + "webhook_path": { + "type": "string", + "description": "Relative path the UI can display and copy. The frontend builds\nthe full URL by prefixing its own origin." + }, + "webhook_path_token": { + "type": "string", + "description": "Unguessable token embedded in the public webhook URL. The full\nURL is `{api_origin}/webhooks/revenue/{provider}/{webhook_path_token}`." + } + } + }, + "IpAccessControlQuery": { + "type": "object", + "description": "Query parameters for listing IP access control rules", + "properties": { + "action": { + "type": [ + "string", + "null" + ], + "description": "Filter by action (\"block\" or \"allow\")" + } + } + }, + "IpAccessControlResponse": { + "type": "object", + "description": "Response model for IP access control rules", + "required": [ + "id", + "ip_address", + "action", + "created_at", + "updated_at" + ], + "properties": { + "action": { + "type": "string" + }, + "created_at": { + "type": "string", + "example": "2025-10-12T12:15:47.609Z" + }, + "created_by": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "ip_address": { + "type": "string" + }, + "reason": { + "type": [ + "string", + "null" + ] + }, + "updated_at": { + "type": "string", + "example": "2025-10-12T12:15:47.609Z" + } + } + }, + "JobStatusResponse": { + "type": "object", + "description": "Snapshot of a background job. `status` is one of \"running\" | \"exited\"\n| \"failed\"; `exit_code` is populated only when `status == \"exited\"`.", + "required": [ + "status", + "stdout", + "stderr" + ], + "properties": { + "exit_code": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "reason": { + "type": [ + "string", + "null" + ] + }, + "status": { + "type": "string" + }, + "stderr": { + "type": "string" + }, + "stdout": { + "type": "string" + } + } + }, + "JobSummaryResponse": { + "type": "object", + "description": "Row in the jobs list. Omits stdout/stderr so a noisy dev server doesn't\nbloat the list payload \u2014 callers drill into `GET /jobs/{id}` for the\nfull buffer.", + "required": [ + "id", + "status", + "cmd", + "started_at" + ], + "properties": { + "cmd": { + "type": "string" + }, + "exit_code": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "id": { + "type": "string" + }, + "reason": { + "type": [ + "string", + "null" + ] + }, + "started_at": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "JoinTokenStatusResponse": { + "type": "object", + "description": "Response for join token status check", + "required": [ + "has_token" + ], + "properties": { + "has_token": { + "type": "boolean", + "description": "Whether a join token has been configured" + } + } + }, + "JourneyEvent": { + "type": "object", + "description": "A single event in the visitor journey timeline", + "required": [ + "id", + "event_type", + "event_name", + "occurred_at", + "is_entry", + "is_exit", + "is_bounce" + ], + "properties": { + "event_data": { + "description": "Custom event properties (for custom events)" + }, + "event_name": { + "type": "string", + "description": "Resolved event name (event_name for custom events, event_type for system events)" + }, + "event_type": { + "type": "string", + "description": "Event type: \"page_view\", \"page_leave\", \"custom\", \"web_vitals\"" + }, + "id": { + "type": "integer", + "format": "int64", + "description": "Event ID" + }, + "is_bounce": { + "type": "boolean", + "description": "Whether this was a bounce" + }, + "is_entry": { + "type": "boolean", + "description": "Whether this is the entry page of the session" + }, + "is_exit": { + "type": "boolean", + "description": "Whether this is the exit page of the session" + }, + "occurred_at": { + "type": "string", + "format": "date-time", + "description": "When the event occurred" + }, + "page_path": { + "type": [ + "string", + "null" + ], + "description": "Page path where the event happened" + }, + "page_title": { + "type": [ + "string", + "null" + ], + "description": "Page title (if available)" + }, + "referrer": { + "type": [ + "string", + "null" + ], + "description": "Referrer URL for this event" + }, + "scroll_depth": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Scroll depth percentage (0-100)" + }, + "session_page_number": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Page number within the session (1-indexed)" + }, + "time_on_page": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Time spent on page in seconds (computed, not from column)" + } + } + }, + "JourneySession": { + "type": "object", + "description": "A session within the visitor journey, grouping events", + "required": [ + "session_id", + "started_at", + "duration_seconds", + "page_views", + "events_count", + "is_bounced", + "is_engaged", + "events" + ], + "properties": { + "channel": { + "type": [ + "string", + "null" + ], + "description": "Traffic source: channel (e.g. \"organic\", \"direct\", \"social\")" + }, + "duration_seconds": { + "type": "integer", + "format": "int64", + "description": "Session duration in seconds" + }, + "ended_at": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "When the session ended" + }, + "entry_path": { + "type": [ + "string", + "null" + ], + "description": "Entry page path" + }, + "events": { + "type": "array", + "items": { + "$ref": "#/components/schemas/JourneyEvent" + }, + "description": "Events within this session, ordered chronologically" + }, + "events_count": { + "type": "integer", + "format": "int64", + "description": "Total events in this session" + }, + "exit_path": { + "type": [ + "string", + "null" + ], + "description": "Exit page path" + }, + "is_bounced": { + "type": "boolean", + "description": "Whether the session was a bounce" + }, + "is_engaged": { + "type": "boolean", + "description": "Whether the visitor was engaged (had non-pageview events)" + }, + "page_views": { + "type": "integer", + "format": "int64", + "description": "Number of page views in this session" + }, + "referrer": { + "type": [ + "string", + "null" + ], + "description": "Traffic source: referrer URL" + }, + "referrer_hostname": { + "type": [ + "string", + "null" + ], + "description": "Traffic source: referrer hostname" + }, + "session_id": { + "type": "integer", + "format": "int32", + "description": "Session internal ID" + }, + "started_at": { + "type": "string", + "format": "date-time", + "description": "When the session started" + }, + "utm_campaign": { + "type": [ + "string", + "null" + ], + "description": "UTM campaign parameter" + }, + "utm_medium": { + "type": [ + "string", + "null" + ], + "description": "UTM medium parameter" + }, + "utm_source": { + "type": [ + "string", + "null" + ], + "description": "UTM source parameter" + } + } + }, + "KeysRequest": { + "type": "object", + "description": "Request to get keys matching a pattern", + "required": [ + "pattern" + ], + "properties": { + "pattern": { + "type": "string", + "description": "Pattern to match (supports * and ? wildcards)", + "example": "user:*" + }, + "project_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Project ID (required for API key/session auth, optional for deployment tokens)", + "example": 1 + } + } + }, + "KeysResponse": { + "type": "object", + "description": "Response for keys operation", + "required": [ + "keys" + ], + "properties": { + "keys": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of matching keys", + "example": [ + "user:1", + "user:2", + "user:3" + ] + } + } + }, + "KillJobBody": { + "type": "object", + "properties": { + "force": { + "type": "boolean", + "description": "When true, sends SIGKILL immediately. Defaults to SIGTERM so the\nprocess gets a chance to flush (mirrors `Command.kill()` in\n`@vercel/sandbox`, which also accepts a signal override)." + } + }, + "additionalProperties": false + }, + "KnownAiAgentsResponse": { + "type": "object", + "description": "Response listing every AI agent the detector knows about.", + "required": [ + "items" + ], + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AiAgentDescriptor" + } + } + } + }, + "KvStatusResponse": { + "type": "object", + "description": "Response for KV service status", + "required": [ + "enabled", + "healthy" + ], + "properties": { + "docker_image": { + "type": [ + "string", + "null" + ], + "description": "Docker image being used", + "example": "gotempsh/redis-walg:8-bookworm" + }, + "enabled": { + "type": "boolean", + "description": "Whether the KV service is enabled" + }, + "healthy": { + "type": "boolean", + "description": "Whether the underlying Redis service is healthy" + }, + "version": { + "type": [ + "string", + "null" + ], + "description": "Service version", + "example": "7.2" + } + } + }, + "LemonSqueezyConfig": { + "type": "object", + "properties": { + "product_allowlist": { + "type": "array", + "items": { + "type": "string" + } + }, + "variant_allowlist": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "LetsEncryptSettings": { + "type": "object", + "properties": { + "email": { + "type": [ + "string", + "null" + ], + "default": null + }, + "environment": { + "type": "string", + "default": "production" + } + } + }, + "LineContext": { + "type": "object", + "description": "Raw surrounding lines for a single match (grep -C style).", + "required": [ + "before", + "after" + ], + "properties": { + "after": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ContextLine" + }, + "description": "Lines immediately after the match, oldest-first." + }, + "before": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ContextLine" + }, + "description": "Lines immediately before the match, oldest-first." + } + } + }, + "LinkServiceRequest": { + "type": "object", + "required": [ + "project_id" + ], + "properties": { + "project_id": { + "type": "integer", + "format": "int32" + } + } + }, + "ListAgentsResponse": { + "type": "object", + "required": [ + "items", + "total" + ], + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AgentConfigResponse" + } + }, + "total": { + "type": "integer", + "minimum": 0 + } + } + }, + "ListApiKeysQuery": { + "type": "object", + "properties": { + "page": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + }, + "page_size": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + } + } + }, + "ListAuditLogsQuery": { + "type": "object", + "description": "Query parameters for listing audit logs.\n\nEvery field is optional \u2014 omitting one means \"don't filter on it\". Deriving\n`IntoParams` makes utoipa render them as optional query params with the\ncorrect types; the previous hand-written `params((\"operation_type\", Query,\n\u2026))` tuples defaulted every param to `required: true, type: string`, which\nmisled both API clients and the AI `describe_api`/`call_api` tools into\nthinking all filters were mandatory.", + "properties": { + "from": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "Start timestamp (milliseconds since epoch)" + }, + "limit": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Maximum number of logs to return" + }, + "offset": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Number of logs to skip" + }, + "operation_type": { + "type": [ + "string", + "null" + ], + "description": "Filter logs by operation type (omit for all)" + }, + "to": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "End timestamp (milliseconds since epoch)" + }, + "user_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Filter logs by user ID (omit for all users)" + } + } + }, + "ListBlobsQuery": { + "type": "object", + "description": "Query parameters for listing blobs", + "properties": { + "cursor": { + "type": [ + "string", + "null" + ], + "description": "Continuation token for pagination" + }, + "limit": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Maximum number of items to return", + "example": 100 + }, + "prefix": { + "type": [ + "string", + "null" + ], + "description": "Prefix to filter by", + "example": "images/" + }, + "project_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Project ID (required for API key/session auth, optional for deployment tokens)", + "example": 1 + } + } + }, + "ListBlobsResponse": { + "type": "object", + "description": "Response for listing blobs", + "required": [ + "blobs", + "hasMore" + ], + "properties": { + "blobs": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BlobResponse" + }, + "description": "List of blobs" + }, + "cursor": { + "type": [ + "string", + "null" + ], + "description": "Continuation token for next page" + }, + "hasMore": { + "type": "boolean", + "description": "Whether there are more results", + "example": false + } + } + }, + "ListCustomDomainsResponse": { + "type": "object", + "required": [ + "domains", + "total" + ], + "properties": { + "domains": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomDomainResponse" + } + }, + "total": { + "type": "integer", + "minimum": 0 + } + } + }, + "ListDeploymentTokensQuery": { + "type": "object", + "properties": { + "page": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "example": 1, + "minimum": 0 + }, + "page_size": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "example": 20, + "minimum": 0 + } + } + }, + "ListDomainsResponse": { + "type": "object", + "required": [ + "domains", + "total", + "page", + "page_size" + ], + "properties": { + "domains": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DomainResponse" + } + }, + "page": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "page_size": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "total": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + }, + "ListEntitiesQuery": { + "type": "object", + "properties": { + "limit": { + "type": "integer", + "description": "Maximum number of entities to return", + "example": 100, + "minimum": 0 + }, + "token": { + "type": [ + "string", + "null" + ], + "description": "Continuation token for pagination (backend-specific)" + } + } + }, + "ListErrorEventsQuery": { + "type": "object", + "properties": { + "page": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "page_size": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + }, + "ListErrorGroupsQuery": { + "type": "object", + "properties": { + "end_date": { + "type": [ + "string", + "null" + ], + "format": "date-time" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "page": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "page_size": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "sort_by": { + "type": [ + "string", + "null" + ] + }, + "sort_order": { + "type": "string" + }, + "start_date": { + "type": [ + "string", + "null" + ], + "format": "date-time" + }, + "status": { + "type": [ + "string", + "null" + ] + } + } + }, + "ListJobsResponse": { + "type": "object", + "required": [ + "items" + ], + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/JobSummaryResponse" + } + } + } + }, + "ListMcpsResponse": { + "type": "object", + "description": "Concrete list wrapper for MCP server definitions (utoipa requires non-generic types).", + "required": [ + "items", + "total" + ], + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/McpDefinitionResponse" + } + }, + "total": { + "type": "integer", + "minimum": 0 + } + } + }, + "ListOnDemandCertsResponse": { + "type": "object", + "description": "Paginated list of on-demand cert attempts (ADR-018 \u00a75 console \"Certificates\"\nsurface). Joined with current `domains.status`, newest first.", + "required": [ + "certs", + "total", + "page", + "page_size" + ], + "properties": { + "certs": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OnDemandCertRow" + } + }, + "page": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "page_size": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "total": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + }, + "ListOrdersResponse": { + "type": "object", + "required": [ + "orders" + ], + "properties": { + "orders": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AcmeOrderResponse" + } + } + } + }, + "ListPresetsResponse": { + "type": "object", + "required": [ + "presets", + "total" + ], + "properties": { + "presets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PresetResponse" + } + }, + "total": { + "type": "integer", + "minimum": 0 + } + } + }, + "ListRunsResponse": { + "type": "object", + "required": [ + "items", + "total", + "page", + "page_size" + ], + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AgentRunResponse" + } + }, + "page": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "page_size": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "total": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + }, + "ListSandboxesResponse": { + "type": "object", + "description": "SDK list response: `{ sandboxes: [...], pagination: {...} }`.", + "required": [ + "sandboxes", + "pagination" + ], + "properties": { + "pagination": { + "$ref": "#/components/schemas/Pagination" + }, + "sandboxes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SandboxInner" + } + } + } + }, + "ListScansQuery": { + "type": "object", + "properties": { + "page": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "example": 1, + "minimum": 0 + }, + "page_size": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "example": 20, + "minimum": 0 + } + } + }, + "ListSecretsResponse": { + "type": "object", + "required": [ + "items", + "total" + ], + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SecretResponse" + } + }, + "total": { + "type": "integer", + "minimum": 0 + } + } + }, + "ListSkillsResponse": { + "type": "object", + "description": "Concrete list wrapper for skill definitions (utoipa requires non-generic types).", + "required": [ + "items", + "total" + ], + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SkillDefinitionResponse" + } + }, + "total": { + "type": "integer", + "minimum": 0 + } + } + }, + "ListTagsResponse": { + "type": "object", + "description": "Response for listing tags", + "required": [ + "tags", + "total" + ], + "properties": { + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of available tags" + }, + "total": { + "type": "integer", + "description": "Total number of tags", + "minimum": 0 + } + } + }, + "ListTemplatesQuery": { + "type": "object", + "description": "Query parameters for listing templates", + "properties": { + "featured": { + "type": [ + "boolean", + "null" + ], + "description": "Only return featured templates" + }, + "tag": { + "type": [ + "string", + "null" + ], + "description": "Filter templates by tag" + } + } + }, + "ListTemplatesResponse": { + "type": "object", + "description": "Response for listing templates", + "required": [ + "templates", + "total" + ], + "properties": { + "templates": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TemplateResponse" + }, + "description": "List of templates" + }, + "total": { + "type": "integer", + "description": "Total number of templates", + "minimum": 0 + } + } + }, + "ListVulnerabilitiesQuery": { + "type": "object", + "properties": { + "page": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "example": 1, + "minimum": 0 + }, + "page_size": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "example": 20, + "minimum": 0 + }, + "severity": { + "type": [ + "string", + "null" + ], + "example": "CRITICAL" + } + } + }, + "LiveVisitorInfo": { + "type": "object", + "required": [ + "id", + "visitor_id", + "project_id", + "environment_id", + "first_seen", + "last_seen", + "is_crawler" + ], + "properties": { + "city": { + "type": [ + "string", + "null" + ] + }, + "country": { + "type": [ + "string", + "null" + ] + }, + "country_code": { + "type": [ + "string", + "null" + ] + }, + "crawler_name": { + "type": [ + "string", + "null" + ] + }, + "current_page": { + "type": [ + "string", + "null" + ], + "description": "Most recent page path visited by this visitor" + }, + "custom_data": {}, + "environment_id": { + "type": "integer", + "format": "int32" + }, + "first_channel": { + "type": [ + "string", + "null" + ], + "description": "Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")" + }, + "first_referrer": { + "type": [ + "string", + "null" + ], + "description": "Full referrer URL from the visitor's first session" + }, + "first_referrer_hostname": { + "type": [ + "string", + "null" + ], + "description": "Hostname extracted from first_referrer" + }, + "first_seen": { + "type": "string", + "format": "date-time", + "example": "2024-01-01T00:00:00" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "ip_address": { + "type": [ + "string", + "null" + ] + }, + "ip_address_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "is_crawler": { + "type": "boolean" + }, + "is_eu": { + "type": [ + "boolean", + "null" + ] + }, + "last_seen": { + "type": "string", + "format": "date-time", + "example": "2024-01-01T00:00:00" + }, + "latitude": { + "type": [ + "number", + "null" + ], + "format": "double" + }, + "longitude": { + "type": [ + "number", + "null" + ], + "format": "double" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "region": { + "type": [ + "string", + "null" + ] + }, + "timezone": { + "type": [ + "string", + "null" + ] + }, + "user_agent": { + "type": [ + "string", + "null" + ] + }, + "visitor_id": { + "type": "string" + } + } + }, + "LiveVisitorsListResponse": { + "type": "object", + "required": [ + "total_count", + "visitors", + "window_minutes" + ], + "properties": { + "total_count": { + "type": "integer", + "format": "int64" + }, + "visitors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LiveVisitorInfo" + } + }, + "window_minutes": { + "type": "integer", + "format": "int32" + } + } + }, + "LocationCount": { + "type": "object", + "required": [ + "location", + "count", + "percentage" + ], + "properties": { + "count": { + "type": "integer", + "format": "int64" + }, + "location": { + "type": "string" + }, + "percentage": { + "type": "number", + "format": "double" + } + } + }, + "LocationGranularity": { + "type": "string", + "enum": [ + "country", + "region", + "city" + ] + }, + "LocationInfo": { + "type": "object", + "properties": { + "city": { + "type": [ + "string", + "null" + ] + }, + "country": { + "type": [ + "string", + "null" + ] + }, + "region": { + "type": [ + "string", + "null" + ] + } + } + }, + "LogLevel": { + "type": "string", + "description": "Normalized log level", + "enum": [ + "TRACE", + "DEBUG", + "INFO", + "WARN", + "ERROR" + ] + }, + "LogRecord": { + "type": "object", + "description": "A single log record ready for storage.", + "required": [ + "project_id", + "resource", + "timestamp", + "observed_timestamp", + "severity", + "severity_text", + "body", + "attributes" + ], + "properties": { + "attributes": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + } + }, + "body": { + "type": "string" + }, + "deployment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "observed_timestamp": { + "type": "string", + "format": "date-time" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "resource": { + "$ref": "#/components/schemas/ResourceInfo" + }, + "severity": { + "$ref": "#/components/schemas/LogSeverity" + }, + "severity_text": { + "type": "string" + }, + "span_id": { + "type": [ + "string", + "null" + ] + }, + "timestamp": { + "type": "string", + "format": "date-time" + }, + "trace_id": { + "type": [ + "string", + "null" + ] + } + } + }, + "LogSearchLine": { + "type": "object", + "description": "A single line in search results", + "required": [ + "timestamp", + "level", + "service", + "message", + "chunk_id", + "line_offset" + ], + "properties": { + "chunk_id": { + "type": "string" + }, + "container_id": { + "type": "string", + "description": "Container this line came from \u2014 lets the UI tag/group lines by container\nin a combined (\"show all\") multi-container view." + }, + "context": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/LineContext", + "description": "Raw surrounding lines (grep -C). `None` unless `context_lines > 0` was\nrequested. Overlapping windows between nearby matches are merged: the\nshared neighbors appear on the earlier match only, so the frontend can\nrender one continuous block without duplicated lines." + } + ] + }, + "deploy_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "fields": {}, + "level": { + "$ref": "#/components/schemas/LogLevel" + }, + "line_offset": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "node_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Worker node the line came from (`None` = control-plane-local)." + }, + "node_name": { + "type": [ + "string", + "null" + ], + "description": "Human-readable node name for display." + }, + "service": { + "type": "string" + }, + "timestamp": { + "type": "string" + } + } + }, + "LogSeverity": { + "type": "string", + "description": "Log severity level (simplified from OTel's 24 levels).", + "enum": [ + "TRACE", + "DEBUG", + "INFO", + "WARN", + "ERROR", + "FATAL" + ] + }, + "LogSource": { + "type": "object", + "description": "A distinct log source (container) seen in the queried scope. Used to populate\nthe history filter dropdowns with the *full* set of containers/nodes for the\nproject + env + deployment + time window \u2014 independent of the active\ncontainer/node/service filter, so the user can switch between them.", + "required": [ + "container_id", + "service" + ], + "properties": { + "container_id": { + "type": "string" + }, + "node_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "node_name": { + "type": [ + "string", + "null" + ] + }, + "service": { + "type": "string" + } + } + }, + "LogStream": { + "type": "string", + "description": "Log output stream", + "enum": [ + "stdout", + "stderr" + ] + }, + "LoginRequest": { + "type": "object", + "required": [ + "email", + "password" + ], + "properties": { + "email": { + "type": "string" + }, + "password": { + "type": "string" + } + } + }, + "LogsQuery": { + "type": "object", + "properties": { + "tail": { + "type": [ + "integer", + "null" + ], + "description": "Number of lines to return from the tail. Defaults to 200, capped at 2000.", + "minimum": 0 + } + } + }, + "LogsResponse": { + "type": "object", + "required": [ + "data", + "count" + ], + "properties": { + "count": { + "type": "integer", + "minimum": 0 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LogRecord" + } + } + } + }, + "ManagedDomainResponse": { + "type": "object", + "description": "Managed domain response", + "required": [ + "id", + "provider_id", + "domain", + "auto_manage", + "verified", + "generated_hostname_mode", + "sync_generated_records", + "created_at", + "updated_at" + ], + "properties": { + "auto_manage": { + "type": "boolean" + }, + "created_at": { + "type": "string" + }, + "domain": { + "type": "string" + }, + "generated_hostname_mode": { + "type": "string", + "description": "Generated hostname layout: `\"standard\"` or `\"flat\"`." + }, + "id": { + "type": "integer", + "format": "int32" + }, + "provider_id": { + "type": "integer", + "format": "int32" + }, + "sync_generated_records": { + "type": "boolean", + "description": "Whether generated hostnames are reconciled into the provider's DNS zone." + }, + "updated_at": { + "type": "string" + }, + "verification_error": { + "type": [ + "string", + "null" + ] + }, + "verified": { + "type": "boolean" + }, + "verified_at": { + "type": [ + "string", + "null" + ] + }, + "zone_access_error": { + "type": [ + "string", + "null" + ], + "description": "Detail for a failed zone-access check." + }, + "zone_access_ok": { + "type": [ + "boolean", + "null" + ], + "description": "Last token zone-access check: `Some(true)`/`Some(false)`/`None` (unchecked)." + }, + "zone_id": { + "type": [ + "string", + "null" + ] + } + } + }, + "ManualAction": { + "type": "object", + "description": "A manual action the user must perform outside of the automated migration", + "required": [ + "timing", + "description", + "reason" + ], + "properties": { + "description": { + "type": "string", + "description": "Human-readable description" + }, + "reason": { + "type": "string", + "description": "Why this can't be automated" + }, + "timing": { + "$ref": "#/components/schemas/ManualActionTiming", + "description": "When this action needs to happen" + } + } + }, + "ManualActionTiming": { + "type": "string", + "description": "When a manual action needs to happen relative to migration", + "enum": [ + "before-migration", + "after-migration", + "within-hours" + ] + }, + "McpDefinitionResponse": { + "type": "object", + "required": [ + "id", + "slug", + "name", + "config", + "created_at", + "updated_at" + ], + "properties": { + "config": { + "type": "object" + }, + "created_at": { + "type": "string" + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "project_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "slug": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + } + }, + "MessageContent": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "$ref": "#/components/schemas/ContentPart" + } + } + ] + }, + "MessagePart": { + "oneOf": [ + { + "type": "object", + "required": [ + "text", + "type" + ], + "properties": { + "text": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "text" + ] + } + } + }, + { + "type": "object", + "required": [ + "tool", + "type" + ], + "properties": { + "tool": { + "$ref": "#/components/schemas/ToolInfo" + }, + "type": { + "type": "string", + "enum": [ + "tool" + ] + } + } + } + ], + "description": "One ordered segment of an assistant turn: a chunk of prose, or a tool\ninvocation. Mirrors the `metadata.parts` persisted by the chat service." + }, + "MessageResponse": { + "type": "object", + "required": [ + "role", + "content", + "created_at" + ], + "properties": { + "content": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "parts": { + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/components/schemas/MessagePart" + }, + "description": "Ordered render segments (text / tool, in the order they occurred) so a\nreloaded chat shows the same interleaving as the live stream. Absent for\nolder messages persisted before parts were tracked; the client then falls\nback to `tools` (rendered first) + `content`." + }, + "role": { + "type": "string" + }, + "tools": { + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/components/schemas/ToolInfo" + }, + "description": "Tools the assistant ran on this turn (persisted in message metadata), so\nthe chat replays its tool work after a reload. Absent for plain turns." + } + } + }, + "MeteredMode": { + "type": "string", + "description": "How to treat metered-billing subscriptions when computing MRR.\n\n* `DeriveFromInvoices` (default): ignore the subscription row's\n `mrr_minor` for metered items and rely on the per-invoice\n [`NormalizedEventType::MrrRealized`] events instead. Correct for\n pure-metered, hybrid, tiered, and flat \u2014 recommended.\n* `UseSubscription`: trust whatever MRR the subscription parser\n returns (0 for metered). Legacy behavior.\n* `Ignore`: drop metered subscriptions from MRR entirely.", + "enum": [ + "derive_from_invoices", + "use_subscription", + "ignore" + ] + }, + "MetricAggregation": { + "oneOf": [ + { + "type": "string", + "description": "Arithmetic mean of the scalar value in each bucket. The default.", + "enum": [ + "avg" + ] + }, + { + "type": "string", + "description": "Sum of the scalar value in each bucket.", + "enum": [ + "sum" + ] + }, + { + "type": "string", + "description": "Minimum scalar value in each bucket.", + "enum": [ + "min" + ] + }, + { + "type": "string", + "description": "Maximum scalar value in each bucket.", + "enum": [ + "max" + ] + }, + { + "type": "string", + "description": "Number of points in each bucket.", + "enum": [ + "count" + ] + }, + { + "type": "string", + "description": "Per-second rate of change of a cumulative monotonic counter, computed as\n`(max - min) / window_seconds` within each bucket. Non-monotonic series\nfall back to a simple delta.", + "enum": [ + "rate_per_sec" + ] + }, + { + "type": "object", + "description": "A quantile of the scalar value in each bucket. The carried `f64` is the\nrequested quantile in `[0.0, 1.0]`.", + "required": [ + "quantile" + ], + "properties": { + "quantile": { + "type": "number", + "format": "double", + "description": "A quantile of the scalar value in each bucket. The carried `f64` is the\nrequested quantile in `[0.0, 1.0]`." + } + } + } + ], + "description": "The aggregation applied when reducing raw metric points into a time bucket.\n\nStore-neutral: every storage backend (ClickHouse today, TimescaleDB later)\nmust be able to satisfy this contract. `Quantile(q)` carries the requested\nquantile in `[0.0, 1.0]` (e.g. `0.95` for p95)." + }, + "MetricBucket": { + "type": "object", + "description": "A time-bucketed metric aggregate for chart display.\n\nStore-neutral response contract. The legacy scalar fields\n(`avg_value`/`min_value`/`max_value`/`count`) are always populated for chart\nback-compat. The richer fields describe the explicitly-requested\n[`MetricAggregation`] (`value`), optional `quantiles`, an optional\n`histogram_summary`, and a `series_key` identifying the label-set when the\nquery used `group_by`.", + "required": [ + "bucket", + "avg_value", + "min_value", + "max_value", + "count" + ], + "properties": { + "avg_value": { + "type": "number", + "format": "double" + }, + "bucket": { + "type": "string", + "format": "date-time" + }, + "count": { + "type": "integer", + "format": "int64" + }, + "histogram_summary": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/HistogramSummary", + "description": "A reduced histogram summary when the bucketed metric is a histogram." + } + ] + }, + "max_value": { + "type": "number", + "format": "double" + }, + "min_value": { + "type": "number", + "format": "double" + }, + "quantiles": { + "type": "array", + "items": { + "type": "array", + "items": false, + "prefixItems": [ + { + "type": "number", + "format": "double" + }, + { + "type": "number", + "format": "double" + } + ] + }, + "description": "Computed quantile/value pairs `(quantile, value)` when the query asked for\nquantile aggregation; otherwise empty." + }, + "series_key": { + "type": [ + "array", + "null" + ], + "items": { + "type": "array", + "items": false, + "prefixItems": [ + { + "type": "string" + }, + { + "type": "string" + } + ] + }, + "description": "The label-set this bucket belongs to, as ordered `(key, value)` pairs,\nwhen the query grouped by labels. Empty/`None` = the single ungrouped\naggregate stream." + }, + "value": { + "type": "number", + "format": "double", + "description": "The value of the requested [`MetricAggregation`] for this bucket. For the\ndefault `Avg` aggregation this equals `avg_value`. `#[serde(default)]` so\npre-existing payloads (which only carried avg/min/max/count) still parse." + } + } + }, + "MetricDataPoint": { + "type": "object", + "description": "A single `(timestamp, value)` data point in a metric series.", + "required": [ + "time", + "value" + ], + "properties": { + "time": { + "type": "string", + "description": "ISO 8601 timestamp with `Z` suffix." + }, + "value": { + "type": "number", + "format": "double", + "description": "Metric value at this bucket." + } + } + }, + "MetricType": { + "type": "string", + "description": "The type of an OTel metric.", + "enum": [ + "gauge", + "sum", + "histogram", + "exponential_histogram", + "summary" + ] + }, + "MetricsOverTimeResponse": { + "type": "object", + "required": [ + "timestamps", + "ttfb", + "lcp", + "fid", + "fcp", + "cls", + "inp" + ], + "properties": { + "cls": { + "type": "array", + "items": { + "type": [ + "number", + "null" + ], + "format": "float" + } + }, + "cls_p75": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "cls_p90": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "cls_p95": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "cls_p99": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "fcp": { + "type": "array", + "items": { + "type": [ + "number", + "null" + ], + "format": "float" + } + }, + "fcp_p75": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "fcp_p90": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "fcp_p95": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "fcp_p99": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "fid": { + "type": "array", + "items": { + "type": [ + "number", + "null" + ], + "format": "float" + } + }, + "fid_p75": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "fid_p90": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "fid_p95": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "fid_p99": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "inp": { + "type": "array", + "items": { + "type": [ + "number", + "null" + ], + "format": "float" + } + }, + "inp_p75": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "inp_p90": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "inp_p95": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "inp_p99": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "lcp": { + "type": "array", + "items": { + "type": [ + "number", + "null" + ], + "format": "float" + } + }, + "lcp_p75": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "lcp_p90": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "lcp_p95": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "lcp_p99": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "timestamps": { + "type": "array", + "items": { + "type": "string" + } + }, + "ttfb": { + "type": "array", + "items": { + "type": [ + "number", + "null" + ], + "format": "float" + } + }, + "ttfb_p75": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "ttfb_p90": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "ttfb_p95": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "ttfb_p99": { + "type": [ + "number", + "null" + ], + "format": "float" + } + } + }, + "MetricsQuery": { + "type": "object", + "required": [ + "start_date", + "end_date", + "project_id" + ], + "properties": { + "deployment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "end_date": { + "type": "string", + "format": "date-time" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "start_date": { + "type": "string", + "format": "date-time" + } + } + }, + "MetricsRangeQuery": { + "type": "object", + "description": "Query params for range metric queries.", + "required": [ + "metric" + ], + "properties": { + "metric": { + "type": "string", + "description": "Metric name, e.g. `\"pg.connections_active\"`." + }, + "percentile": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Optional histogram percentile (0\u2013100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile." + }, + "range": { + "type": "string", + "description": "Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`." + } + } + }, + "MetricsStatusResponse": { + "type": "object", + "description": "Freshness status: when metrics were last received for this service.", + "properties": { + "last_received_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp of the most recent metric row, or null if none yet." + } + } + }, + "MetricsStoreKind": { + "type": "string", + "description": "Which storage backend to use for the MetricsStore.", + "enum": [ + "timescale_db", + "click_house" + ] + }, + "MetricsSummaryResponse": { + "type": "object", + "required": [ + "currency", + "current_mrr_minor", + "current_arr_minor", + "active_subscriptions", + "active_customers", + "churned_last_30d", + "arpu_minor" + ], + "properties": { + "active_customers": { + "type": "integer", + "format": "int64" + }, + "active_subscriptions": { + "type": "integer", + "format": "int64" + }, + "arpu_minor": { + "type": "integer", + "format": "int64" + }, + "churned_last_30d": { + "type": "integer", + "format": "int64" + }, + "currency": { + "type": "string" + }, + "current_arr_minor": { + "type": "integer", + "format": "int64" + }, + "current_mrr_minor": { + "type": "integer", + "format": "int64" + } + } + }, + "MfaRequiredResponse": { + "type": "object", + "required": [ + "requires_mfa", + "session_token" + ], + "properties": { + "requires_mfa": { + "type": "boolean" + }, + "session_token": { + "type": "string" + } + } + }, + "MfaSetupResponse": { + "type": "object", + "required": [ + "secret_key", + "qr_code", + "recovery_codes" + ], + "properties": { + "qr_code": { + "type": "string" + }, + "recovery_codes": { + "type": "array", + "items": { + "type": "string" + } + }, + "secret_key": { + "type": "string" + } + } + }, + "MfaVerificationRequest": { + "type": "object", + "required": [ + "code" + ], + "properties": { + "code": { + "type": "string" + } + } + }, + "MigrationStep": { + "type": "object", + "description": "A single step in the migration execution plan.\n\nSteps are presented to the user before execution so they know exactly\nwhat will happen. During execution, each step runs in order and reports\nits outcome before proceeding to the next.", + "required": [ + "order", + "id", + "title", + "description", + "resource_type", + "risk", + "skippable", + "reversible" + ], + "properties": { + "data_implications": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DataImplication" + }, + "description": "Data implications \u2014 what could go wrong or what the user needs to know" + }, + "description": { + "type": "string", + "description": "Detailed description of what this step does" + }, + "estimated_duration": { + "type": [ + "string", + "null" + ], + "description": "Estimated duration hint (e.g., \"< 1 second\", \"10-30 seconds\")" + }, + "id": { + "type": "string", + "description": "Machine-readable step identifier (e.g., \"create-project\", \"create-service-postgres\")" + }, + "order": { + "type": "integer", + "description": "Step number (1-based, for display)", + "minimum": 0 + }, + "post_conditions": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Things the user should verify AFTER this step completes" + }, + "pre_conditions": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Things the user should verify BEFORE this step runs" + }, + "resource_type": { + "$ref": "#/components/schemas/StepResourceType", + "description": "What kind of resource this step creates/modifies" + }, + "reversible": { + "type": "boolean", + "description": "Whether this step is reversible (can be cleaned up on failure)" + }, + "risk": { + "$ref": "#/components/schemas/RiskLevel", + "description": "Risk level for this step" + }, + "skippable": { + "type": "boolean", + "description": "Whether this step can be skipped by the user" + }, + "skipped": { + "type": "boolean", + "description": "Whether the user has chosen to skip this step (set during review)" + }, + "title": { + "type": "string", + "description": "Human-readable title (e.g., \"Create project 'my-app'\")" + } + } + }, + "MigrationSummary": { + "type": "object", + "description": "Human-readable summary of the entire migration plan", + "required": [ + "headline", + "overall_risk", + "resource_counts" + ], + "properties": { + "critical_warnings": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Critical warnings that must be acknowledged before proceeding.\nThese are the most important things the user needs to know." + }, + "headline": { + "type": "string", + "description": "One-line summary (e.g., \"Migrate 'my-app' from Vercel with 1 database, 2 domains\")" + }, + "manual_actions_required": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ManualAction" + }, + "description": "Manual actions the user must perform (before or after migration)" + }, + "overall_risk": { + "$ref": "#/components/schemas/RiskLevel", + "description": "Overall risk assessment for the migration" + }, + "resource_counts": { + "$ref": "#/components/schemas/ResourceCounts", + "description": "Resource counts for quick overview" + }, + "unsupported_features": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UnsupportedFeature" + }, + "description": "Features from the source platform that cannot be migrated" + } + } + }, + "MintEnrollmentTokenRequest": { + "type": "object", + "properties": { + "bound_node_name": { + "type": [ + "string", + "null" + ], + "description": "Optional: restrict the token to register one specific node name." + }, + "max_uses": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Maximum registrations this token may authorize (default 1)." + }, + "ttl_secs": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Time-to-live in seconds (default 3600 = 1h)." + } + } + }, + "MintEnrollmentTokenResponse": { + "type": "object", + "required": [ + "id", + "token", + "expires_at", + "max_uses", + "message" + ], + "properties": { + "ca_fingerprint": { + "type": [ + "string", + "null" + ], + "description": "SHA-256 fingerprint of the cluster CA (if mTLS is set up). Pass it to the\nworker as `temps join --ca-fingerprint ` to verify the CA on join." + }, + "expires_at": { + "type": "string" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "max_uses": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "token": { + "type": "string", + "description": "The plaintext enrollment token \u2014 shown only once, save it now." + } + } + }, + "MiscResult": { + "type": "object", + "description": "Miscellaneous validation result", + "required": [ + "is_disposable", + "is_role_account", + "is_b2c" + ], + "properties": { + "gravatar_url": { + "type": [ + "string", + "null" + ], + "description": "Gravatar URL if available" + }, + "is_b2c": { + "type": "boolean", + "description": "Whether the email provider is a B2C (consumer) email provider" + }, + "is_disposable": { + "type": "boolean", + "description": "Whether the email is from a disposable email provider" + }, + "is_role_account": { + "type": "boolean", + "description": "Whether the email is a role-based account (e.g., admin@, info@)" + } + } + }, + "MkdirBody": { + "type": "object", + "required": [ + "path" + ], + "properties": { + "path": { + "type": "string" + } + }, + "additionalProperties": false + }, + "ModelInfo": { + "type": "object", + "required": [ + "id", + "object", + "owned_by" + ], + "properties": { + "id": { + "type": "string" + }, + "object": { + "type": "string" + }, + "owned_by": { + "type": "string" + } + } + }, + "ModelListResponse": { + "type": "object", + "required": [ + "object", + "data" + ], + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ModelInfo" + } + }, + "object": { + "type": "string" + } + } + }, + "ModelPricing": { + "type": "object", + "description": "Pricing for a single model, all values in USD per 1M tokens.\nFields are optional because not every provider supports every pricing tier.", + "required": [ + "model", + "display_name", + "provider", + "input_per_million", + "output_per_million" + ], + "properties": { + "batch_input_per_million": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Batch API input cost per 1M tokens (if provider offers batch pricing)" + }, + "batch_output_per_million": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Batch API output cost per 1M tokens" + }, + "cache_hit_per_million": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Cache hit / refresh cost per 1M tokens" + }, + "cache_write_1h_per_million": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "1-hour cache write cost per 1M tokens" + }, + "cache_write_5m_per_million": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "5-minute cache write cost per 1M tokens (Anthropic-style prompt caching)" + }, + "deprecated": { + "type": "boolean", + "description": "Whether the model is deprecated" + }, + "display_name": { + "type": "string", + "description": "Human-readable model name (e.g. \"Claude Sonnet 4.6\")" + }, + "input_per_million": { + "type": "number", + "format": "double", + "description": "Base input token cost per 1M tokens" + }, + "model": { + "type": "string", + "description": "Model identifier (e.g. \"gpt-5.4\", \"claude-sonnet-4-6\")" + }, + "output_per_million": { + "type": "number", + "format": "double", + "description": "Output token cost per 1M tokens" + }, + "provider": { + "type": "string", + "description": "Provider ID (e.g. \"openai\", \"anthropic\")" + } + } + }, + "ModelUsage": { + "type": "object", + "required": [ + "model", + "provider", + "request_count", + "input_tokens", + "output_tokens", + "total_tokens", + "avg_latency_ms" + ], + "properties": { + "avg_latency_ms": { + "type": "number", + "format": "double" + }, + "input_tokens": { + "type": "integer", + "format": "int64" + }, + "model": { + "type": "string" + }, + "output_tokens": { + "type": "integer", + "format": "int64" + }, + "provider": { + "type": "string" + }, + "request_count": { + "type": "integer", + "format": "int64" + }, + "total_tokens": { + "type": "integer", + "format": "int64" + } + } + }, + "MonitorResponse": { + "type": "object", + "required": [ + "id", + "project_id", + "name", + "monitor_type", + "monitor_url", + "check_interval_seconds", + "is_active", + "created_at", + "updated_at" + ], + "properties": { + "check_interval_seconds": { + "type": "integer", + "format": "int32" + }, + "check_path": { + "type": [ + "string", + "null" + ] + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "is_active": { + "type": "boolean" + }, + "monitor_type": { + "type": "string" + }, + "monitor_url": { + "type": "string" + }, + "name": { + "type": "string" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "updated_at": { + "type": "string", + "format": "date-time" + } + } + }, + "MonitorStatus": { + "type": "object", + "required": [ + "monitor", + "current_status", + "uptime_percentage" + ], + "properties": { + "avg_response_time_ms": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "current_status": { + "type": "string" + }, + "monitor": { + "$ref": "#/components/schemas/MonitorResponse" + }, + "uptime_percentage": { + "type": "number", + "format": "double" + } + } + }, + "MonitoringSettings": { + "type": "object", + "description": "Global metrics observability configuration.\n\nControls whether the MetricsScraper and AlertEvaluator background tasks\nare active, which storage backend they write to, and how long data is kept\nat each retention tier.", + "properties": { + "clickhouse_url": { + "type": [ + "string", + "null" + ], + "description": "ClickHouse DSN (legacy, optional). The runtime metrics store is built\nfrom the `TEMPS_CLICKHOUSE_*` env vars, never from this field; it is\nretained for compatibility and operator reference only.\nExample: `\"http://localhost:8123\"`.", + "default": null + }, + "enabled": { + "type": "boolean", + "description": "Enable or disable all metrics collection (scraping + alerting).\nDefaults to `false` so new installs don't write to TimescaleDB until\nan operator explicitly enables the feature.", + "default": false + }, + "retention_daily_years": { + "type": "integer", + "format": "int32", + "description": "How many years of daily-aggregate data to keep (converted to days internally).", + "default": 2, + "example": 2, + "maximum": 10, + "minimum": 1 + }, + "retention_hourly_days": { + "type": "integer", + "format": "int32", + "description": "How many days of hourly-aggregate data to keep.", + "default": 90, + "example": 90, + "minimum": 1 + }, + "retention_raw_days": { + "type": "integer", + "format": "int32", + "description": "How many days of raw (30 s resolution) metric data to keep.", + "default": 7, + "example": 7, + "minimum": 1 + }, + "scrape_interval_secs": { + "type": "integer", + "format": "int64", + "description": "How often the MetricsScraper collects data from all sources, in seconds.\nMinimum effective value is 10 s; values below that are clamped at runtime.", + "default": 30, + "example": 30, + "minimum": 10 + }, + "store": { + "oneOf": [ + { + "$ref": "#/components/schemas/MetricsStoreKind", + "description": "Storage backend for metric data." + } + ], + "default": "timescale_db" + } + } + }, + "MonitoringSettingsMasked": { + "type": "object", + "description": "Monitoring settings with the ClickHouse DSN masked.\n\n`clickhouse_url` can embed credentials (`http://user:pass@host`), so it is\nreported only as a boolean (`clickhouse_url_set`) rather than echoed back \u2014\nconsistent with how the DNS API key and Docker registry password are masked.", + "required": [ + "enabled", + "store", + "scrape_interval_secs", + "retention_raw_days", + "retention_hourly_days", + "retention_daily_years", + "clickhouse_url_set" + ], + "properties": { + "clickhouse_url_set": { + "type": "boolean", + "description": "True when a ClickHouse DSN is configured. The DSN itself is never\nreturned over HTTP because it may contain credentials." + }, + "enabled": { + "type": "boolean" + }, + "retention_daily_years": { + "type": "integer", + "format": "int32", + "minimum": 0 + }, + "retention_hourly_days": { + "type": "integer", + "format": "int32", + "minimum": 0 + }, + "retention_raw_days": { + "type": "integer", + "format": "int32", + "minimum": 0 + }, + "scrape_interval_secs": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "store": { + "$ref": "#/components/schemas/MetricsStoreKind" + } + } + }, + "MrrBucketResponse": { + "type": "object", + "required": [ + "bucket", + "mrr_minor", + "charge_total_minor", + "refund_total_minor", + "charge_count" + ], + "properties": { + "bucket": { + "type": "string", + "format": "date-time" + }, + "charge_count": { + "type": "integer", + "format": "int64" + }, + "charge_total_minor": { + "type": "integer", + "format": "int64" + }, + "mrr_minor": { + "type": "integer", + "format": "int64" + }, + "refund_total_minor": { + "type": "integer", + "format": "int64" + } + } + }, + "MultiNodeSettings": { + "type": "object", + "description": "Multi-node cluster settings", + "properties": { + "cluster_ca_cert_pem": { + "type": [ + "string", + "null" + ], + "description": "Per-cluster CA certificate (PEM) for multi-node mTLS (ADR-020 WS-2.1).\nPublic \u2014 distributed to nodes as the trust root and used by the control\nplane as the root for verifying agent server certs. Minted lazily on the\nfirst CSR-bearing registration.", + "default": null + }, + "cluster_ca_key_encrypted": { + "type": [ + "string", + "null" + ], + "description": "Per-cluster CA private key, AES-256-GCM ciphertext (EncryptionService).\nSECRET \u2014 never returned over HTTP (elided in the masked response).", + "default": null + }, + "join_token_hash": { + "type": [ + "string", + "null" + ], + "description": "SHA-256 hash of the join token (never store plaintext)", + "default": null + }, + "legacy_shared_token_enabled": { + "type": "boolean", + "description": "Whether the legacy single shared join token is still accepted for node\nregistration (ADR-020 WS-1.1). Defaults to `true` so existing clusters\nkeep working on upgrade; fresh installs should set it `false` and rely on\nshort-lived, single-use enrollment tokens instead.", + "default": true + }, + "node_cpu_alert_percent": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "CPU-usage percent above which a worker node raises a resource alert\n(ADR-020 / monitoring). `None` disables CPU alerting. Default 90.", + "default": 90.0 + }, + "node_disk_alert_percent": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Disk-usage percent above which a worker node raises a resource alert.\n`None` disables disk alerting. Default 90.", + "default": 90.0 + }, + "node_memory_alert_percent": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Memory-usage percent above which a worker node raises a resource alert.\n`None` disables memory alerting. Default 90.", + "default": 90.0 + }, + "private_address": { + "type": [ + "string", + "null" + ], + "description": "Private/WireGuard IP address of the control plane node.\nUsed by remote worker nodes to reach services (databases, etc.) running on the control plane.\nSet via `--private-address` or `TEMPS_PRIVATE_ADDRESS`.", + "default": null + }, + "require_mtls": { + "type": "boolean", + "description": "Whether to enforce multi-node mTLS (ADR-020 WS-2.1). When `false`\n(default), the control plane ignores join-time CSRs and nodes keep\nserving plaintext HTTP \u2014 zero behavior change. When `true`, the CP signs\nnode CSRs, nodes serve mutual TLS, and every CP\u2192agent call uses the\ncluster client cert. Observe-then-enforce: flip this on only once all\nworkers have re-enrolled with certs.", + "default": false + } + } + }, + "MultiNodeSettingsMasked": { + "type": "object", + "description": "Multi-node settings with `join_token_hash` elided.", + "required": [ + "has_join_token", + "require_mtls", + "legacy_shared_token_enabled" + ], + "properties": { + "cluster_ca_fingerprint": { + "type": [ + "string", + "null" + ], + "description": "SHA-256 fingerprint of the cluster CA certificate (public \u2014 operators can\nverify it out of band; the CA private key is never exposed)." + }, + "has_join_token": { + "type": "boolean" + }, + "legacy_shared_token_enabled": { + "type": "boolean", + "description": "Whether the deprecated shared join token is still accepted." + }, + "node_cpu_alert_percent": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Node resource-alert thresholds (percent); `None` = that alert disabled." + }, + "node_disk_alert_percent": { + "type": [ + "number", + "null" + ], + "format": "double" + }, + "node_memory_alert_percent": { + "type": [ + "number", + "null" + ], + "format": "double" + }, + "private_address": { + "type": [ + "string", + "null" + ] + }, + "require_mtls": { + "type": "boolean", + "description": "Whether control-plane\u2194agent mutual TLS is enforced." + } + } + }, + "MxResult": { + "type": "object", + "description": "MX (Mail Exchange) validation result", + "required": [ + "accepts_mail", + "records" + ], + "properties": { + "accepts_mail": { + "type": "boolean", + "description": "Whether the domain accepts mail" + }, + "error": { + "type": [ + "string", + "null" + ], + "description": "Error message if MX lookup failed" + }, + "records": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of MX records for the domain", + "example": [ + "alt1.gmail-smtp-in.l.google.com.", + "gmail-smtp-in.l.google.com." + ] + } + } + }, + "NavEntry": { + "type": "object", + "description": "A navigation entry that the plugin contributes to the Temps UI.", + "required": [ + "label", + "icon", + "section", + "path", + "order" + ], + "properties": { + "icon": { + "type": "string", + "description": "Lucide icon name (e.g., \"puzzle\", \"database\", \"activity\")" + }, + "label": { + "type": "string", + "description": "Display label in the sidebar" + }, + "order": { + "type": "integer", + "format": "int32", + "description": "Sort order within the section (lower = higher in list)", + "minimum": 0 + }, + "path": { + "type": "string", + "description": "Client-side route path (e.g., \"/my-plugin\")" + }, + "section": { + "$ref": "#/components/schemas/NavSection", + "description": "Which sidebar section this entry belongs to" + } + } + }, + "NavSection": { + "type": "string", + "description": "Where the plugin's nav entry appears in the Temps UI sidebar.", + "enum": [ + "platform", + "settings", + "project" + ] + }, + "NetworkConfiguration": { + "type": "object", + "description": "Network configuration", + "required": [ + "mode", + "dns_servers" + ], + "properties": { + "dns_servers": { + "type": "array", + "items": { + "type": "string" + }, + "description": "DNS servers" + }, + "hostname": { + "type": [ + "string", + "null" + ], + "description": "Hostname" + }, + "mode": { + "$ref": "#/components/schemas/NetworkMode", + "description": "Network mode" + } + } + }, + "NetworkMode": { + "oneOf": [ + { + "type": "string", + "enum": [ + "bridge" + ] + }, + { + "type": "string", + "enum": [ + "host" + ] + }, + { + "type": "string", + "enum": [ + "none" + ] + }, + { + "type": "object", + "required": [ + "custom" + ], + "properties": { + "custom": { + "type": "string" + } + } + } + ], + "description": "Network mode" + }, + "NixpacksPresetConfig": { + "type": "object", + "description": "Configuration for Nixpacks preset\nNixpacks provider and inline build-plan configuration.", + "properties": { + "nixpacksConfig": { + "type": [ + "string", + "null" + ], + "description": "Optional inline nixpacks.toml contents." + }, + "providers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NixpacksProvider" + }, + "description": "Ordered Nixpacks providers. Empty means repository config or auto-detect;\ninclude `...` to combine auto-detection with explicit providers." + } + } + }, + "NixpacksProvider": { + "type": "string", + "description": "A Nixpacks build provider.\n\n`Auto` serializes as the native Nixpacks `...` marker, which includes the\nprovider detected from the project alongside any explicitly listed\nproviders.", + "enum": [ + "...", + "node", + "python", + "rust", + "go", + "java", + "php", + "ruby", + "deno", + "elixir", + "csharp", + "fsharp", + "dart", + "swift", + "zig", + "scala", + "haskell", + "clojure", + "crystal", + "cobol", + "gleam", + "lunatic", + "scheme", + "static" + ] + }, + "NodeContainerListResponse": { + "type": "object", + "required": [ + "containers", + "total" + ], + "properties": { + "containers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NodeContainerResponse" + } + }, + "total": { + "type": "integer", + "minimum": 0 + } + } + }, + "NodeContainerResponse": { + "type": "object", + "description": "A container running on a specific node, enriched with project/environment context.", + "required": [ + "container_id", + "container_name", + "image_name", + "status", + "created_at", + "deployment_id", + "project_id", + "project_name", + "environment_id", + "environment_name" + ], + "properties": { + "container_id": { + "type": "string" + }, + "container_name": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "deployment_id": { + "type": "integer", + "format": "int32" + }, + "environment_id": { + "type": "integer", + "format": "int32" + }, + "environment_name": { + "type": "string" + }, + "image_name": { + "type": "string" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "project_name": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "NodeCostInfo": { + "type": "object", + "description": "One cluster node with capacity and (when priceable) a cost estimate", + "required": [ + "name", + "cpu_millis", + "memory_mb" + ], + "properties": { + "cpu_millis": { + "type": "integer", + "format": "int64", + "description": "CPU capacity in millicores" + }, + "instance_type": { + "type": [ + "string", + "null" + ], + "description": "Instance type from `node.kubernetes.io/instance-type` (e.g. \"m5.xlarge\")" + }, + "memory_mb": { + "type": "integer", + "format": "int64", + "description": "Memory capacity in MB" + }, + "monthly_usd": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Estimated on-demand monthly price in USD. `None` when the instance\ntype is unknown or not in the price table." + }, + "name": { + "type": "string", + "description": "Node name" + }, + "region": { + "type": [ + "string", + "null" + ], + "description": "Region from `topology.kubernetes.io/region`" + } + } + }, + "NodeInfoResponse": { + "type": "object", + "required": [ + "id", + "name", + "address", + "private_address", + "role", + "status", + "labels", + "capacity", + "created_at" + ], + "properties": { + "address": { + "type": "string" + }, + "architecture": { + "type": [ + "string", + "null" + ], + "description": "Container platform this node runs (`linux/amd64`, `linux/arm64`).\n`None` until an agent that reports it has heartbeated." + }, + "capacity": { + "description": "Resource capacity/usage metrics from the latest heartbeat" + }, + "created_at": { + "type": "string" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "labels": {}, + "last_heartbeat": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": "string" + }, + "private_address": { + "type": "string" + }, + "role": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "NodeListResponse": { + "type": "object", + "required": [ + "nodes", + "total" + ], + "properties": { + "nodes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NodeInfoResponse" + } + }, + "total": { + "type": "integer", + "minimum": 0 + } + } + }, + "NotificationPreferencesResponse": { + "type": "object", + "required": [ + "email_enabled", + "slack_enabled", + "batch_similar_notifications", + "minimum_severity", + "deployment_failures_enabled", + "build_errors_enabled", + "runtime_errors_enabled", + "error_threshold", + "error_time_window", + "ssl_expiration_enabled", + "ssl_days_before_expiration", + "domain_expiration_enabled", + "dns_changes_enabled", + "backup_failures_enabled", + "backup_successes_enabled", + "s3_connection_issues_enabled", + "retention_policy_violations_enabled", + "route_downtime_enabled", + "load_balancer_issues_enabled", + "weekly_digest_enabled", + "digest_send_day", + "digest_send_time", + "digest_sections" + ], + "properties": { + "backup_failures_enabled": { + "type": "boolean" + }, + "backup_successes_enabled": { + "type": "boolean" + }, + "batch_similar_notifications": { + "type": "boolean" + }, + "build_errors_enabled": { + "type": "boolean" + }, + "deployment_failures_enabled": { + "type": "boolean" + }, + "digest_sections": { + "$ref": "#/components/schemas/DigestSections" + }, + "digest_send_day": { + "type": "string" + }, + "digest_send_time": { + "type": "string" + }, + "dns_changes_enabled": { + "type": "boolean" + }, + "domain_expiration_enabled": { + "type": "boolean" + }, + "email_enabled": { + "type": "boolean" + }, + "error_threshold": { + "type": "integer", + "format": "int32" + }, + "error_time_window": { + "type": "integer", + "format": "int32" + }, + "load_balancer_issues_enabled": { + "type": "boolean" + }, + "minimum_severity": { + "type": "string" + }, + "retention_policy_violations_enabled": { + "type": "boolean" + }, + "route_downtime_enabled": { + "type": "boolean" + }, + "runtime_errors_enabled": { + "type": "boolean" + }, + "s3_connection_issues_enabled": { + "type": "boolean" + }, + "slack_enabled": { + "type": "boolean" + }, + "ssl_days_before_expiration": { + "type": "integer", + "format": "int32" + }, + "ssl_expiration_enabled": { + "type": "boolean" + }, + "weekly_digest_enabled": { + "type": "boolean" + } + } + }, + "NotificationProviderResponse": { + "type": "object", + "required": [ + "id", + "name", + "provider_type", + "config", + "enabled", + "created_at", + "updated_at" + ], + "properties": { + "config": {}, + "created_at": { + "type": "integer", + "format": "int64" + }, + "enabled": { + "type": "boolean" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "provider_type": { + "type": "string" + }, + "updated_at": { + "type": "integer", + "format": "int64" + } + } + }, + "ObservabilityCompressionSettings": { + "type": "object", + "description": "TimescaleDB compression policy configuration for append-only observability\ntables. Values are expressed in hours so operators can choose sub-day\nwindows while keeping the API representation unambiguous.", + "properties": { + "otel_spans_after_hours": { + "type": "integer", + "format": "int32", + "description": "Compress OpenTelemetry span chunks after this many hours. Defaults to\n24 hours.", + "default": 24, + "example": 24, + "maximum": 2160, + "minimum": 1 + }, + "proxy_logs_after_hours": { + "type": "integer", + "format": "int32", + "description": "Compress proxy-log chunks after this many hours. Defaults to 24 hours.", + "default": 24, + "example": 24, + "maximum": 720, + "minimum": 1 + } + } + }, + "ObservabilityEvent": { + "oneOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/RequestRow" + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "request" + ] + } + } + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/SpanRow" + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "span" + ] + } + } + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/ErrorRow" + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "error" + ] + } + } + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/RevenueRow" + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "revenue" + ] + } + } + } + ] + } + ], + "description": "Discriminated union of every row that can appear in the Observe list.\n\nSerializes to `{ \"type\": \"request\" | \"span\" | ... , ...rest }` so the UI\ncan switch on `event.type` without ambiguity.\n\n**No `Log` variant**: runtime stdout/stderr lines live on a dedicated\nLogs page rather than Observe. Logs are too high-volume to interleave\nwith business signals (requests, errors, revenue) without dominating\nthe timeline, and they have their own retention/storage constraints\n(TimescaleDB hypertable + chunked file/S3 store) that don't compose\nwith the merge service's per-kind LIMIT strategy." + }, + "ObservabilityRetentionSettings": { + "type": "object", + "description": "Retention policy configuration for raw observability tables. Values are in\ndays. The Settings API applies them to TimescaleDB; ClickHouse-backed proxy\nlogs and spans retain their storage-level per-row TTL behavior.", + "properties": { + "otel_logs_days": { + "type": "integer", + "format": "int32", + "description": "Retain OpenTelemetry log events for this many days.", + "default": 90, + "example": 90, + "maximum": 3650, + "minimum": 1 + }, + "otel_metrics_days": { + "type": "integer", + "format": "int32", + "description": "Retain OpenTelemetry metric points for this many days.", + "default": 90, + "example": 90, + "maximum": 3650, + "minimum": 1 + }, + "otel_spans_days": { + "type": "integer", + "format": "int32", + "description": "Retain OpenTelemetry spans (traces) for this many days.", + "default": 90, + "example": 90, + "maximum": 3650, + "minimum": 1 + }, + "proxy_logs_days": { + "type": "integer", + "format": "int32", + "description": "Retain proxy request logs for this many days.", + "default": 30, + "example": 30, + "maximum": 3650, + "minimum": 1 + } + } + }, + "OidcProviderResponse": { + "type": "object", + "required": [ + "id", + "name", + "issuer_url", + "client_id", + "client_secret", + "scopes", + "jit_provisioning", + "enabled", + "template", + "group_claim", + "role_claim", + "default_role", + "trust_idp_email" + ], + "properties": { + "client_id": { + "type": "string" + }, + "client_secret": { + "type": "string", + "description": "Always masked \u2014 the secret is never returned after creation." + }, + "default_role": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "group_claim": { + "type": "string" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "issuer_url": { + "type": "string" + }, + "jit_provisioning": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "role_claim": { + "type": "string" + }, + "scopes": { + "type": "string" + }, + "template": { + "type": "string" + }, + "trust_idp_email": { + "type": "boolean", + "description": "When true, the resolver skips the `email_verified` claim gate\nduring SSO login. Only safe for IdPs where an admin controls\nuser provisioning \u2014 see `oidc_providers::Model::trust_idp_email`." + } + } + }, + "OidcProviderSummary": { + "type": "object", + "required": [ + "slug", + "name", + "template" + ], + "properties": { + "name": { + "type": "string" + }, + "slug": { + "type": "string", + "description": "Stable opaque slug \u2014 use this as the path parameter when initiating\nOIDC login (`/auth/oidc/login/{slug}`). The integer database ID is\nintentionally omitted from this public endpoint to prevent provider\nenumeration." + }, + "template": { + "type": "string", + "description": "The template the provider was created from \u2014 e.g. `keycloak`,\n`okta`, `auth0`, `google`, `azure-ad`, or `generic`. Surfaced on\nthe public login endpoint so the unauthenticated login page can\nrender the right brand logo on the \"Sign in with X\" button.\nNever sensitive \u2014 the template name is part of the provider's\npublic identity, not configuration." + } + } + }, + "OidcProviderUserResponse": { + "type": "object", + "description": "A user that has logged in via a given OIDC provider. Used by the\nadmin \"Users for provider\" panel \u2014 the `oidc_subject` is the\nIdP-side identifier we matched on, useful when diagnosing why a\nuser can or can't log in.", + "required": [ + "id", + "name", + "email", + "email_verified", + "mfa_enabled", + "created_at", + "updated_at" + ], + "properties": { + "created_at": { + "type": "string", + "format": "date-time", + "example": "2024-01-15T14:30:00Z" + }, + "email": { + "type": "string" + }, + "email_verified": { + "type": "boolean" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "mfa_enabled": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "oidc_subject": { + "type": [ + "string", + "null" + ] + }, + "updated_at": { + "type": "string", + "format": "date-time", + "example": "2024-01-15T14:30:00Z" + } + } + }, + "OidcProvidersListResponse": { + "type": "object", + "required": [ + "providers" + ], + "properties": { + "providers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OidcProviderSummary" + } + } + } + }, + "OidcRoleMappingResponse": { + "type": "object", + "required": [ + "id", + "provider_id", + "priority", + "idp_group", + "role" + ], + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "idp_group": { + "type": "string" + }, + "priority": { + "type": "integer", + "format": "int32" + }, + "provider_id": { + "type": "integer", + "format": "int32" + }, + "role": { + "type": "string" + } + } + }, + "OidcTestConnectionResponse": { + "type": "object", + "required": [ + "success", + "message" + ], + "properties": { + "message": { + "type": "string" + }, + "success": { + "type": "boolean" + } + } + }, + "OnDemandCertAttemptResponse": { + "type": "object", + "description": "A single on-demand HTTP-01 issuance attempt from the append-only\n`on_demand_cert_attempts` audit log. Carries the full forensic detail for one\nattempt; the current cert state lives on the enclosing row's domain fields.\n\nContains no private-key or certificate material \u2014 only audit metadata \u2014 so it\nis safe to return without masking.", + "required": [ + "id", + "hostname", + "trigger", + "outcome", + "created_at" + ], + "properties": { + "acme_request_sent": { + "type": [ + "boolean", + "null" + ], + "description": "Did we reach the Let's Encrypt API?" + }, + "acme_response_status": { + "type": [ + "string", + "null" + ], + "description": "HTTP status or ACME error type returned by Let's Encrypt, when known." + }, + "challenge_served": { + "type": [ + "boolean", + "null" + ], + "description": "Did the proxy serve the `/.well-known/acme-challenge/` request?" + }, + "created_at": { + "type": "integer", + "format": "int64", + "description": "When the attempt was recorded (epoch millis)." + }, + "duration_ms": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "End-to-end issuance duration in milliseconds (0/None for skipped)." + }, + "error_category": { + "type": [ + "string", + "null" + ], + "description": "Coarse error category for UI labelling: `\"rate_limited\"`, `\"dns_failure\"`,\n`\"acme_order_expired\"`, `\"challenge_mismatch\"`, `\"timeout\"`, `\"internal\"`." + }, + "error_chain": { + "type": [ + "string", + "null" + ], + "description": "Full `Display` chain of the error (all `source()` levels), when failed." + }, + "hostname": { + "type": "string", + "description": "SNI hostname that triggered the attempt." + }, + "id": { + "type": "integer", + "format": "int32" + }, + "outcome": { + "type": "string", + "description": "Final outcome: `\"issued\"`, `\"failed\"`, `\"skipped_duplicate\"`,\n`\"skipped_gate\"`, `\"skipped_rate_limit\"`, or `\"skipped_no_route\"`." + }, + "trigger": { + "type": "string", + "description": "What triggered the attempt (always `\"tls_callback\"` today)." + } + } + }, + "OnDemandCertRow": { + "type": "object", + "description": "One row of the on-demand certificates list: the most-recent attempt for a\nhostname plus the current authoritative cert state from its `domains` row.", + "required": [ + "hostname", + "attempt" + ], + "properties": { + "attempt": { + "$ref": "#/components/schemas/OnDemandCertAttemptResponse", + "description": "The audit record for the attempt this row represents (newest first in\nthe list)." + }, + "backoff_until": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "On-demand negative-cache deadline (epoch millis), when in backoff." + }, + "expiration_time": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Certificate expiration (epoch millis), when an active cert exists." + }, + "hostname": { + "type": "string", + "description": "SNI hostname." + }, + "status": { + "type": [ + "string", + "null" + ], + "description": "Current cert lifecycle status from the `domains` row, when one exists:\n`on_demand_pending`, `on_demand_issuing`, `active`, `on_demand_failed`,\netc. `None` when no `domains` row exists yet for this hostname." + } + } + }, + "OnDemandTlsSettings": { + "type": "object", + "description": "On-demand (lazy) HTTP-01 TLS issuance settings (ADR-018).\n\nWhen `enabled`, the proxy's `certificate_callback` triggers ACME HTTP-01\nissuance for allowlisted, STABLE hostnames (per-environment aliases and the\nconsole host) that have no active cert, rather than silently failing the\nhandshake. Ephemeral per-deployment hostnames are NEVER certed (ADR \u00a72).\n\nOff by default \u2014 operators opt in explicitly, except QuickStart (`sslip.io`)\ninstalls where `temps setup` auto-enables it and derives `zone`.", + "properties": { + "deployment_url_mode": { + "type": "string", + "description": "How ephemeral per-deployment hostnames behave when they have no cert\n(they are NEVER certed \u2014 see ADR \u00a72). One of:\n - `\"http\"` (default): serve plain HTTP on :80.\n - `\"redirect_to_env\"`: 308-redirect to the stable per-environment URL,\n which IS certed.", + "default": "http", + "example": "http" + }, + "enabled": { + "type": "boolean", + "description": "Master switch. When `false` (default) the proxy's on-demand cert gate\nrejects every SNI and no issuance is ever triggered.", + "default": false, + "example": false + }, + "hourly_cap": { + "type": "integer", + "format": "int32", + "description": "Global cap on total on-demand issuances per hour across all hostnames\n(ADR \u00a74 Layer 3). The operator's self-imposed safety net, separate from\nthe Let's Encrypt rate limit.", + "default": 10, + "example": 10, + "minimum": 1 + }, + "max_concurrent": { + "type": "integer", + "format": "int32", + "description": "Maximum number of ACME issuance flows allowed to run simultaneously\n(the concurrent-issuance semaphore, ADR \u00a74 Layer 1). Min 1.", + "default": 3, + "example": 3, + "minimum": 1 + }, + "zone": { + "type": [ + "string", + "null" + ], + "description": "Zone suffix for the allowlist gate. A hostname passes the gate only if\nit is a direct subdomain of this zone (e.g. zone `1.2.3.4.sslip.io`\nadmits `myapp.1.2.3.4.sslip.io` but not `deep.sub.1.2.3.4.sslip.io`).\n`None` (default) means \"auto-derive from `external_url`\"; if no zone can\nbe derived the gate rejects all SNI, disabling the feature.", + "default": null, + "example": "1.2.3.4.sslip.io" + } + } + }, + "OpenAiError": { + "type": "object", + "required": [ + "message", + "type" + ], + "properties": { + "code": { + "type": [ + "string", + "null" + ] + }, + "message": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "OpenAiErrorResponse": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "$ref": "#/components/schemas/OpenAiError" + } + } + }, + "OperatingSystemCount": { + "type": "object", + "required": [ + "operating_system", + "count", + "percentage" + ], + "properties": { + "count": { + "type": "integer", + "format": "int64" + }, + "operating_system": { + "type": "string" + }, + "percentage": { + "type": "number", + "format": "double" + } + } + }, + "OperationResultResponse": { + "type": "object", + "required": [ + "operation", + "success", + "message", + "executed_at" + ], + "properties": { + "data": {}, + "executed_at": { + "type": "string", + "format": "date-time", + "example": "2025-10-12T12:15:47.609192Z" + }, + "message": { + "type": "string" + }, + "operation": { + "type": "string" + }, + "success": { + "type": "boolean" + } + } + }, + "OperationResultsResponse": { + "type": "object", + "required": [ + "deployment_id", + "operations" + ], + "properties": { + "deployment_id": { + "type": "string" + }, + "operations": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OperationResultResponse" + } + } + } + }, + "OtelDashboardResponse": { + "type": "object", + "required": [ + "id", + "project_id", + "name", + "layout", + "created_at", + "updated_at" + ], + "properties": { + "created_at": { + "type": "string", + "example": "2025-10-12T12:15:47.609192Z" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "layout": { + "$ref": "#/components/schemas/DashboardLayout" + }, + "name": { + "type": "string" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "updated_at": { + "type": "string", + "example": "2025-10-12T12:15:47.609192Z" + } + } + }, + "OtelDashboardsResponse": { + "type": "object", + "required": [ + "data", + "total" + ], + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OtelDashboardResponse" + } + }, + "total": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + }, + "OtelMetricAlertRuleResponse": { + "type": "object", + "required": [ + "id", + "project_id", + "name", + "metric_name", + "aggregation", + "detection_kind", + "detection_config", + "window_secs", + "for_duration_secs", + "severity", + "enabled", + "last_state", + "label_filters", + "group_by", + "dynamic_alerts", + "max_series", + "grouped_notification_threshold", + "last_dropped_series_count", + "series_states", + "created_at", + "updated_at" + ], + "properties": { + "aggregation": { + "type": "string" + }, + "created_at": { + "type": "string", + "example": "2025-10-12T12:15:47.609192Z" + }, + "detection_config": { + "$ref": "#/components/schemas/DetectionConfig", + "description": "The typed detector definition (discriminated union keyed by `kind`)." + }, + "detection_kind": { + "type": "string", + "description": "Coarse detector discriminator: `static|anomaly|forecast|outlier|auto_watch`." + }, + "dynamic_alerts": { + "type": "boolean", + "description": "Whether per-series (\"dynamic\") alerting is enabled for this rule." + }, + "enabled": { + "type": "boolean" + }, + "firing_series": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FiringSeriesEntry" + }, + "description": "Currently-firing series for a dynamic rule, snapshotted from the evaluator's\nin-memory firing map at read time. Empty for static/aggregate rules or when\nnothing is firing." + }, + "for_duration_secs": { + "type": "integer", + "format": "int32" + }, + "group_by": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Label keys the rule breaks the metric down by. Empty = one aggregate stream." + }, + "grouped_notification_threshold": { + "type": "integer", + "format": "int32", + "description": "Notification-grouping threshold: when more than this many series fire in the\nsame tick, only the first gets chart/AI enrichment (1\u20131000)." + }, + "id": { + "type": "integer", + "format": "int32" + }, + "label_filters": { + "type": "array", + "items": { + "type": "array", + "items": false, + "prefixItems": [ + { + "type": "string" + }, + { + "type": "string" + } + ] + }, + "description": "AND-combined label equality filters applied when evaluating this rule.\nEmpty = no filtering (matches all series)." + }, + "last_dropped_series_count": { + "type": "integer", + "format": "int32", + "description": "Number of series dropped by the cardinality cap on the latest dynamic tick\n(0 when nothing was dropped or for static/aggregate rules). Lets a UI warn\n\"N series were dropped this tick\" without reading server logs." + }, + "last_evaluated_at": { + "type": [ + "string", + "null" + ], + "example": "2025-10-12T12:15:47.609192Z" + }, + "last_state": { + "type": "string", + "description": "One of `ok|firing|unknown`." + }, + "last_value": { + "type": [ + "number", + "null" + ], + "format": "double" + }, + "max_series": { + "type": "integer", + "format": "int32", + "description": "Cardinality cap for dynamic alerting (1\u2013100)." + }, + "metric_name": { + "type": "string" + }, + "name": { + "type": "string" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "series_states": { + "type": "object", + "description": "Full per-series state snapshot persisted after the latest dynamic-rule tick,\nkeyed by the human-readable series label (`endpoint=/checkout`). Empty for\nstatic/aggregate rules. Unlike `firing_series` (a live in-memory snapshot),\nthis is decoded from the persisted `series_states` jsonb column, so an\nexternal consumer that only reads the rule row still sees per-series detail.", + "additionalProperties": { + "$ref": "#/components/schemas/SeriesStateEntry" + }, + "propertyNames": { + "type": "string" + } + }, + "severity": { + "type": "string" + }, + "updated_at": { + "type": "string", + "example": "2025-10-12T12:15:47.609192Z" + }, + "window_secs": { + "type": "integer", + "format": "int32" + } + } + }, + "OtelMetricAlertsResponse": { + "type": "object", + "required": [ + "data", + "total" + ], + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OtelMetricAlertRuleResponse" + } + }, + "total": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + }, + "OtelMetricLabelKeysResponse": { + "type": "object", + "required": [ + "keys" + ], + "properties": { + "keys": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "OtelMetricLabelValuesResponse": { + "type": "object", + "required": [ + "values" + ], + "properties": { + "values": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "OtelMetricNamesResponse": { + "type": "object", + "required": [ + "names" + ], + "properties": { + "names": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "OtelMetricsResponse": { + "type": "object", + "required": [ + "data", + "count" + ], + "properties": { + "count": { + "type": "integer", + "minimum": 0 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MetricBucket" + } + } + } + }, + "OutlierAlgorithm": { + "type": "string", + "description": "Outlier detection algorithm.", + "enum": [ + "dbscan", + "scaled_dbscan", + "mad", + "scaled_mad" + ] + }, + "OutlierParams": { + "type": "object", + "description": "Outlier (cross-series population) detector parameters (stub \u2014 not evaluated).", + "required": [ + "peer_group_key" + ], + "properties": { + "algorithm": { + "$ref": "#/components/schemas/OutlierAlgorithm" + }, + "peer_group_key": { + "type": "string", + "description": "Label key defining the peer population compared across series (e.g. `host`)." + }, + "tolerance": { + "type": "number", + "format": "double", + "description": "Sensitivity; higher tolerates larger spread before flagging." + } + } + }, + "OverprovisioningAssessment": { + "type": "object", + "description": "Requests-vs-capacity-vs-usage assessment", + "required": [ + "verdict", + "explanation" + ], + "properties": { + "cpu_request_inflation_ratio": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Ratio of requested CPU to measured CPU usage (e.g. 40.0 = requests\nreserve 40\u00d7 what the workloads actually use). `None` without metrics." + }, + "cpu_requested_pct": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Requested CPU as % of cluster capacity" + }, + "cpu_utilization_pct": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Measured CPU usage as % of cluster capacity (`None` without metrics)" + }, + "explanation": { + "type": "string", + "description": "Human-readable explanation of the verdict, e.g. \"Cluster capacity is\n8 vCPU but measured usage is 0.3 vCPU (3.7%) \u2014 severely overprovisioned\"" + }, + "memory_request_inflation_ratio": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Ratio of requested memory to measured memory usage" + }, + "memory_requested_pct": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Requested memory as % of cluster capacity" + }, + "memory_utilization_pct": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Measured memory usage as % of cluster capacity (`None` without metrics)" + }, + "verdict": { + "$ref": "#/components/schemas/OverprovisioningVerdict", + "description": "Overall verdict" + } + } + }, + "OverprovisioningVerdict": { + "type": "string", + "description": "Overall overprovisioning verdict", + "enum": [ + "severe", + "moderate", + "reasonable", + "unknown" + ] + }, + "PageActivityBucket": { + "type": "object", + "description": "Time bucket data point for page activity graph", + "required": [ + "timestamp", + "visitors", + "page_views", + "avg_time_seconds" + ], + "properties": { + "avg_time_seconds": { + "type": "number", + "format": "double", + "description": "Average time on page in seconds" + }, + "page_views": { + "type": "integer", + "format": "int64", + "description": "Number of page views in this bucket" + }, + "timestamp": { + "type": "string", + "description": "Timestamp for this bucket (ISO 8601)" + }, + "visitors": { + "type": "integer", + "format": "int64", + "description": "Number of unique visitors in this bucket" + } + } + }, + "PageCountryStats": { + "type": "object", + "description": "Geographic distribution of visitors for a page", + "required": [ + "country", + "visitors", + "page_views", + "percentage" + ], + "properties": { + "country": { + "type": "string", + "description": "Country name" + }, + "country_code": { + "type": [ + "string", + "null" + ], + "description": "ISO country code (2-letter)" + }, + "page_views": { + "type": "integer", + "format": "int64", + "description": "Number of page views from this country" + }, + "percentage": { + "type": "number", + "format": "double", + "description": "Percentage of total visitors" + }, + "visitors": { + "type": "integer", + "format": "int64", + "description": "Number of unique visitors from this country" + } + } + }, + "PageFlowEntry": { + "type": "object", + "description": "A single page with its entry/exit/bounce statistics", + "required": [ + "page_path", + "entry_count", + "exit_count", + "bounce_count", + "total_views", + "entry_rate", + "exit_rate", + "bounce_rate" + ], + "properties": { + "avg_time_on_page": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Average time spent on this page in seconds" + }, + "bounce_count": { + "type": "integer", + "format": "int64", + "description": "Number of times visitors bounced on this page" + }, + "bounce_rate": { + "type": "number", + "format": "double", + "description": "Bounce rate: bounce_count / entry_count (only meaningful for entry pages)" + }, + "entry_count": { + "type": "integer", + "format": "int64", + "description": "Number of times this page was the entry page of a session" + }, + "entry_rate": { + "type": "number", + "format": "double", + "description": "Entry rate: entry_count / total_views" + }, + "exit_count": { + "type": "integer", + "format": "int64", + "description": "Number of times this page was the exit page of a session" + }, + "exit_rate": { + "type": "number", + "format": "double", + "description": "Exit rate: exit_count / total_views" + }, + "page_path": { + "type": "string", + "description": "The page path (e.g. \"/pricing\", \"/docs/getting-started\")" + }, + "total_views": { + "type": "integer", + "format": "int64", + "description": "Total page views for this page" + } + } + }, + "PageFlowQuery": { + "type": "object", + "description": "Query parameters for page flow analytics", + "required": [ + "project_id", + "start_date", + "end_date" + ], + "properties": { + "end_date": { + "type": "string", + "format": "date-time" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "limit": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Maximum number of entry/exit pages to return (default: 20)" + }, + "min_views_for_dropoff": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Minimum views for drop-off analysis (default: 5)" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "start_date": { + "type": "string", + "format": "date-time" + }, + "transitions_limit": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Maximum number of transitions to return (default: 50)" + } + } + }, + "PageFlowResponse": { + "type": "object", + "description": "Complete page flow analytics response", + "required": [ + "top_entry_pages", + "top_exit_pages", + "drop_off_points", + "transitions", + "total_pages", + "total_sessions" + ], + "properties": { + "drop_off_points": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DropOffPoint" + }, + "description": "Top drop-off points (highest exit rates with meaningful traffic)" + }, + "top_entry_pages": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PageFlowEntry" + }, + "description": "Top entry pages (where visitors land), sorted by entry_count DESC" + }, + "top_exit_pages": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PageFlowEntry" + }, + "description": "Top exit pages (where visitors leave), sorted by exit_count DESC" + }, + "total_pages": { + "type": "integer", + "format": "int64", + "description": "Total unique pages seen in the period" + }, + "total_sessions": { + "type": "integer", + "format": "int64", + "description": "Total sessions in the period" + }, + "transitions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PageTransition" + }, + "description": "Page-to-page transitions (most common navigation paths)" + } + } + }, + "PageHourlySessionsQuery": { + "type": "object", + "description": "Query parameters for page hourly sessions endpoint", + "required": [ + "page_path", + "project_id", + "start_time", + "end_time" + ], + "properties": { + "bucket_interval": { + "type": [ + "string", + "null" + ] + }, + "end_time": { + "type": "string", + "format": "date-time" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "page_path": { + "type": "string" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "start_time": { + "type": "string", + "format": "date-time" + } + } + }, + "PageHourlySessionsResponse": { + "type": "object", + "required": [ + "page_path", + "hourly_data", + "total_sessions", + "hours" + ], + "properties": { + "hourly_data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HourlyPageSessions" + } + }, + "hours": { + "type": "integer", + "format": "int32" + }, + "page_path": { + "type": "string" + }, + "total_sessions": { + "type": "integer", + "format": "int64" + } + } + }, + "PagePathDetailQuery": { + "type": "object", + "description": "Query parameters for page path detail analytics", + "required": [ + "page_path", + "project_id", + "start_date", + "end_date" + ], + "properties": { + "bucket_interval": { + "type": [ + "string", + "null" + ], + "description": "Bucket interval for time series: 'hour', 'day', 'week', 'month' (default: auto)" + }, + "end_date": { + "type": "string", + "format": "date-time" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "page_path": { + "type": "string", + "description": "The specific page path to get details for (URL-encoded)" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "start_date": { + "type": "string", + "format": "date-time" + } + } + }, + "PagePathDetailResponse": { + "type": "object", + "description": "Detailed analytics response for a specific page path", + "required": [ + "page_path", + "unique_visitors", + "total_page_views", + "avg_time_on_page", + "bounce_rate", + "entry_rate", + "exit_rate", + "activity_over_time", + "countries", + "referrers", + "bucket_interval" + ], + "properties": { + "activity_over_time": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PageActivityBucket" + }, + "description": "Time series data for activity graph" + }, + "avg_time_on_page": { + "type": "number", + "format": "double", + "description": "Average time on page in seconds" + }, + "bounce_rate": { + "type": "number", + "format": "double", + "description": "Bounce rate percentage (0-100)" + }, + "bucket_interval": { + "type": "string", + "description": "Bucket interval used for time series ('hour', 'day', etc.)" + }, + "countries": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PageCountryStats" + }, + "description": "Geographic distribution of visitors" + }, + "entry_rate": { + "type": "number", + "format": "double", + "description": "Entry rate - percentage of sessions that started on this page" + }, + "exit_rate": { + "type": "number", + "format": "double", + "description": "Exit rate - percentage of sessions that ended on this page" + }, + "page_path": { + "type": "string", + "description": "The page path being analyzed" + }, + "referrers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PageReferrerStats" + }, + "description": "Top referrers to this page" + }, + "total_page_views": { + "type": "integer", + "format": "int64", + "description": "Total page views in the date range" + }, + "unique_visitors": { + "type": "integer", + "format": "int64", + "description": "Total unique visitors to this page in the date range" + } + } + }, + "PagePathInfo": { + "type": "object", + "required": [ + "page_path", + "session_count", + "page_view_count", + "first_seen", + "last_seen" + ], + "properties": { + "avg_time_seconds": { + "type": [ + "number", + "null" + ], + "format": "double" + }, + "first_seen": { + "type": "string" + }, + "last_seen": { + "type": "string" + }, + "page_path": { + "type": "string" + }, + "page_view_count": { + "type": "integer", + "format": "int64" + }, + "session_count": { + "type": "integer", + "format": "int64" + } + } + }, + "PagePathSparkline": { + "type": "object", + "required": [ + "page_path", + "points" + ], + "properties": { + "page_path": { + "type": "string" + }, + "points": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PagePathSparklinePoint" + } + } + } + }, + "PagePathSparklinePoint": { + "type": "object", + "required": [ + "timestamp", + "session_count" + ], + "properties": { + "session_count": { + "type": "integer", + "format": "int64" + }, + "timestamp": { + "type": "string" + } + } + }, + "PagePathVisitorsQuery": { + "type": "object", + "description": "Query parameters for page path visitors", + "required": [ + "page_path", + "project_id", + "start_date", + "end_date" + ], + "properties": { + "end_date": { + "type": "string", + "format": "date-time" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "page": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Page number (1-based, default: 1)", + "minimum": 0 + }, + "page_path": { + "type": "string", + "description": "The specific page path to get visitors for" + }, + "per_page": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Items per page (default: 50, max: 100)", + "minimum": 0 + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "start_date": { + "type": "string", + "format": "date-time" + } + } + }, + "PagePathVisitorsResponse": { + "type": "object", + "description": "Response for page path visitors endpoint", + "required": [ + "page_path", + "total_count", + "page", + "per_page", + "sessions" + ], + "properties": { + "page": { + "type": "integer", + "format": "int64", + "description": "Current page number", + "minimum": 0 + }, + "page_path": { + "type": "string", + "description": "The page path" + }, + "per_page": { + "type": "integer", + "format": "int64", + "description": "Items per page", + "minimum": 0 + }, + "sessions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PageVisitorSession" + }, + "description": "Individual visitor sessions" + }, + "total_count": { + "type": "integer", + "format": "int64", + "description": "Total number of visitor sessions matching the query" + } + } + }, + "PagePathsQuery": { + "type": "object", + "required": [ + "project_id" + ], + "properties": { + "end_date": { + "type": [ + "string", + "null" + ], + "format": "date-time" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "limit": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "start_date": { + "type": [ + "string", + "null" + ], + "format": "date-time" + } + } + }, + "PagePathsResponse": { + "type": "object", + "required": [ + "page_paths", + "total_count" + ], + "properties": { + "page_paths": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PagePathInfo" + } + }, + "total_count": { + "type": "integer", + "minimum": 0 + } + } + }, + "PagePathsSparklineQuery": { + "type": "object", + "description": "Query parameters for batch page paths sparkline endpoint", + "required": [ + "project_id", + "start_time", + "end_time", + "page_paths" + ], + "properties": { + "end_time": { + "type": "string", + "format": "date-time" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "page_paths": { + "type": "string", + "description": "Comma-separated list of page paths" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "start_time": { + "type": "string", + "format": "date-time" + } + } + }, + "PagePathsSparklineResponse": { + "type": "object", + "required": [ + "sparklines" + ], + "properties": { + "sparklines": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PagePathSparkline" + } + } + } + }, + "PageReferrerStats": { + "type": "object", + "description": "Referrer source for the page", + "required": [ + "referrer", + "visits", + "percentage" + ], + "properties": { + "percentage": { + "type": "number", + "format": "double", + "description": "Percentage of total visits" + }, + "referrer": { + "type": "string", + "description": "Referrer URL or domain" + }, + "visits": { + "type": "integer", + "format": "int64", + "description": "Number of visits from this referrer" + } + } + }, + "PageSessionComparison": { + "type": "object", + "required": [ + "page_path", + "date", + "session_count", + "event_count", + "avg_duration_seconds" + ], + "properties": { + "avg_duration_seconds": { + "type": "number", + "format": "double" + }, + "date": { + "type": "string" + }, + "event_count": { + "type": "integer", + "format": "int64" + }, + "page_path": { + "type": "string" + }, + "session_count": { + "type": "integer", + "format": "int64" + } + } + }, + "PageSessionStats": { + "type": "object", + "required": [ + "page_path", + "total_sessions", + "avg_time_seconds", + "min_time_seconds", + "max_time_seconds", + "total_page_views", + "avg_page_views_per_session" + ], + "properties": { + "avg_page_views_per_session": { + "type": "number", + "format": "double" + }, + "avg_time_seconds": { + "type": "number", + "format": "double" + }, + "max_time_seconds": { + "type": "number", + "format": "double" + }, + "min_time_seconds": { + "type": "number", + "format": "double" + }, + "page_path": { + "type": "string" + }, + "total_page_views": { + "type": "integer", + "format": "int64" + }, + "total_sessions": { + "type": "integer", + "format": "int64" + } + } + }, + "PageSessionStatsQuery": { + "type": "object", + "required": [ + "page_path", + "project_id", + "start_date", + "end_date" + ], + "properties": { + "end_date": { + "type": "string", + "format": "date-time" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "page_path": { + "type": "string" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "start_date": { + "type": "string", + "format": "date-time" + } + } + }, + "PageTransition": { + "type": "object", + "description": "A page-to-page transition with count", + "required": [ + "from_page", + "to_page", + "transition_count", + "percentage" + ], + "properties": { + "from_page": { + "type": "string", + "description": "The source page path" + }, + "percentage": { + "type": "number", + "format": "double", + "description": "Percentage of transitions from the source page that go to this destination" + }, + "to_page": { + "type": "string", + "description": "The destination page path" + }, + "transition_count": { + "type": "integer", + "format": "int64", + "description": "Number of times this transition occurred" + } + } + }, + "PageVisit": { + "type": "object", + "required": [ + "path", + "visits" + ], + "properties": { + "path": { + "type": "string" + }, + "visits": { + "type": "integer", + "format": "int64" + } + } + }, + "PageVisitorSession": { + "type": "object", + "description": "Individual visitor session that viewed a specific page", + "required": [ + "visitor_id", + "visitor_uuid", + "viewed_at", + "is_entry", + "is_exit", + "is_bounce" + ], + "properties": { + "browser": { + "type": [ + "string", + "null" + ], + "description": "Browser name" + }, + "city": { + "type": [ + "string", + "null" + ], + "description": "Visitor's city" + }, + "country": { + "type": [ + "string", + "null" + ], + "description": "Visitor's country" + }, + "country_code": { + "type": [ + "string", + "null" + ], + "description": "Visitor's country code" + }, + "device_type": { + "type": [ + "string", + "null" + ], + "description": "Device type (Desktop, Mobile, Tablet)" + }, + "is_bounce": { + "type": "boolean", + "description": "Whether this was a bounce" + }, + "is_entry": { + "type": "boolean", + "description": "Whether this was the entry page for the session" + }, + "is_exit": { + "type": "boolean", + "description": "Whether this was the exit page for the session" + }, + "operating_system": { + "type": [ + "string", + "null" + ], + "description": "Operating system" + }, + "referrer": { + "type": [ + "string", + "null" + ], + "description": "Referrer URL" + }, + "session_id": { + "type": [ + "string", + "null" + ], + "description": "Session ID" + }, + "session_page_number": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Page number in session flow" + }, + "time_on_page": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Time spent on this page in seconds" + }, + "viewed_at": { + "type": "string", + "format": "date-time", + "description": "When the page was viewed" + }, + "visitor_id": { + "type": "integer", + "format": "int32", + "description": "Visitor numeric ID" + }, + "visitor_uuid": { + "type": "string", + "description": "Visitor UUID" + } + } + }, + "PagesComparisonResponse": { + "type": "object", + "required": [ + "comparisons", + "page_paths" + ], + "properties": { + "comparisons": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PageSessionComparison" + } + }, + "page_paths": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "PaginatedEmailsResponse": { + "type": "object", + "required": [ + "data", + "total", + "page", + "page_size" + ], + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EmailResponse" + } + }, + "page": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "page_size": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "total": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + }, + "PaginatedEntitiesResponse": { + "type": "object", + "required": [ + "entities", + "count", + "limit", + "has_more" + ], + "properties": { + "count": { + "type": "integer", + "description": "Number of entities returned", + "minimum": 0 + }, + "entities": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EntityResponse" + }, + "description": "List of entities" + }, + "has_more": { + "type": "boolean", + "description": "Whether there are more entities available" + }, + "limit": { + "type": "integer", + "description": "Limit used for this request", + "minimum": 0 + }, + "next_token": { + "type": [ + "string", + "null" + ], + "description": "Continuation token for next page (S3, etc.)" + }, + "total": { + "type": [ + "integer", + "null" + ], + "description": "Total number of entities (if available)", + "minimum": 0 + } + } + }, + "PaginatedErrorEventsResponse": { + "type": "object", + "required": [ + "data", + "pagination" + ], + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ErrorEventResponse" + } + }, + "pagination": { + "$ref": "#/components/schemas/PaginationMeta" + } + } + }, + "PaginatedErrorGroupsResponse": { + "type": "object", + "required": [ + "data", + "pagination" + ], + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ErrorGroupResponse" + } + }, + "pagination": { + "$ref": "#/components/schemas/PaginationMeta" + } + } + }, + "PaginatedEventsResponse": { + "type": "object", + "required": [ + "events", + "total", + "page", + "page_size" + ], + "properties": { + "events": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TrackingEventResponse" + } + }, + "page": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "page_size": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "total": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + }, + "PaginatedExternalImagesResponse": { + "type": "object", + "required": [ + "data", + "total", + "page", + "page_size" + ], + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ExternalImageResponse" + } + }, + "page": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "page_size": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "total": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + }, + "PaginatedProjectList": { + "type": "object", + "required": [ + "projects", + "total", + "page", + "per_page" + ], + "properties": { + "page": { + "type": "integer", + "format": "int64" + }, + "per_page": { + "type": "integer", + "format": "int64" + }, + "projects": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProjectResponse" + } + }, + "total": { + "type": "integer", + "format": "int64" + } + } + }, + "PaginatedStaticBundlesResponse": { + "type": "object", + "required": [ + "data", + "total", + "page", + "page_size" + ], + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/StaticBundleResponse" + } + }, + "page": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "page_size": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "total": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + }, + "Pagination": { + "type": "object", + "description": "SDK pagination cursor. We use opaque page numbers internally but\nexpose `count`/`next`/`prev` the way `@vercel/sandbox` expects.", + "required": [ + "count" + ], + "properties": { + "count": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "next": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + }, + "prev": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + } + } + }, + "PaginationMeta": { + "type": "object", + "required": [ + "page", + "page_size", + "total_count", + "total_pages" + ], + "properties": { + "page": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "page_size": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "total_count": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "total_pages": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + }, + "PaginationParams": { + "type": "object", + "properties": { + "page": { + "type": "integer", + "format": "int64" + }, + "per_page": { + "type": "integer", + "format": "int64" + } + } + }, + "PasswordProtectionConfig": { + "type": "object", + "description": "Password protection configuration\n\nWhen enabled, the proxy shows an HTML password form before allowing access.\nAfter the user enters the correct password, an HMAC-signed cookie is set\nso subsequent requests pass through without re-entering the password.", + "required": [ + "enabled", + "passwordHash" + ], + "properties": { + "enabled": { + "type": "boolean", + "description": "Whether password protection is enabled" + }, + "passwordHash": { + "type": "string", + "description": "The bcrypt-hashed password (never stored or returned in plaintext)" + } + } + }, + "PatchSettingsRequest": { + "type": "object", + "properties": { + "auto_upgrade": { + "type": [ + "boolean", + "null" + ] + }, + "host_port": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "minimum": 0 + }, + "image": { + "type": [ + "string", + "null" + ] + } + } + }, + "PathVisitors": { + "type": "object", + "required": [ + "name", + "visitors", + "percentage" + ], + "properties": { + "name": { + "type": "string" + }, + "percentage": { + "type": "number", + "format": "double" + }, + "visitors": { + "type": "integer", + "format": "int64" + } + } + }, + "PathVisitorsAnalyticsQuery": { + "type": "object", + "required": [ + "start_date", + "end_date", + "project_id" + ], + "properties": { + "deployment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "end_date": { + "type": "string", + "format": "date-time" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "limit": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "start_date": { + "type": "string", + "format": "date-time" + } + } + }, + "PathVisitorsResponse": { + "type": "object", + "required": [ + "results" + ], + "properties": { + "results": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PathVisitors" + } + } + } + }, + "PeerEntry": { + "type": "object", + "description": "Wire-format peer entry. Matches `temps_network::config::Peer` but\nuses strings on the wire to keep the API stable across underlying\ntype evolution.", + "required": [ + "node_id", + "compute_cidr", + "underlay_address" + ], + "properties": { + "compute_cidr": { + "type": "string", + "description": "Per-node CIDR (e.g. `\"172.20.5.0/24\"`)." + }, + "node_id": { + "type": "string", + "description": "Stable v5 UUID derived from the database node id. Workers use\nthis as the kernel-layer identifier when calling\n`NetworkManager::reconcile_peers`." + }, + "underlay_address": { + "type": "string", + "description": "Address the local node should use to reach this peer over the\nunderlay (private VPC IP for same-DC, public IP for cross-DC)." + } + } + }, + "PeerListResponse": { + "type": "object", + "description": "Response body for `GET /internal/nodes/{node_id}/network/peers`.", + "required": [ + "peers", + "cluster_dns_enabled" + ], + "properties": { + "alloc": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/AllocEntry", + "description": "Caller's own allocation, or `null` if multi-host networking has\nnot been enabled for this node yet." + } + ] + }, + "cluster_dns_enabled": { + "type": "boolean", + "description": "Whether the cluster-DNS resolver is enabled on this control plane\n(`AppSettings.cluster_dns.enabled`). Workers should start their\nper-node resolver and write `overlay_bridge_address` only when this\nis `true`. Always serialized (never `skip_serializing_if`) so older\nand newer version skew degrades to the safe default of `false`." + }, + "peers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PeerEntry" + }, + "description": "All other nodes with a `compute_cidr` set, excluding the caller." + } + } + }, + "PendingActionResponse": { + "type": "object", + "description": "A proposed AI write action awaiting human confirmation.", + "required": [ + "public_id", + "operation_id", + "method", + "summary", + "status", + "step_index", + "params", + "created_at" + ], + "properties": { + "confirmed_at": { + "type": [ + "string", + "null" + ] + }, + "created_at": { + "type": "string" + }, + "error": { + "type": [ + "string", + "null" + ] + }, + "executed_at": { + "type": [ + "string", + "null" + ] + }, + "method": { + "type": "string" + }, + "operation_id": { + "type": "string" + }, + "params": { + "description": "The flat params to be replayed at execute time (shown pre-execution for review)." + }, + "plan_public_id": { + "type": [ + "string", + "null" + ], + "description": "Set when this action is one step of a multi-step plan (chained actions);\nall steps of the plan share this id. Absent for standalone single actions." + }, + "public_id": { + "type": "string" + }, + "required_permission": { + "type": [ + "string", + "null" + ] + }, + "result": {}, + "status": { + "type": "string" + }, + "step_index": { + "type": "integer", + "format": "int32", + "description": "0-based order of this step within its plan (0 for standalone actions)." + }, + "summary": { + "type": "string" + } + } + }, + "PerformanceMetricsQuery": { + "allOf": [ + { + "$ref": "#/components/schemas/SpeedSegmentFilters", + "description": "Segment filters (filter_path, filter_country, filter_region,\nfilter_city, filter_browser, filter_operating_system) \u2014 flattened so\neach remains a top-level query string param." + }, + { + "type": "object", + "required": [ + "start_date", + "end_date", + "project_id" + ], + "properties": { + "deployment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "device_type": { + "type": [ + "string", + "null" + ], + "description": "Device type filter: \"desktop\" or \"mobile\"" + }, + "end_date": { + "type": "string", + "format": "date-time" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "include_bots": { + "type": [ + "boolean", + "null" + ], + "description": "Include crawler/datacenter (bot) samples. Defaults to false \u2014 bots\nare excluded from the read view but always stored at ingest." + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "start_date": { + "type": "string", + "format": "date-time" + } + } + } + ] + }, + "PerformanceMetricsResponse": { + "type": "object", + "properties": { + "cls": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "cls_p75": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "cls_p90": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "cls_p95": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "cls_p99": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "fcp": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "fcp_p75": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "fcp_p90": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "fcp_p95": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "fcp_p99": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "fid": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "fid_p75": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "fid_p90": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "fid_p95": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "fid_p99": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "inp": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "inp_p75": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "inp_p90": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "inp_p95": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "inp_p99": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "lcp": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "lcp_p75": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "lcp_p90": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "lcp_p95": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "lcp_p99": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "ttfb": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "ttfb_p75": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "ttfb_p90": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "ttfb_p95": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "ttfb_p99": { + "type": [ + "number", + "null" + ], + "format": "float" + } + } + }, + "PermissionInfo": { + "type": "object", + "description": "Information about a single permission", + "required": [ + "name", + "description", + "category" + ], + "properties": { + "category": { + "type": "string", + "description": "Category of the permission (e.g., \"Projects\", \"Deployments\")" + }, + "description": { + "type": "string", + "description": "Human-readable description of the permission" + }, + "name": { + "type": "string", + "description": "The permission identifier (e.g., \"projects:read\")" + } + } + }, + "PgUpgradeLogResponse": { + "type": "object", + "required": [ + "log_id", + "content" + ], + "properties": { + "content": { + "type": "string" + }, + "log_id": { + "type": "string" + } + } + }, + "PgUpgradeResponse": { + "type": "object", + "required": [ + "id", + "service_id", + "from_version", + "to_version", + "from_image", + "to_image", + "status", + "phase", + "log_id", + "attempt", + "created_at" + ], + "properties": { + "attempt": { + "type": "integer", + "format": "int32" + }, + "created_at": { + "type": "string" + }, + "error_message": { + "type": [ + "string", + "null" + ] + }, + "finished_at": { + "type": [ + "string", + "null" + ] + }, + "from_image": { + "type": "string" + }, + "from_version": { + "type": "string" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "log_id": { + "type": "string" + }, + "phase": { + "type": "string" + }, + "pre_upgrade_backup_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "rollback_volume_name": { + "type": [ + "string", + "null" + ] + }, + "service_id": { + "type": "integer", + "format": "int32" + }, + "started_at": { + "type": [ + "string", + "null" + ] + }, + "status": { + "type": "string" + }, + "to_image": { + "type": "string" + }, + "to_version": { + "type": "string" + } + } + }, + "PipelineStats": { + "type": "object", + "description": "Internal pipeline statistics for self-observability.", + "required": [ + "metrics_received", + "metrics_stored", + "metrics_dropped", + "spans_received", + "spans_stored", + "spans_dropped", + "logs_received", + "logs_stored_db", + "logs_stored_s3", + "logs_dropped", + "ingest_errors" + ], + "properties": { + "ingest_errors": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "logs_dropped": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "logs_received": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "logs_stored_db": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "logs_stored_s3": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "metrics_dropped": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "metrics_received": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "metrics_stored": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "spans_dropped": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "spans_received": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "spans_stored": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + }, + "PipelineStatsResponse": { + "type": "object", + "required": [ + "stats" + ], + "properties": { + "stats": { + "$ref": "#/components/schemas/PipelineStats" + } + } + }, + "PlanComplexity": { + "type": "string", + "description": "Plan complexity indicator", + "enum": [ + "low", + "medium", + "high" + ] + }, + "PlanMetadata": { + "type": "object", + "description": "Plan metadata", + "required": [ + "generated_at", + "generator_version", + "complexity", + "warnings" + ], + "properties": { + "complexity": { + "$ref": "#/components/schemas/PlanComplexity", + "description": "Estimated complexity (low, medium, high)" + }, + "generated_at": { + "type": "string", + "format": "date-time", + "description": "When the plan was generated" + }, + "generator_version": { + "type": "string", + "description": "Generator (importer) version" + }, + "warnings": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Warnings detected during planning" + } + } + }, + "PlanSourceBackup": { + "type": "object", + "required": [ + "location", + "location_was_resolved", + "format" + ], + "properties": { + "created_at": { + "type": [ + "string", + "null" + ] + }, + "format": { + "type": "string", + "description": "\"walg\", \"pg_dump\", \"unknown\"." + }, + "id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "DB id, absent for orphan (S3-scan) backups." + }, + "location": { + "type": "string", + "description": "Resolved S3 location the orchestrator will actually use." + }, + "location_was_resolved": { + "type": "boolean", + "description": "True when the original row's `s3_location` was empty and we resolved\na location by probing S3. The UI shows this as a warning." + }, + "origin_service_name": { + "type": [ + "string", + "null" + ], + "description": "Service that originally produced the backup, if known." + }, + "size_bytes": { + "type": [ + "integer", + "null" + ], + "format": "int64" + } + } + }, + "PlanTarget": { + "type": "object", + "required": [ + "id", + "name", + "container" + ], + "properties": { + "container": { + "type": "string", + "description": "Expected Docker container name." + }, + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + } + } + }, + "PlatformInfo": { + "type": "object", + "description": "Platform compatibility information", + "required": [ + "os_type", + "architecture", + "platforms" + ], + "properties": { + "architecture": { + "type": "string", + "description": "System architecture (e.g., \"x86_64\", \"aarch64\")" + }, + "os_type": { + "type": "string", + "description": "Operating system type (e.g., \"linux\", \"windows\", \"darwin\")" + }, + "platforms": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of supported platforms in \"os/arch\" format (e.g., [\"linux/amd64\"])" + } + } + }, + "PluginManifest": { + "type": "object", + "description": "The complete plugin manifest \u2014 the handshake contract.", + "required": [ + "name", + "version" + ], + "properties": { + "description": { + "type": [ + "string", + "null" + ], + "description": "Short description of what the plugin does" + }, + "display_name": { + "type": [ + "string", + "null" + ], + "description": "Human-readable display name" + }, + "events": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Platform event types the plugin subscribes to.\n\nWhen specified, Temps will POST matching events to the plugin's\n`/_events` endpoint. Uses dot-notation event names matching the\nwebhook event types (e.g., \"deployment.succeeded\", \"project.created\").\n\nAvailable events:\n- `deployment.created`, `deployment.succeeded`, `deployment.failed`,\n `deployment.cancelled`, `deployment.ready`\n- `project.created`, `project.deleted`\n- `domain.created`, `domain.provisioned`" + }, + "health_path": { + "type": "string", + "description": "Health check endpoint path (relative to plugin root)" + }, + "name": { + "type": "string", + "description": "Unique plugin identifier (kebab-case, e.g., \"backup-manager\")" + }, + "nav": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NavEntry" + }, + "description": "Navigation entries for the UI sidebar" + }, + "requires_db": { + "type": "boolean", + "description": "Whether the plugin needs database access" + }, + "ui": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/UiManifest", + "description": "UI bundle manifest (if the plugin has a UI)" + } + ] + }, + "version": { + "type": "string", + "description": "SemVer version string" + } + } + }, + "PortMapping": { + "type": "object", + "description": "Port mapping", + "required": [ + "container_port", + "protocol", + "is_primary" + ], + "properties": { + "container_port": { + "type": "integer", + "format": "int32", + "description": "Container port", + "minimum": 0 + }, + "host_port": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Host port (optional - can be assigned dynamically)", + "minimum": 0 + }, + "is_primary": { + "type": "boolean", + "description": "Whether this is the primary HTTP port" + }, + "protocol": { + "$ref": "#/components/schemas/Protocol", + "description": "Protocol (tcp, udp)" + } + } + }, + "PostgresWalHealth": { + "type": "object", + "required": [ + "probed_at", + "pg_wal_bytes", + "max_wal_size_bytes", + "archive_mode", + "archive_backlog", + "stale_slots", + "oldest_wal_age_secs", + "warnings" + ], + "properties": { + "archive_backlog": { + "type": "integer", + "format": "int64", + "description": "Number of `archive_status/*.ready` files \u2014 un-shipped WAL segments." + }, + "archive_command": { + "type": [ + "string", + "null" + ], + "description": "The literal `archive_command` setting. May be empty or `/bin/true`\nwhen archiving is effectively disabled despite `archive_mode = on`." + }, + "archive_mode": { + "$ref": "#/components/schemas/ArchiveMode" + }, + "archiver_failed_count": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "archiver_last_failed_at": { + "type": [ + "string", + "null" + ], + "format": "date-time" + }, + "max_wal_size_bytes": { + "type": "integer", + "format": "int64", + "description": "`max_wal_size` setting in bytes (parsed from `pg_settings`)." + }, + "oldest_wal_age_secs": { + "type": "integer", + "format": "int64", + "description": "Age of the oldest WAL file in `pg_wal/` (seconds)." + }, + "pg_wal_bytes": { + "type": "integer", + "format": "int64", + "description": "Total size of files under `pg_wal/`, from `pg_ls_waldir()`." + }, + "probed_at": { + "type": "string", + "format": "date-time", + "description": "When the snapshot was taken." + }, + "stale_slots": { + "type": "array", + "items": { + "$ref": "#/components/schemas/StaleSlot" + } + }, + "warnings": { + "type": "array", + "items": { + "$ref": "#/components/schemas/WalWarning" + }, + "description": "Computed warnings, ordered by severity (critical first)." + } + } + }, + "PresetConfigSchema": { + "oneOf": [ + { + "$ref": "#/components/schemas/DockerfilePresetConfig", + "description": "Configuration for Dockerfile preset" + }, + { + "$ref": "#/components/schemas/DockerComposePresetConfig", + "description": "Configuration for Docker Compose" + }, + { + "$ref": "#/components/schemas/NixpacksPresetConfig", + "description": "Configuration for Nixpacks provider selection and inline build plan" + }, + { + "$ref": "#/components/schemas/StaticPresetConfig", + "description": "Configuration for static site presets (Vite, Next.js, etc.)" + } + ], + "description": "Union type for preset configurations\nUse the appropriate configuration type based on your preset" + }, + "PresetInfo": { + "type": "object", + "description": "Detected preset information", + "required": [ + "path", + "preset", + "preset_label", + "project_type" + ], + "properties": { + "compose_files": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + }, + "description": "Compose file paths found in the repository (only for docker-compose preset)" + }, + "exposed_port": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Default exposed port for this preset" + }, + "icon_url": { + "type": [ + "string", + "null" + ], + "description": "Icon URL for this preset" + }, + "path": { + "type": "string", + "description": "Path where preset was detected (empty for root)" + }, + "preset": { + "type": "string", + "description": "Preset slug (e.g., \"nextjs\", \"fastapi\")" + }, + "preset_label": { + "type": "string", + "description": "Human-readable preset label" + }, + "project_type": { + "type": "string", + "description": "Project type (e.g., \"frontend\", \"backend\", \"fullstack\")" + } + } + }, + "PresetResponse": { + "type": "object", + "required": [ + "slug", + "label", + "icon_url", + "project_type", + "description" + ], + "properties": { + "default_port": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Default port the application listens on (None for static sites)", + "example": 3000, + "minimum": 0 + }, + "description": { + "type": "string", + "description": "Description of what this preset does" + }, + "icon_url": { + "type": "string", + "description": "Icon URL for the preset" + }, + "label": { + "type": "string", + "description": "Display name/label for the preset" + }, + "project_type": { + "type": "string", + "description": "Project type (server or static)" + }, + "slug": { + "type": "string", + "description": "Unique identifier slug for the preset" + } + } + }, + "PreviewGatewaySettings": { + "type": "object", + "description": "Workspace preview gateway settings.\n\nThe preview gateway is a single shared Docker container that lives on the\n`temps-sandbox-net` network and routes requests to workspace sandbox dev\nservers based on the `Host` header (`ws--.`).\n`temps serve` reconciles this container on startup; these settings let an\noperator override the image, host port, and auto-upgrade behavior.", + "properties": { + "auto_upgrade": { + "type": "boolean", + "description": "When true (default), the supervisor will pull and apply the image\npinned in the Temps binary on every startup. When false, the\ncurrently-running image is left alone \u2014 operators upgrade manually\nfrom the settings UI.", + "default": true, + "example": true + }, + "host_port": { + "type": "integer", + "format": "int32", + "description": "Host port to publish the gateway on (always bound to 127.0.0.1).\nPingora forwards `ws-*` traffic to this port after authenticating.", + "default": 8090, + "example": 8090, + "minimum": 0 + }, + "image": { + "type": "string", + "description": "Docker image reference for the gateway. Pinned per Temps release.\nOperators can override this to test a custom build.", + "default": "ghcr.io/gotempsh/temps-preview-gateway:latest", + "example": "ghcr.io/gotempsh/temps-preview-gateway:latest" + }, + "shared_secret": { + "type": "string", + "description": "Shared secret the host-side Pingora sends on every forwarded preview\nrequest via `X-Temps-Preview-Token`; the gateway rejects requests\nwithout it. Auto-generated on first boot, persisted in DB so the\nsecret is stable across `temps serve` restarts regardless of cwd,\n`TEMPS_DATA_DIR`, or data-dir changes. MUST be masked (`***`) in any\nAPI response \u2014 never expose it over HTTP.", + "default": "", + "example": "" + } + } + }, + "PreviewGatewaySettingsMasked": { + "type": "object", + "description": "Preview gateway settings with `shared_secret` elided.", + "required": [ + "image", + "host_port", + "auto_upgrade", + "shared_secret_set" + ], + "properties": { + "auto_upgrade": { + "type": "boolean" + }, + "host_port": { + "type": "integer", + "format": "int32", + "minimum": 0 + }, + "image": { + "type": "string" + }, + "shared_secret_set": { + "type": "boolean" + } + } + }, + "PreviewGatewaySettingsResponse": { + "type": "object", + "required": [ + "image", + "host_port", + "auto_upgrade", + "default_image", + "default_host_port" + ], + "properties": { + "auto_upgrade": { + "type": "boolean" + }, + "default_host_port": { + "type": "integer", + "format": "int32", + "description": "The compile-time default host port.", + "minimum": 0 + }, + "default_image": { + "type": "string", + "description": "The compile-time default image \u2014 exposed so the UI can offer a\n\"Reset to default\" link without round-tripping." + }, + "host_port": { + "type": "integer", + "format": "int32", + "minimum": 0 + }, + "image": { + "type": "string" + } + } + }, + "PreviewShareLinkBody": { + "type": "object", + "description": "Request body for minting a preview share link.", + "required": [ + "port" + ], + "properties": { + "path": { + "type": [ + "string", + "null" + ], + "description": "Path the recipient lands on. Must be same-origin (start with a single\n`/`); anything else is replaced with `/` so a share link can never be\nturned into an open redirect." + }, + "port": { + "type": "integer", + "format": "int32", + "description": "Port inside the sandbox the preview serves on.", + "minimum": 0 + }, + "ttl_seconds": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "How long the link stays usable, in seconds. Clamped to 24 hours.\nDefaults to one hour \u2014 long enough to send to a reviewer, short enough\nthat a link pasted in a ticket does not stay live indefinitely.", + "minimum": 0 + } + } + }, + "PreviewShareLinkResponse": { + "type": "object", + "required": [ + "url", + "expires_at" + ], + "properties": { + "expires_at": { + "type": "integer", + "format": "int64", + "description": "Unix seconds after which the link stops working.", + "minimum": 0 + }, + "url": { + "type": "string", + "description": "The full link. Its fragment contains the grant and must be treated as a\ncredential; URL fragments are not sent to servers or in Referer headers." + } + } + }, + "PricingResponse": { + "type": "object", + "required": [ + "models" + ], + "properties": { + "models": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ModelPricing" + } + } + } + }, + "ProblemDetails": { + "type": "object", + "description": "Representation of a Problem error to return to the client.\nFollows RFC 7807 - Problem Details for HTTP APIs", + "required": [ + "title", + "extensions" + ], + "properties": { + "detail": { + "type": [ + "string", + "null" + ], + "description": "A human-readable explanation specific to this occurrence of the problem", + "example": "The server encountered an unexpected condition" + }, + "extensions": { + "type": "object", + "description": "Additional properties of the problem", + "additionalProperties": true + }, + "instance": { + "type": [ + "string", + "null" + ], + "description": "A URI reference that identifies the specific occurrence of the problem", + "example": "/account/12345/msgs/abc" + }, + "title": { + "type": "string", + "description": "A short, human-readable summary of the problem type", + "example": "Internal Server Error" + }, + "type": { + "type": [ + "string", + "null" + ], + "description": "A URI reference that identifies the problem type", + "example": "https://example.com/probs/out-of-memory" + } + }, + "example": { + "type": "https://example.com/probs/out-of-memory", + "title": "Internal Server Error", + "detail": "The server encountered an unexpected condition", + "instance": "/account/12345/msgs/abc", + "additional_info": "Custom field with additional details" + } + }, + "ProjectAccessResponse": { + "type": "object", + "required": [ + "id", + "project_id", + "team_id", + "role", + "granted_by", + "created_at", + "updated_at" + ], + "properties": { + "created_at": { + "type": "string", + "format": "date-time", + "example": "2026-07-30T12:15:47.609192Z" + }, + "granted_by": { + "type": "integer", + "format": "int32" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "role": { + "$ref": "#/components/schemas/TeamRole" + }, + "team_id": { + "type": "integer", + "format": "int32" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "example": "2026-07-30T12:15:47.609192Z" + } + } + }, + "ProjectConfiguration": { + "type": "object", + "description": "Project-level configuration", + "required": [ + "name", + "slug", + "project_type", + "is_web_app" + ], + "properties": { + "is_web_app": { + "type": "boolean", + "description": "Whether this is a web application" + }, + "name": { + "type": "string", + "description": "Proposed project name" + }, + "project_type": { + "$ref": "#/components/schemas/ProjectType", + "description": "Project type" + }, + "slug": { + "type": "string", + "description": "Proposed slug (URL-safe identifier)" + } + } + }, + "ProjectDSNResponse": { + "type": "object", + "required": [ + "id", + "project_id", + "name", + "public_key", + "dsn", + "created_at", + "is_active", + "event_count" + ], + "properties": { + "created_at": { + "type": "string" + }, + "deployment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "dsn": { + "type": "string" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "event_count": { + "type": "integer", + "format": "int64" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "is_active": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "public_key": { + "type": "string" + } + } + }, + "ProjectDashboardAnalytics": { + "type": "object", + "description": "Analytics data for a single project in the dashboard batch response", + "required": [ + "project_id", + "unique_visitors", + "previous_unique_visitors", + "hourly_visits" + ], + "properties": { + "hourly_visits": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EventTimeline" + }, + "description": "Hourly sparkline data points" + }, + "previous_unique_visitors": { + "type": "integer", + "format": "int64", + "description": "Unique visitor count in the previous period (same duration, shifted back)" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "trend_percentage": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Percentage change from previous period (positive = growth, negative = decline)\nNull when previous period had zero visitors (no baseline to compare)" + }, + "unique_visitors": { + "type": "integer", + "format": "int64", + "description": "Unique visitor count in the current time range" + } + } + }, + "ProjectHealthSummary": { + "type": "object", + "description": "Health summary for a single project (last 1 hour)", + "required": [ + "project_id", + "total_requests", + "total_errors", + "avg_response_time_ms", + "error_rate", + "status" + ], + "properties": { + "avg_response_time_ms": { + "type": "number", + "format": "double", + "description": "Average response time in ms" + }, + "error_rate": { + "type": "number", + "format": "double", + "description": "Error rate as a percentage (0-100)" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "status": { + "type": "string", + "description": "Health status: \"healthy\", \"degraded\", \"down\", \"unknown\"" + }, + "total_errors": { + "type": "integer", + "format": "int64", + "description": "Total server errors (status >= 500) in the period" + }, + "total_requests": { + "type": "integer", + "format": "int64", + "description": "Total requests in the period" + } + } + }, + "ProjectInfo": { + "type": "object", + "required": [ + "id", + "slug", + "created_at" + ], + "properties": { + "created_at": { + "type": "string", + "example": "2025-10-12T12:15:47.609192Z" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "slug": { + "type": "string" + } + } + }, + "ProjectMonitorHealth": { + "type": "object", + "description": "Health summary for a single project based on its production monitors", + "required": [ + "project_id", + "status" + ], + "properties": { + "project_id": { + "type": "integer", + "format": "int32" + }, + "status": { + "type": "string", + "description": "Overall status: \"operational\", \"degraded\", \"down\", or \"no_monitors\"" + } + } + }, + "ProjectPresetResponse": { + "type": "object", + "required": [ + "path", + "preset", + "presetLabel", + "projectType" + ], + "properties": { + "composeFiles": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + }, + "description": "Compose file paths found in the repository (only for docker-compose preset)" + }, + "exposedPort": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Default exposed port for this preset (e.g., 3000 for Next.js, 8000 for FastAPI)" + }, + "iconUrl": { + "type": [ + "string", + "null" + ], + "description": "Icon URL for the preset" + }, + "path": { + "type": "string" + }, + "preset": { + "type": "string" + }, + "presetLabel": { + "type": "string" + }, + "projectType": { + "type": "string", + "description": "Project type category (e.g., \"frontend\", \"backend\", \"fullstack\")" + } + } + }, + "ProjectQuery": { + "type": "object", + "required": [ + "project_id" + ], + "properties": { + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "project_id": { + "type": "integer", + "format": "int32" + } + } + }, + "ProjectRef": { + "type": "object", + "description": "A lightweight project descriptor included in `UnifiedTrace`.", + "required": [ + "project_id", + "project_name", + "project_slug" + ], + "properties": { + "project_id": { + "type": "integer", + "format": "int32" + }, + "project_name": { + "type": "string" + }, + "project_slug": { + "type": "string", + "description": "URL slug used to link a span back into its owning project's trace view." + } + } + }, + "ProjectResponse": { + "type": "object", + "required": [ + "id", + "slug", + "name", + "directory", + "main_branch", + "created_at", + "updated_at", + "deployment_config", + "attack_mode", + "ai_write_actions_enabled", + "error_source_context_enabled", + "enable_preview_environments", + "preview_envs_on_demand", + "preview_envs_idle_timeout_seconds", + "preview_envs_wake_timeout_seconds", + "source_type", + "cross_project_trace_sharing" + ], + "properties": { + "ai_alert_summaries_enabled": { + "type": [ + "boolean", + "null" + ], + "description": "Opt-in to AI summarization of metric alert notifications (NULL/false = off)." + }, + "ai_debug_chat_enabled": { + "type": [ + "boolean", + "null" + ], + "description": "Opt-in to AI debugging chat, e.g. on deployment failures (NULL/false = off)." + }, + "ai_write_actions_enabled": { + "type": "boolean", + "description": "Opt-in to AI propose-then-confirm write capability (false = off)." + }, + "attack_mode": { + "type": "boolean", + "description": "Attack mode - when enabled, requires CAPTCHA verification for all project environments" + }, + "created_at": { + "type": "integer", + "format": "int64" + }, + "cross_project_trace_sharing": { + "type": "boolean", + "description": "ADR-027 Phase 3 opt-out: when false, this project's traces are suppressed\nfrom cross-project discovery results. Default true (consistent with the\nOSS global-observability model where any OtelRead holder can query any\nproject's telemetry)." + }, + "deployment_config": { + "$ref": "#/components/schemas/DeploymentConfig", + "description": "Deployment configuration (resources, autoscaling, features)" + }, + "directory": { + "type": "string" + }, + "enable_preview_environments": { + "type": "boolean", + "description": "Enable automatic preview environment creation for each branch" + }, + "error_source_context_enabled": { + "type": "boolean", + "description": "Opt-in to native error-tracking source context (false = off). When on,\nTemps stores uploaded source files and shows source code in stack traces." + }, + "error_source_root": { + "type": [ + "string", + "null" + ], + "description": "Where auto-capture reads source from (relative to the checkout). Null =\nthe deployment's Docker build context." + }, + "git_provider_connection_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "git_url": { + "type": [ + "string", + "null" + ], + "description": "Git clone URL for the repository (used for public repos without a provider connection)" + }, + "gitlab_webhook_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "GitLab webhook ID installed on the connected repository.\n`null` when no GitLab webhook is installed (not connected to GitLab,\nor webhook was removed / never created).", + "example": 42 + }, + "id": { + "type": "integer", + "format": "int32" + }, + "last_deployment": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "main_branch": { + "type": "string" + }, + "name": { + "type": "string" + }, + "preset": { + "type": [ + "string", + "null" + ] + }, + "preset_config": { + "description": "Preset-specific configuration (Dockerfile path, build context, etc.)" + }, + "preview_envs_idle_timeout_seconds": { + "type": "integer", + "format": "int32", + "description": "Idle timeout (seconds) for on-demand preview environments." + }, + "preview_envs_on_demand": { + "type": "boolean", + "description": "When true, newly-created preview environments default to on-demand mode\n(containers stop after the configured idle timeout to save resources)." + }, + "preview_envs_wake_timeout_seconds": { + "type": "integer", + "format": "int32", + "description": "Wake timeout (seconds) for on-demand preview environments." + }, + "repo_name": { + "type": [ + "string", + "null" + ] + }, + "repo_owner": { + "type": [ + "string", + "null" + ] + }, + "slug": { + "type": "string" + }, + "source_type": { + "$ref": "#/components/schemas/SourceType", + "description": "Source type for deployments (git, docker_image, or static_files)" + }, + "updated_at": { + "type": "integer", + "format": "int64" + } + } + }, + "ProjectSecretEnvironmentInfo": { + "type": "object", + "required": [ + "id", + "name", + "main_url" + ], + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "main_url": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "ProjectSecretResponse": { + "type": "object", + "description": "Project secret metadata. There is deliberately no `value` field \u2014 secret\nplaintext is never returned after creation. Callers that need the value\nmust read it from the mounted file inside the container.", + "required": [ + "id", + "project_id", + "key", + "include_in_preview", + "created_at", + "updated_at", + "environments" + ], + "properties": { + "created_at": { + "type": "integer", + "format": "int64" + }, + "environments": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProjectSecretEnvironmentInfo" + } + }, + "id": { + "type": "integer", + "format": "int32" + }, + "include_in_preview": { + "type": "boolean" + }, + "key": { + "type": "string" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "updated_at": { + "type": "integer", + "format": "int64" + } + } + }, + "ProjectServiceInfo": { + "type": "object", + "required": [ + "id", + "project", + "service" + ], + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "project": { + "$ref": "#/components/schemas/ProjectInfo" + }, + "service": { + "$ref": "#/components/schemas/ExternalServiceInfo" + } + } + }, + "ProjectStatisticsResponse": { + "type": "object", + "required": [ + "total_count" + ], + "properties": { + "total_count": { + "type": "integer", + "format": "int64" + } + } + }, + "ProjectStatsBreakdown": { + "type": "object", + "required": [ + "project_id", + "unique_visitors", + "total_visits", + "total_page_views", + "bounce_rate", + "engagement_rate" + ], + "properties": { + "bounce_rate": { + "type": "number", + "format": "double" + }, + "engagement_rate": { + "type": "number", + "format": "double" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "project_name": { + "type": [ + "string", + "null" + ] + }, + "total_page_views": { + "type": "integer", + "format": "int64" + }, + "total_visits": { + "type": "integer", + "format": "int64" + }, + "unique_visitors": { + "type": "integer", + "format": "int64" + } + } + }, + "ProjectType": { + "type": "string", + "description": "Project type enumeration", + "enum": [ + "static", + "docker", + "buildpack", + "git" + ] + }, + "ProjectUsageInfoResponse": { + "type": "object", + "required": [ + "id", + "name", + "slug", + "connection_id", + "connection_name" + ], + "properties": { + "connection_id": { + "type": "integer", + "format": "int32" + }, + "connection_name": { + "type": "string" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "slug": { + "type": "string" + } + } + }, + "ProjectsHealthResponse": { + "type": "object", + "description": "Batch health summary response", + "required": [ + "projects" + ], + "properties": { + "projects": { + "type": "object", + "description": "Health summaries keyed by project ID", + "additionalProperties": { + "$ref": "#/components/schemas/ProjectHealthSummary" + }, + "propertyNames": { + "type": "string" + } + } + } + }, + "ProjectsMonitorHealthResponse": { + "type": "object", + "description": "Batch response for projects health", + "required": [ + "projects" + ], + "properties": { + "projects": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/ProjectMonitorHealth" + }, + "propertyNames": { + "type": "string" + } + } + } + }, + "PromoteDeploymentRequest": { + "type": "object", + "required": [ + "target_environment_id" + ], + "properties": { + "target_environment_id": { + "type": "integer", + "format": "int32", + "description": "Target environment ID to promote the deployment to" + } + } + }, + "PropertyBreakdownItem": { + "type": "object", + "required": [ + "value", + "count", + "percentage" + ], + "properties": { + "count": { + "type": "integer", + "format": "int64" + }, + "percentage": { + "type": "number", + "format": "double" + }, + "value": { + "type": "string" + } + } + }, + "PropertyBreakdownQuery": { + "type": "object", + "description": "Query parameters for property breakdown (group by column)", + "required": [ + "start_date", + "end_date", + "group_by" + ], + "properties": { + "aggregation_level": { + "$ref": "#/components/schemas/AggregationLevel", + "description": "Aggregation level" + }, + "deployment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Optional deployment filter" + }, + "end_date": { + "type": "string", + "format": "date-time", + "description": "End date for the query range" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Optional environment filter" + }, + "event_name": { + "type": [ + "string", + "null" + ], + "description": "Optional event name filter (e.g., \"page_view\", \"click\")" + }, + "filter_browser": { + "type": [ + "string", + "null" + ], + "description": "Filter by browser name (for browser version drill-downs)" + }, + "filter_channel": { + "type": [ + "string", + "null" + ], + "description": "Filter by channel name (for channel -> referrer drill-downs)" + }, + "filter_country": { + "type": [ + "string", + "null" + ], + "description": "Filter by country (for region/city drill-downs). Requires geolocation join." + }, + "filter_os": { + "type": [ + "string", + "null" + ], + "description": "Filter by operating system name (for OS version drill-downs)" + }, + "filter_referrer": { + "type": [ + "string", + "null" + ], + "description": "Filter by referrer hostname (for referrer -> pages drill-downs)" + }, + "filter_region": { + "type": [ + "string", + "null" + ], + "description": "Filter by region (for city drill-downs). Requires geolocation join." + }, + "group_by": { + "$ref": "#/components/schemas/PropertyColumn", + "description": "Property column to group by" + }, + "limit": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Maximum number of results to return (default: 20, max: 100)" + }, + "start_date": { + "type": "string", + "format": "date-time", + "description": "Start date for the query range" + } + } + }, + "PropertyBreakdownResponse": { + "type": "object", + "required": [ + "property", + "items", + "total" + ], + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PropertyBreakdownItem" + } + }, + "property": { + "type": "string" + }, + "total": { + "type": "integer", + "format": "int64" + } + } + }, + "PropertyColumn": { + "type": "string", + "enum": [ + "channel", + "device_type", + "browser", + "browser_version", + "operating_system", + "operating_system_version", + "utm_source", + "utm_medium", + "utm_campaign", + "utm_term", + "utm_content", + "referrer_hostname", + "language", + "event_type", + "event_name", + "page_path", + "pathname", + "country", + "region", + "city" + ] + }, + "PropertyTimelineItem": { + "type": "object", + "required": [ + "timestamp", + "value", + "count" + ], + "properties": { + "count": { + "type": "integer", + "format": "int64" + }, + "timestamp": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, + "PropertyTimelineQuery": { + "type": "object", + "description": "Query parameters for property timeline (group by column over time)", + "required": [ + "start_date", + "end_date", + "group_by" + ], + "properties": { + "aggregation_level": { + "$ref": "#/components/schemas/AggregationLevel", + "description": "Aggregation level" + }, + "bucket_size": { + "type": [ + "string", + "null" + ], + "description": "Time bucket size: \"hour\", \"day\", \"week\", \"month\" (default: auto-detect)" + }, + "deployment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Optional deployment filter" + }, + "end_date": { + "type": "string", + "format": "date-time", + "description": "End date for the query range" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Optional environment filter" + }, + "event_name": { + "type": [ + "string", + "null" + ], + "description": "Optional event name filter" + }, + "group_by": { + "$ref": "#/components/schemas/PropertyColumn", + "description": "Property column to group by" + }, + "start_date": { + "type": "string", + "format": "date-time", + "description": "Start date for the query range" + } + } + }, + "PropertyTimelineResponse": { + "type": "object", + "required": [ + "property", + "bucket_size", + "items" + ], + "properties": { + "bucket_size": { + "type": "string" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PropertyTimelineItem" + } + }, + "property": { + "type": "string" + } + } + }, + "Protocol": { + "type": "string", + "description": "Network protocol", + "enum": [ + "tcp", + "udp" + ] + }, + "ProviderCatalogDto": { + "type": "object", + "description": "One catalog entry rendered for the settings UI.", + "required": [ + "id", + "name", + "install_command", + "auth_command", + "auth_flavors", + "models", + "credential_saved", + "supports_max_turns" + ], + "properties": { + "auth_command": { + "type": "string" + }, + "auth_flavors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AuthFlavorDto" + } + }, + "credential_saved": { + "type": "boolean", + "description": "True when a credential is currently saved for this provider in the\nsettings JSON. Lets the UI render \"Configured\" badges without the\nfrontend having to inspect the encrypted blob." + }, + "current_auth_type": { + "type": [ + "string", + "null" + ], + "description": "Currently saved auth flavor id (when `credential_saved` is true).\n`None` when no credential is saved yet." + }, + "default_model": { + "type": [ + "string", + "null" + ], + "description": "Currently saved default model id for this provider, if one was\npicked. `None` means \"use the CLI's own default\" \u2014 the UI renders\nthat as \"Use provider default\"." + }, + "id": { + "type": "string" + }, + "install_command": { + "type": "string" + }, + "max_turns_analysis": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Default max turns for the autofixer analysis phase. `None` = built-in\ndefault (10). Only enforced for CLIs with a turn flag (Claude Code)." + }, + "max_turns_feedback": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Default max turns for autofixer feedback rounds. `None` = built-in\ndefault (10)." + }, + "max_turns_fix": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Default max turns for the autofixer fix phase. `None` = built-in\ndefault (20)." + }, + "models": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Model ids this provider accepts, in display order. The first entry is\nthe recommended default. Empty when the provider doesn't expose model\nselection (e.g. OpenCode), which the UI uses to hide the dropdown." + }, + "name": { + "type": "string" + }, + "supports_max_turns": { + "type": "boolean", + "description": "True when this provider's CLI supports enforcing a turn cap. False\nfor Codex/OpenCode, which run to completion \u2014 the UI labels their\nmax-turns inputs accordingly." + } + } + }, + "ProviderCatalogResponse": { + "type": "object", + "required": [ + "default_provider", + "providers" + ], + "properties": { + "default_provider": { + "type": "string", + "description": "Active provider id from `agent_sandbox.default_provider`. The settings\nUI uses this to highlight which card is the active one." + }, + "providers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProviderCatalogDto" + } + } + } + }, + "ProviderConfig": { + "oneOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/StripeConfig" + }, + { + "type": "object", + "required": [ + "provider" + ], + "properties": { + "provider": { + "type": "string", + "enum": [ + "stripe" + ] + } + } + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/LemonSqueezyConfig" + }, + { + "type": "object", + "required": [ + "provider" + ], + "properties": { + "provider": { + "type": "string", + "enum": [ + "lemon_squeezy" + ] + } + } + } + ] + } + ], + "description": "Provider-specific integration settings persisted in\n`revenue_integrations.config`.\n\nThe tag is the lowercase provider name, so adding a new provider\nmeans adding a new variant and the existing rows are untouched.\nOld rows (pre-config) and rows with `NULL` config are treated as\n\"accept all events, no filtering\" via [`ProviderConfig::default_for`]." + }, + "ProviderConfigMasked": { + "type": "object", + "required": [ + "auth_type", + "credential_saved", + "extra" + ], + "properties": { + "auth_type": { + "type": "string" + }, + "credential_saved": { + "type": "boolean", + "description": "True if a credential is stored for this provider. The encrypted blob\nis never returned over HTTP." + }, + "default_model": { + "type": [ + "string", + "null" + ] + }, + "extra": {} + } + }, + "ProviderDeletionCheckResponse": { + "type": "object", + "required": [ + "can_delete", + "projects_in_use", + "message" + ], + "properties": { + "can_delete": { + "type": "boolean" + }, + "message": { + "type": "string" + }, + "projects_in_use": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProjectUsageInfoResponse" + } + } + } + }, + "ProviderDescriptor": { + "type": "object", + "required": [ + "name", + "display_name", + "recommended_events" + ], + "properties": { + "display_name": { + "type": "string" + }, + "name": { + "type": "string" + }, + "recommended_events": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "ProviderKeyResponse": { + "type": "object", + "required": [ + "id", + "provider", + "display_name", + "api_key_masked", + "is_active", + "created_at", + "updated_at" + ], + "properties": { + "api_key_masked": { + "type": "string", + "description": "Masked API key (only last 4 chars visible)" + }, + "base_url": { + "type": [ + "string", + "null" + ] + }, + "created_at": { + "type": "string" + }, + "default_model": { + "type": [ + "string", + "null" + ], + "description": "Model id this provider serves (NULL \u2192 per-provider default)." + }, + "display_name": { + "type": "string" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "is_active": { + "type": "boolean" + }, + "provider": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + } + }, + "ProviderMetadata": { + "type": "object", + "required": [ + "service_type", + "display_name", + "description", + "icon_url", + "color" + ], + "properties": { + "color": { + "type": "string", + "example": "#336791" + }, + "description": { + "type": "string", + "example": "Relational database management system" + }, + "display_name": { + "type": "string", + "example": "PostgreSQL" + }, + "icon_url": { + "type": "string", + "example": "https://cdn.simpleicons.org/postgresql" + }, + "service_type": { + "$ref": "#/components/schemas/ServiceTypeRoute" + } + } + }, + "ProviderResponse": { + "type": "object", + "required": [ + "id", + "name", + "provider_type", + "auth_method", + "is_active", + "is_default", + "created_at", + "updated_at" + ], + "properties": { + "auth_method": { + "type": "string" + }, + "base_url": { + "type": [ + "string", + "null" + ] + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "is_active": { + "type": "boolean" + }, + "is_default": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "provider_type": { + "type": "string" + }, + "updated_at": { + "type": "string", + "format": "date-time" + } + } + }, + "ProviderUsage": { + "type": "object", + "required": [ + "provider", + "request_count", + "input_tokens", + "output_tokens", + "avg_latency_ms", + "error_count" + ], + "properties": { + "avg_latency_ms": { + "type": "number", + "format": "double" + }, + "error_count": { + "type": "integer", + "format": "int64" + }, + "input_tokens": { + "type": "integer", + "format": "int64" + }, + "output_tokens": { + "type": "integer", + "format": "int64" + }, + "provider": { + "type": "string" + }, + "request_count": { + "type": "integer", + "format": "int64" + } + } + }, + "ProvisionResponse": { + "oneOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/DomainError" + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "error" + ] + } + } + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/DomainResponse" + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "complete" + ] + } + } + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/DomainChallengeResponse" + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "pending" + ] + } + } + } + ] + } + ] + }, + "ProxyLogResponse": { + "type": "object", + "description": "Response model for proxy logs", + "required": [ + "id", + "timestamp", + "method", + "path", + "host", + "status_code", + "request_source", + "is_system_request", + "routing_status", + "request_id" + ], + "properties": { + "bot_name": { + "type": [ + "string", + "null" + ] + }, + "browser": { + "type": [ + "string", + "null" + ] + }, + "browser_version": { + "type": [ + "string", + "null" + ] + }, + "cache_status": { + "type": [ + "string", + "null" + ] + }, + "client_ip": { + "type": [ + "string", + "null" + ] + }, + "container_id": { + "type": [ + "string", + "null" + ] + }, + "deployment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "device_type": { + "type": [ + "string", + "null" + ] + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "error_message": { + "type": [ + "string", + "null" + ] + }, + "host": { + "type": "string" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "ip_geolocation_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "is_bot": { + "type": [ + "boolean", + "null" + ] + }, + "is_system_request": { + "type": "boolean" + }, + "method": { + "type": "string" + }, + "operating_system": { + "type": [ + "string", + "null" + ] + }, + "path": { + "type": "string" + }, + "project_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "query_string": { + "type": [ + "string", + "null" + ] + }, + "referrer": { + "type": [ + "string", + "null" + ] + }, + "request_id": { + "type": "string" + }, + "request_size_bytes": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "request_source": { + "type": "string" + }, + "response_size_bytes": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "response_time_ms": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "routing_status": { + "type": "string" + }, + "session_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "status_code": { + "type": "integer", + "format": "int32" + }, + "timestamp": { + "type": "string" + }, + "upstream_host": { + "type": [ + "string", + "null" + ] + }, + "user_agent": { + "type": [ + "string", + "null" + ] + }, + "visitor_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + } + }, + "ProxyLogsPaginatedResponse": { + "type": "object", + "description": "Paginated response for proxy logs", + "required": [ + "logs", + "total", + "page", + "page_size", + "total_pages" + ], + "properties": { + "logs": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProxyLogResponse" + } + }, + "page": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "page_size": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "total": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "total_pages": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + }, + "PublicHostnameStrategy": { + "type": "string", + "description": "Public hostname generation mode for Temps-managed preview routes.\n\nThe mode is stored per managed domain (`dns_managed_domains.generated_hostname_mode`)\nrather than globally, so a provider such as Cloudflare can offer the flat layout\nrequired by its Universal SSL wildcard cert without changing every domain's behaviour.", + "enum": [ + "standard", + "flat" + ] + }, + "PublicPresetResponse": { + "type": "object", + "description": "Response for preset detection", + "required": [ + "branch", + "presets" + ], + "properties": { + "branch": { + "type": "string", + "description": "Branch name where presets were detected" + }, + "presets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PresetInfo" + }, + "description": "List of detected presets" + } + } + }, + "PublicRepositoryInfo": { + "type": "object", + "description": "Public repository information", + "required": [ + "owner", + "name", + "full_name", + "default_branch", + "stars", + "forks" + ], + "properties": { + "default_branch": { + "type": "string", + "description": "Default branch name" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Repository description" + }, + "forks": { + "type": "integer", + "format": "int32", + "description": "Fork count" + }, + "full_name": { + "type": "string", + "description": "Full repository name (owner/repo)" + }, + "language": { + "type": [ + "string", + "null" + ], + "description": "Primary programming language" + }, + "name": { + "type": "string", + "description": "Repository name" + }, + "owner": { + "type": "string", + "description": "Repository owner" + }, + "stars": { + "type": "integer", + "format": "int32", + "description": "Star count" + } + } + }, + "PurgeLogsRequest": { + "type": "object", + "required": [ + "before" + ], + "properties": { + "before": { + "type": "string", + "description": "Delete all logs before this timestamp (ISO 8601)" + } + } + }, + "PushImageRequest": { + "type": "object", + "description": "Request to push an external image", + "required": [ + "image_ref" + ], + "properties": { + "image_ref": { + "type": "string" + }, + "metadata": {} + } + }, + "PushedExternalImageResponse": { + "type": "object", + "description": "Response for in-memory external image operations (legacy push flow).\n\nRenamed to avoid shadowing the richer database-backed `ExternalImageResponse`\nin `handlers/remote_deployments.rs`. The two types serve different routes\n(`/images` ephemeral push vs `/external-images` registered images).", + "required": [ + "id", + "image_ref", + "pushed_at" + ], + "properties": { + "digest": { + "type": [ + "string", + "null" + ] + }, + "id": { + "type": "string" + }, + "image_ref": { + "type": "string" + }, + "pushed_at": { + "type": "string", + "format": "date-time", + "example": "2025-10-12T12:15:47.609192Z" + }, + "size": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + } + } + }, + "QueryDataRequest": { + "type": "object", + "properties": { + "filters": { + "description": "JSON filters (backend-specific format)" + }, + "limit": { + "type": "integer", + "description": "Maximum number of rows to return", + "example": 100, + "minimum": 0 + }, + "offset": { + "type": "integer", + "description": "Number of rows to skip", + "example": 0, + "minimum": 0 + }, + "sort_by": { + "type": [ + "string", + "null" + ], + "description": "Sort by field name" + }, + "sort_order": { + "type": [ + "string", + "null" + ], + "description": "Sort order (asc/desc)" + } + } + }, + "QueryDataResponse": { + "type": "object", + "required": [ + "fields", + "rows", + "total_count", + "returned_count", + "execution_time_ms", + "truncated" + ], + "properties": { + "execution_time_ms": { + "type": "integer", + "format": "int64", + "description": "Query execution time in milliseconds", + "example": 45, + "minimum": 0 + }, + "fields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldResponse" + }, + "description": "Field definitions" + }, + "returned_count": { + "type": "integer", + "description": "Number of rows returned in this response", + "example": 100, + "minimum": 0 + }, + "rows": { + "type": "array", + "items": {}, + "description": "Data rows (array of JSON objects)" + }, + "total_count": { + "type": "integer", + "format": "int64", + "description": "Total number of rows matching the query (before limit/offset)", + "example": 1234, + "minimum": 0 + }, + "truncated": { + "type": "boolean", + "description": "Whether rows were dropped from this response to stay inside the byte budget.\n\n`returned_count` is always the number of rows actually present, so a truncated page is still internally consistent \u2014 but a caller comparing it against the requested limit would otherwise conclude the table simply ended. Reported explicitly so a partial page is never mistaken for a complete one, by a human, a script, or a model reading a tool result.", + "example": false + } + } + }, + "QuotaResponse": { + "type": "object", + "required": [ + "quota" + ], + "properties": { + "quota": { + "$ref": "#/components/schemas/StorageQuota" + } + } + }, + "RateLimitConfig": { + "type": "object", + "description": "Rate limiting configuration (subset of global RateLimitSettings)", + "properties": { + "blacklistIps": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Blacklist specific IPs for this project/environment" + }, + "maxRequestsPerHour": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Override rate limit per hour", + "minimum": 0 + }, + "maxRequestsPerMinute": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Override rate limit per minute", + "minimum": 0 + }, + "whitelistIps": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Whitelist specific IPs for this project/environment" + } + } + }, + "RateLimitSettings": { + "type": "object", + "properties": { + "blacklist_ips": { + "type": "array", + "items": { + "type": "string" + }, + "default": [] + }, + "enabled": { + "type": "boolean", + "default": false + }, + "max_requests_per_hour": { + "type": "integer", + "format": "int32", + "default": 1000, + "minimum": 0 + }, + "max_requests_per_minute": { + "type": "integer", + "format": "int32", + "default": 60, + "minimum": 0 + }, + "whitelist_ips": { + "type": "array", + "items": { + "type": "string" + }, + "default": [] + } + } + }, + "ReachabilityStatus": { + "type": "string", + "description": "Email reachability status", + "enum": [ + "safe", + "risky", + "invalid", + "unknown" + ] + }, + "ReadFileResponse": { + "type": "object", + "required": [ + "path", + "contents_b64", + "size" + ], + "properties": { + "contents_b64": { + "type": "string", + "description": "File contents, base64-encoded. Symmetric with `WriteFileBody`." + }, + "path": { + "type": "string" + }, + "size": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + }, + "ReadRowsQuery": { + "type": "object", + "description": "Query-string form of [`QueryDataRequest`] for the read-only `GET` rows\nendpoint.\n\nThe `POST` variant exists because filters are arbitrary backend-specific\nJSON. Reading rows is nonetheless a *read*, and the AI agent's tool index\nis GET-only by construction, so the same capability has to be reachable\nwithout a body. `filter` therefore carries the JSON as a string.", + "properties": { + "filter": { + "type": [ + "string", + "null" + ], + "description": "Backend-specific filter, JSON-encoded. Fetch the expected shape from\nthe `filter_schema` field of the explorer-support endpoint \u2014 e.g.\n`{\"where\":\"created_at > now() - interval '7 days'\"}` for SQL sources." + }, + "limit": { + "type": "integer", + "description": "Maximum number of rows to return", + "example": 100, + "minimum": 0 + }, + "offset": { + "type": "integer", + "description": "Number of rows to skip", + "example": 0, + "minimum": 0 + }, + "sort_by": { + "type": [ + "string", + "null" + ], + "description": "Sort by field name" + }, + "sort_order": { + "type": [ + "string", + "null" + ], + "description": "Sort order (asc/desc)" + } + } + }, + "RecentActivityQuery": { + "type": "object", + "description": "Query parameters for recent activity endpoint", + "required": [ + "project_id" + ], + "properties": { + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Environment ID (optional)" + }, + "limit": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Max number of events to return (default: 50, max: 100)" + }, + "project_id": { + "type": "integer", + "format": "int32", + "description": "Project ID" + }, + "since_id": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Return events with ID greater than this (for cursor-based polling)" + } + } + }, + "RecentActivityResponse": { + "type": "object", + "description": "Response for recent activity events endpoint", + "required": [ + "events", + "count" + ], + "properties": { + "count": { + "type": "integer", + "description": "Total events returned", + "minimum": 0 + }, + "events": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ActivityEvent" + }, + "description": "Recent events, newest first" + } + } + }, + "RecentEventResponse": { + "type": "object", + "required": [ + "occurred_at", + "event_type" + ], + "properties": { + "amount_minor": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "currency": { + "type": [ + "string", + "null" + ] + }, + "customer_ref": { + "type": [ + "string", + "null" + ] + }, + "event_type": { + "type": "string" + }, + "mrr_minor": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "occurred_at": { + "type": "string", + "format": "date-time" + } + } + }, + "RecentQueryParams": { + "type": "object", + "properties": { + "conversation_id": { + "type": [ + "string", + "null" + ], + "description": "Filter by conversation ID" + }, + "cost_gt": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Cost strictly greater-than, in microcents" + }, + "cost_gte": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Cost greater-than-or-equal, in microcents" + }, + "cost_lt": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Cost strictly less-than, in microcents" + }, + "cost_lte": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Cost less-than-or-equal, in microcents" + }, + "limit": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Page size (defaults to 20, max 50)", + "minimum": 0 + }, + "model": { + "type": [ + "string", + "null" + ], + "description": "Filter by model name" + }, + "offset": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Number of results to skip for pagination (defaults to 0)", + "minimum": 0 + }, + "provider": { + "type": [ + "string", + "null" + ], + "description": "Filter by provider name" + }, + "status": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Filter by HTTP status code (exact match)" + }, + "tags": { + "type": [ + "string", + "null" + ], + "description": "Filter by tags (comma-separated, AND logic)" + }, + "tokens_gt": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Total tokens (input + output) strictly greater-than" + }, + "tokens_gte": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Total tokens (input + output) greater-than-or-equal" + }, + "tokens_lt": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Total tokens (input + output) strictly less-than" + }, + "tokens_lte": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Total tokens (input + output) less-than-or-equal" + }, + "user_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Filter by user ID" + } + } + }, + "RecordExposureRequest": { + "type": "object", + "description": "Keys a running app actually evaluated since its last report.", + "required": [ + "keys" + ], + "properties": { + "keys": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Flag keys evaluated since the last report. Unknown keys are ignored.", + "example": [ + "checkout.v2", + "api.rate_limit" + ] + } + } + }, + "RecordExposureResponse": { + "type": "object", + "required": [ + "recorded" + ], + "properties": { + "recorded": { + "type": "integer", + "format": "int64", + "description": "How many keys were accepted for processing.\n\nDeliberately not the number of rows updated: echoing that back would\nlet a caller post a single candidate key and read the result as \"this\nflag exists\", turning the endpoint into an existence oracle.", + "minimum": 0 + } + } + }, + "RecordListResponse": { + "type": "object", + "description": "Record list response", + "required": [ + "records" + ], + "properties": { + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DnsRecord" + } + } + } + }, + "RecoveryTarget": { + "oneOf": [ + { + "type": "object", + "description": "Recover to a specific timestamp.", + "required": [ + "time", + "kind" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "time" + ] + }, + "time": { + "type": "string", + "format": "date-time" + } + } + }, + { + "type": "object", + "description": "Recover to a specific transaction id (Postgres).", + "required": [ + "xid", + "kind" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "xid" + ] + }, + "xid": { + "type": "string" + } + } + }, + { + "type": "object", + "description": "Recover to a specific log sequence number (Postgres).", + "required": [ + "lsn", + "kind" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "lsn" + ] + }, + "lsn": { + "type": "string" + } + } + }, + { + "type": "object", + "description": "Recover to a named restore point created via `pg_create_restore_point` (Postgres).", + "required": [ + "name", + "kind" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "name" + ] + }, + "name": { + "type": "string" + } + } + } + ], + "description": "Engine-specific recovery target for PITR.\n\nPostgres honors all variants; Redis/Mongo/S3 will likely reject non-Time\nvariants or define their own semantics when they grow PITR support." + }, + "ReferrerCount": { + "type": "object", + "required": [ + "referrer", + "count", + "percentage" + ], + "properties": { + "count": { + "type": "integer", + "format": "int64" + }, + "percentage": { + "type": "number", + "format": "double" + }, + "referrer": { + "type": "string" + } + } + }, + "ReferrersAnalyticsQuery": { + "type": "object", + "required": [ + "start_date", + "end_date", + "project_id" + ], + "properties": { + "end_date": { + "type": "string", + "format": "date-time" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "start_date": { + "type": "string", + "format": "date-time" + } + } + }, + "RegenerateDSNRequest": { + "type": "object", + "properties": { + "base_url": { + "type": [ + "string", + "null" + ] + } + } + }, + "RegisterImageRequest": { + "type": "object", + "required": [ + "image_ref" + ], + "properties": { + "digest": { + "type": [ + "string", + "null" + ], + "description": "Image digest (sha256:...)", + "example": "sha256:abc123def456" + }, + "image_ref": { + "type": "string", + "description": "Docker image reference (e.g., \"ghcr.io/org/app:v1.0\")", + "example": "ghcr.io/myorg/myapp:v1.0" + }, + "metadata": { + "description": "Additional metadata" + }, + "tag": { + "type": [ + "string", + "null" + ], + "description": "Image tag", + "example": "v1.0" + } + } + }, + "RegisterNodeApiRequest": { + "type": "object", + "required": [ + "name", + "token", + "address", + "private_address" + ], + "properties": { + "address": { + "type": "string", + "description": "Node's reachable address (e.g., \"10.100.0.2\" or \"192.168.1.50\")" + }, + "architecture": { + "type": [ + "string", + "null" + ], + "description": "Container platform of this node's Docker daemon (`linux/amd64`,\n`linux/arm64`). Optional: agents older than multi-arch support omit it\nand the value is learned from the first heartbeat instead." + }, + "csr_pem": { + "type": [ + "string", + "null" + ], + "description": "Node-generated certificate signing request (PEM) for multi-node mTLS\n(ADR-020 WS-2.1). When present, the control plane signs it with the\ncluster CA and returns the leaf + CA cert. Optional \u2014 token-only nodes\n(legacy / edge) still register without one." + }, + "edge_public_key": { + "type": [ + "string", + "null" + ], + "description": "X25519 public key for ECIES certificate encryption (base64-encoded, edge nodes only)" + }, + "join_token": { + "type": [ + "string", + "null" + ], + "description": "Join token to authorize this registration (must match the token generated in Settings)" + }, + "labels": { + "description": "Labels for scheduling (e.g., {\"region\": \"us-east\", \"gpu\": \"true\"})" + }, + "name": { + "type": "string", + "description": "Unique name for this node" + }, + "prior_token": { + "type": [ + "string", + "null" + ], + "description": "The node's *current* token, supplied to prove possession when\nre-registering (changing the identity of) a node that already exists.\nOptional; only needed to rebind a still-live node. (ADR-020 WS-1.2.)" + }, + "private_address": { + "type": "string", + "description": "Private/WireGuard address for inter-node communication" + }, + "public_endpoint": { + "type": [ + "string", + "null" + ], + "description": "Public endpoint for WireGuard (e.g., \"203.0.113.1:51820\")" + }, + "role": { + "type": [ + "string", + "null" + ], + "description": "Node role (default: \"worker\")" + }, + "token": { + "type": "string", + "description": "Registration token (plaintext, will be hashed before storage)" + }, + "wg_public_key": { + "type": [ + "string", + "null" + ], + "description": "WireGuard public key" + } + } + }, + "RegisterNodeResponse": { + "type": "object", + "required": [ + "id", + "name", + "status", + "message" + ], + "properties": { + "ca_cert_pem": { + "type": [ + "string", + "null" + ], + "description": "The cluster CA certificate (PEM) the node pins as its trust root.\nPresent only when a `csr_pem` was supplied. (ADR-020 WS-2.1.)" + }, + "cert_pem": { + "type": [ + "string", + "null" + ], + "description": "The signed per-node leaf certificate (PEM) the agent serves as its TLS\nserver cert. Present only when a `csr_pem` was supplied. (ADR-020 WS-2.1.)" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "name": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "RegisterRequest": { + "type": "object", + "required": [ + "email", + "password", + "name" + ], + "properties": { + "email": { + "type": "string" + }, + "name": { + "type": "string" + }, + "password": { + "type": "string" + } + } + }, + "ReinstallWebhookResponse": { + "type": "object", + "description": "Response for `POST /projects/{project_id}/gitlab/reinstall-webhook`", + "required": [ + "hook_id", + "message" + ], + "properties": { + "hook_id": { + "type": "integer", + "format": "int32", + "description": "The new GitLab hook ID that was installed." + }, + "message": { + "type": "string", + "description": "Human-readable status message." + } + } + }, + "ReleaseListResponse": { + "type": "object", + "required": [ + "releases" + ], + "properties": { + "releases": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "ReloadResponse": { + "type": "object", + "description": "Response from the reload endpoint.", + "required": [ + "loaded", + "plugins", + "message" + ], + "properties": { + "loaded": { + "type": "integer", + "description": "Number of plugins successfully loaded after reload", + "minimum": 0 + }, + "message": { + "type": "string", + "description": "Human-readable status message" + }, + "plugins": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Names of loaded plugins" + } + } + }, + "RemoteDeploymentResponse": { + "type": "object", + "required": [ + "id", + "project_id", + "environment_id", + "slug", + "state", + "source_type", + "created_at" + ], + "properties": { + "created_at": { + "type": "string", + "format": "date-time", + "example": "2025-10-12T12:15:47.609192Z" + }, + "environment_id": { + "type": "integer", + "format": "int32" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "slug": { + "type": "string" + }, + "source_type": { + "type": "string" + }, + "state": { + "type": "string" + } + } + }, + "RemoveNodeResponse": { + "type": "object", + "required": [ + "id", + "message" + ], + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } + }, + "RenameConversationRequest": { + "type": "object", + "required": [ + "title" + ], + "properties": { + "title": { + "type": "string", + "description": "New human-facing title. Trimmed; must be non-empty after trimming." + } + } + }, + "RepositoryListQuery": { + "type": "object", + "properties": { + "direction": { + "type": [ + "string", + "null" + ] + }, + "language": { + "type": [ + "string", + "null" + ] + }, + "owner": { + "type": [ + "string", + "null" + ] + }, + "page": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + }, + "per_page": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + }, + "private": { + "type": [ + "boolean", + "null" + ] + }, + "search": { + "type": [ + "string", + "null" + ] + }, + "sort": { + "type": [ + "string", + "null" + ] + } + } + }, + "RepositoryListResponse": { + "type": "object", + "required": [ + "repositories", + "total_count" + ], + "properties": { + "repositories": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RepositoryResponse" + } + }, + "total_count": { + "type": "integer", + "minimum": 0 + } + } + }, + "RepositoryPresetResponse": { + "type": "object", + "required": [ + "repository_id", + "owner", + "name", + "presets", + "calculated_at" + ], + "properties": { + "calculated_at": { + "type": "string", + "format": "date-time" + }, + "name": { + "type": "string" + }, + "owner": { + "type": "string" + }, + "presets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProjectPresetResponse" + } + }, + "repository_id": { + "type": "integer", + "format": "int32" + } + } + }, + "RepositoryResponse": { + "type": "object", + "required": [ + "id", + "owner", + "name", + "full_name", + "private", + "default_branch", + "created_at", + "updated_at", + "pushed_at", + "git_provider_connection_id" + ], + "properties": { + "clone_url": { + "type": [ + "string", + "null" + ], + "description": "HTTPS clone URL (e.g., https://github.com/owner/repo.git)" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "default_branch": { + "type": "string" + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "full_name": { + "type": "string" + }, + "git_provider_connection_id": { + "type": "integer", + "format": "int32", + "description": "ID of the git provider connection this repository was synced from." + }, + "id": { + "type": "integer", + "format": "int32" + }, + "language": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": "string" + }, + "owner": { + "type": "string" + }, + "preset": { + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/components/schemas/ProjectPresetResponse" + } + }, + "private": { + "type": "boolean" + }, + "pushed_at": { + "type": "string", + "format": "date-time" + }, + "ssh_url": { + "type": [ + "string", + "null" + ], + "description": "SSH clone URL (e.g., git@github.com:owner/repo.git)" + }, + "updated_at": { + "type": "string", + "format": "date-time" + } + } + }, + "RepositorySyncStartedResponse": { + "type": "object", + "description": "Returned by `POST /git-connections/{id}/sync` to acknowledge that a\nsync has been kicked off in the background. Clients should poll the\nconnection's `syncing` and `synced_repository_count` fields to track\nprogress rather than waiting on this response.", + "required": [ + "connection_id", + "syncing", + "started_at" + ], + "properties": { + "connection_id": { + "type": "integer", + "format": "int32" + }, + "started_at": { + "type": "string", + "format": "date-time" + }, + "syncing": { + "type": "boolean" + } + } + }, + "RequestRow": { + "type": "object", + "required": [ + "id", + "ts", + "method", + "host", + "path", + "status", + "request_headers", + "response_headers", + "headers_truncated" + ], + "properties": { + "client_ip": { + "type": [ + "string", + "null" + ] + }, + "country": { + "type": [ + "string", + "null" + ] + }, + "deployment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "error_group_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "headers_truncated": { + "type": "boolean" + }, + "host": { + "type": "string" + }, + "id": { + "type": "string", + "description": "The request's unique `request_id` (assigned by the proxy). Used as the\nrow identity instead of the storage PK because the ClickHouse backend\nhas no serial id (rows come back with `id = 0`) while `request_id` is\nunique and present on both backends." + }, + "latency_ms": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "method": { + "type": "string" + }, + "path": { + "type": "string" + }, + "query_string": { + "type": [ + "string", + "null" + ] + }, + "referrer": { + "type": [ + "string", + "null" + ] + }, + "request_headers": {}, + "response_headers": {}, + "status": { + "type": "integer", + "format": "int32" + }, + "trace_id": { + "type": [ + "string", + "null" + ] + }, + "ts": { + "type": "string", + "format": "date-time" + }, + "user_agent": { + "type": [ + "string", + "null" + ] + } + } + }, + "ResetPasswordRequest": { + "type": "object", + "required": [ + "token", + "new_password" + ], + "properties": { + "new_password": { + "type": "string" + }, + "token": { + "type": "string" + } + } + }, + "ResetPgStatStatementsRequest": { + "type": "object", + "description": "Explicit confirmation required for the destructive statistics reset.\n\nRequiring JSON makes the endpoint non-simple for browsers, preventing a\ndeployed same-site application from triggering it with a plain HTML form.", + "required": [ + "confirm" + ], + "properties": { + "confirm": { + "type": "boolean", + "description": "Must be `true` to acknowledge the global, irreversible reset." + } + } + }, + "ResetPgStatStatementsResponse": { + "type": "object", + "description": "Response for the pg_stat_statements reset endpoint.", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string", + "description": "Human-readable message confirming the destructive action." + } + } + }, + "ResizeSandboxBody": { + "type": "object", + "required": [ + "disk_size_mb" + ], + "properties": { + "disk_size_mb": { + "type": "integer", + "format": "int64", + "description": "New root disk size in MB. Grow-only; must exceed the current size.", + "minimum": 0 + } + }, + "additionalProperties": false + }, + "ResolvedEnvVarResponse": { + "type": "object", + "description": "One entry in the computed env-var view that merges manual and integration\nsources and tags each result with its origin. `value_preview` is always\nmasked \u2014 plaintext must be fetched per-key via the existing reveal endpoint,\nwhich is audit-logged.", + "required": [ + "key", + "value_preview", + "source", + "environments", + "include_in_preview" + ], + "properties": { + "environments": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EnvironmentInfo" + }, + "description": "Environments this var applies to. For integration-sourced vars this\nreflects every environment of the project (integrations are global)." + }, + "include_in_preview": { + "type": "boolean", + "description": "Whether the var would be auto-applied to preview environments.\nIntegration vars always surface in preview; manual vars follow the flag." + }, + "key": { + "type": "string" + }, + "source": { + "$ref": "#/components/schemas/ResolvedEnvVarSource" + }, + "value_preview": { + "type": "string", + "description": "Masked or truncated preview. Never the raw value." + } + } + }, + "ResolvedEnvVarSource": { + "oneOf": [ + { + "type": "object", + "description": "Manually-defined env var. If `overrides_service` is set, this key would\notherwise have been supplied by an integration \u2014 the UI should show the\nintegration icon plus an \"overridden\" indicator.", + "required": [ + "var_id", + "type" + ], + "properties": { + "overrides_service": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/EnvVarIntegrationInfo" + } + ] + }, + "type": { + "type": "string", + "enum": [ + "manual" + ] + }, + "var_id": { + "type": "integer", + "format": "int32" + } + } + }, + { + "type": "object", + "description": "Supplied by a linked external service (Postgres, Redis, S3, etc.).", + "required": [ + "service", + "type" + ], + "properties": { + "service": { + "$ref": "#/components/schemas/EnvVarIntegrationInfo" + }, + "type": { + "type": "string", + "enum": [ + "integration" + ] + } + } + } + ], + "description": "Where a resolved env var comes from. Integration-sourced vars may be\n\"shadowed\" by a manual entry with the same key, in which case the response\ncarries `Manual` with `overrides_service` populated so the UI can still show\nthe integration icon." + }, + "ResourceCounts": { + "type": "object", + "description": "Quick count of resources involved in the migration", + "required": [ + "projects", + "environments", + "deployments", + "environment_variables", + "services", + "domains" + ], + "properties": { + "deployments": { + "type": "integer", + "minimum": 0 + }, + "domains": { + "type": "integer", + "minimum": 0 + }, + "environment_variables": { + "type": "integer", + "minimum": 0 + }, + "environments": { + "type": "integer", + "minimum": 0 + }, + "projects": { + "type": "integer", + "minimum": 0 + }, + "services": { + "type": "integer", + "minimum": 0 + } + } + }, + "ResourceFootprint": { + "type": "object", + "description": "A CPU + memory footprint (requests or measured usage)", + "required": [ + "cpu_millis", + "memory_mb" + ], + "properties": { + "cpu_millis": { + "type": "integer", + "format": "int64", + "description": "CPU in millicores" + }, + "memory_mb": { + "type": "integer", + "format": "int64", + "description": "Memory in MB" + } + } + }, + "ResourceInfo": { + "type": "object", + "description": "Resource attributes extracted from OTel resource descriptors.", + "required": [ + "service_name", + "attributes" + ], + "properties": { + "attributes": { + "type": "object" + }, + "deployment_environment": { + "type": [ + "string", + "null" + ] + }, + "service_name": { + "type": "string" + }, + "service_version": { + "type": [ + "string", + "null" + ] + } + } + }, + "ResourceLimitApplyResult": { + "type": "object", + "description": "Per-container outcome of a live `docker update` call. Surfaced from the\nPATCH /resources endpoint so the UI can tell the operator whether the\nnew caps are already in effect or whether they only apply on next\nrecreate (e.g., container was missing).", + "required": [ + "role", + "container_name", + "outcome" + ], + "properties": { + "container_name": { + "type": "string" + }, + "error": { + "type": [ + "string", + "null" + ], + "description": "Populated only when `outcome == \"failed\"`." + }, + "outcome": { + "type": "string", + "description": "One of:\n- \"applied\" \u2014 Docker accepted the update; caps are live now.\n- \"missing\" \u2014 container does not exist; caps stored, will apply on next start.\n- \"stopped\" \u2014 container exists but isn't running; Docker still\n accepts the update (the new caps apply on next start).\n- \"failed\" \u2014 `docker update` returned an error (see `error`)." + }, + "role": { + "type": "string", + "description": "`service_members.role` for cluster members; \"standalone\" otherwise." + } + } + }, + "ResourceLimits": { + "type": "object", + "description": "Resource limits and requests", + "properties": { + "cpu_limit": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "CPU limit (millicores)" + }, + "cpu_request": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "CPU request (millicores)" + }, + "memory_limit": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Memory limit (MB)" + }, + "memory_request": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Memory request (MB)" + } + } + }, + "ResourceLimitsResponse": { + "type": "object", + "description": "Container resource limits", + "properties": { + "cpu_limit": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "cpu_request": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "memory_limit": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "memory_request": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + } + }, + "ResourceLimitsUpdateResponse": { + "type": "object", + "description": "Response from PATCH /external-services/{id}/resources.", + "required": [ + "limits", + "applied" + ], + "properties": { + "applied": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ResourceLimitApplyResult" + }, + "description": "Per-container result of trying to apply the limits live." + }, + "limits": { + "$ref": "#/components/schemas/ServiceResourceLimits", + "description": "The limits that were persisted to the encrypted config." + } + } + }, + "ResourcesBody": { + "type": "object", + "description": "Nested `resources: { memory, vcpus }` as sent by `@vercel/sandbox`.\n`memory` is in MB, `vcpus` is fractional CPU count.", + "properties": { + "memory": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + }, + "vcpus": { + "type": [ + "number", + "null" + ], + "format": "double" + } + } + }, + "RestoreCapabilities": { + "type": "object", + "description": "Capabilities a service exposes for the generic restore framework.\n\nEach engine overrides `ExternalService::restore_capabilities` to declare\nwhat it supports. The handler layer uses this to validate requests and\nthe UI uses it to conditionally show options (e.g., PITR picker).", + "required": [ + "restore_in_place", + "restore_to_new_service", + "pitr" + ], + "properties": { + "earliest_pitr_time": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "Earliest recoverable timestamp, if `pitr` is true. Derived from\nengine-specific archive metadata (e.g., `pg_stat_archiver`)." + }, + "latest_pitr_time": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "Latest recoverable timestamp, if `pitr` is true." + }, + "pitr": { + "type": "boolean", + "description": "Point-in-time recovery using engine-specific continuous archives\n(WAL for Postgres, AOF for Redis, oplog for MongoDB, object versions for S3)." + }, + "restore_in_place": { + "type": "boolean", + "description": "Restore a backup onto the same running service (destructive)." + }, + "restore_to_new_service": { + "type": "boolean", + "description": "Restore a backup into a freshly provisioned service." + } + } + }, + "RestoreCapabilitiesResponse": { + "allOf": [ + { + "$ref": "#/components/schemas/RestoreCapabilities", + "description": "Trait-declared capabilities." + }, + { + "type": "object", + "required": [ + "suggested_new_service_name" + ], + "properties": { + "suggested_new_service_name": { + "type": "string", + "description": "Suggested name for the new service when creating a clone. Safe to\npre-fill into the UI dialog; the user can edit before submitting." + } + } + } + ] + }, + "RestorePlan": { + "type": "object", + "description": "Preview of a restore operation. Answers \"what will happen if I click\nstart?\" with engine-level specificity so the user can confirm before\ncommitting to a destructive action.", + "required": [ + "engine", + "target_service", + "source_backup", + "strategy", + "steps", + "warnings", + "errors", + "destructive", + "mode" + ], + "properties": { + "destructive": { + "type": "boolean", + "description": "Whether any step overwrites existing data on the target service." + }, + "engine": { + "type": "string", + "description": "Target engine (\"postgres\", etc.)." + }, + "errors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Blocking problems. The UI disables the Start button when non-empty." + }, + "mode": { + "type": "string", + "description": "Echo of the requested mode for the UI." + }, + "source_backup": { + "$ref": "#/components/schemas/PlanSourceBackup", + "description": "Backup we'll read from." + }, + "steps": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Ordered list of human-readable actions the orchestrator will take." + }, + "strategy": { + "type": "string", + "description": "How the restore will be performed: \"walg_restore\", \"pg_dump_restore\",\nor \"unsupported\"." + }, + "target_service": { + "$ref": "#/components/schemas/PlanTarget", + "description": "Service we'll operate on (or provision a sibling of)." + }, + "warnings": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Non-blocking caveats the user should see (cross-service, empty\nlocation that will be auto-resolved, missing engine metadata, ...)." + } + } + }, + "RestoreRequestMode": { + "oneOf": [ + { + "type": "object", + "description": "Restore the backup onto the existing service (destructive).", + "required": [ + "mode" + ], + "properties": { + "mode": { + "type": "string", + "enum": [ + "in_place" + ] + } + } + }, + { + "type": "object", + "description": "Provision a new service and restore into it.", + "required": [ + "name", + "mode" + ], + "properties": { + "mode": { + "type": "string", + "enum": [ + "new_service" + ] + }, + "name": { + "type": "string", + "description": "Name for the new service. Orchestrator auto-suggests\n`{source}-restore-{yyyymmdd-hhmm}` if caller omits, but we require\nan explicit value at the API boundary." + }, + "parameter_overrides": { + "description": "Optional parameter overrides (port, docker_image, database)." + } + } + }, + { + "type": "object", + "description": "Point-in-time recovery. Only valid on WAL-G backups (Postgres).", + "required": [ + "to_new_service", + "target", + "mode" + ], + "properties": { + "mode": { + "type": "string", + "enum": [ + "pitr" + ] + }, + "new_service_name": { + "type": [ + "string", + "null" + ], + "description": "Required when `to_new_service` is true." + }, + "target": { + "$ref": "#/components/schemas/RecoveryTarget", + "description": "Recovery target kind + value." + }, + "to_new_service": { + "type": "boolean", + "description": "Whether PITR restores in place or creates a new service." + } + } + } + ], + "description": "What the caller wants to do. Mirrors `externalsvc::RestoreMode` but\nflattened for JSON over the wire." + }, + "RestoreRunView": { + "type": "object", + "required": [ + "id", + "source_backup_id", + "source_service_id", + "mode", + "status", + "phase", + "created_at" + ], + "properties": { + "created_at": { + "type": "string" + }, + "error_message": { + "type": [ + "string", + "null" + ] + }, + "finished_at": { + "type": [ + "string", + "null" + ] + }, + "id": { + "type": "integer", + "format": "int32" + }, + "mode": { + "type": "string" + }, + "phase": { + "type": "string" + }, + "recovery_target": {}, + "source_backup_id": { + "type": "integer", + "format": "int32" + }, + "source_service_id": { + "type": "integer", + "format": "int32" + }, + "started_at": { + "type": [ + "string", + "null" + ] + }, + "status": { + "type": "string" + }, + "target_service_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "target_service_name": { + "type": [ + "string", + "null" + ] + } + } + }, + "RetentionCleanupFailure": { + "type": "object", + "required": [ + "backup_id", + "reason", + "partial", + "deleted_objects" + ], + "properties": { + "backup_id": { + "type": "string" + }, + "deleted_objects": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "partial": { + "type": "boolean" + }, + "reason": { + "type": "string" + } + } + }, + "RetentionCleanupReport": { + "type": "object", + "required": [ + "dry_run", + "expired", + "deleted", + "failed", + "failures", + "deleted_backup_ids", + "deleted_backup_ids_truncated", + "partially_deleted_backup_ids", + "partially_deleted_backup_ids_truncated", + "candidate_backup_ids", + "candidate_backup_ids_truncated" + ], + "properties": { + "candidate_backup_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Capped sample of backups selected by the retention policy." + }, + "candidate_backup_ids_truncated": { + "type": "boolean" + }, + "deleted": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "deleted_backup_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Capped sample of deleted backup UUIDs for audit attribution." + }, + "deleted_backup_ids_truncated": { + "type": "boolean" + }, + "dry_run": { + "type": "boolean", + "description": "True when this report is a non-destructive preview." + }, + "expired": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "failed": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "failures": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RetentionCleanupFailure" + }, + "description": "Capped diagnostic sample; `failed` remains the authoritative total." + }, + "partially_deleted_backup_ids": { + "type": "array", + "items": { + "type": "string" + } + }, + "partially_deleted_backup_ids_truncated": { + "type": "boolean" + }, + "schedule_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Schedule scope, or `None` when every schedule was considered." + } + } + }, + "RetryClusterRequest": { + "type": "object", + "description": "Request body for retrying a failed cluster initialization.", + "properties": { + "members": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ClusterMemberRequest" + }, + "description": "Cluster member specifications (same format as create).\nIf omitted, the original member configuration is reconstructed from\nthe preserved service_members records." + } + } + }, + "RevenueRow": { + "type": "object", + "required": [ + "id", + "ts", + "provider", + "event_type" + ], + "properties": { + "amount_minor": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "currency": { + "type": [ + "string", + "null" + ] + }, + "customer_ref": { + "type": [ + "string", + "null" + ] + }, + "deployment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "event_type": { + "type": "string" + }, + "id": { + "type": "integer", + "format": "int64" + }, + "provider": { + "type": "string" + }, + "trace_id": { + "type": [ + "string", + "null" + ] + }, + "ts": { + "type": "string", + "format": "date-time" + } + } + }, + "RiskLevel": { + "type": "string", + "description": "Risk level for a migration step", + "enum": [ + "none", + "low", + "medium", + "high", + "critical" + ] + }, + "RoleInfo": { + "type": "object", + "description": "Information about a role", + "required": [ + "name", + "description", + "permissions" + ], + "properties": { + "description": { + "type": "string", + "description": "Human-readable description of the role" + }, + "name": { + "type": "string", + "description": "The role identifier (e.g., \"admin\")" + }, + "permissions": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Permissions included in this role" + } + } + }, + "RootfsCacheEntry": { + "type": "object", + "description": "A cached rootfs image (Firecracker backend). Digest-keyed build artifact\nshared by all VMs created from the same image.", + "required": [ + "digest", + "bytes", + "referenced_by" + ], + "properties": { + "bytes": { + "type": "integer", + "format": "int64", + "description": "Actual on-disk size in bytes (sparse-aware).", + "minimum": 0 + }, + "digest": { + "type": "string", + "description": "Image digest this rootfs was built from (the cache key)." + }, + "referenced_by": { + "type": "array", + "items": { + "type": "string" + }, + "description": "IDs of live sandboxes whose per-VM disk was cloned from this entry.\nEmpty means the entry is reclaimable \u2014 no sandbox needs it." + } + } + }, + "RootfsGcReport": { + "type": "object", + "description": "Outcome of a rootfs garbage-collection pass.", + "required": [ + "removed_digests", + "freed_bytes" + ], + "properties": { + "freed_bytes": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "removed_digests": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Digests of cache entries removed because no sandbox referenced them." + } + } + }, + "RootfsReport": { + "type": "object", + "description": "Snapshot of a backend's rootfs storage for the management API. Backends\nwithout a rootfs concept (Docker, local) return an empty report.", + "required": [ + "cache_bytes", + "cache", + "vm_bytes", + "vms" + ], + "properties": { + "cache": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RootfsCacheEntry" + } + }, + "cache_bytes": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "vm_bytes": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "vms": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RootfsVmEntry" + } + } + } + }, + "RootfsVmEntry": { + "type": "object", + "description": "A per-sandbox rootfs disk (Firecracker backend). One per non-destroyed\nsandbox \u2014 the authoritative storage, independent of the cache.", + "required": [ + "sandbox_name", + "bytes", + "running" + ], + "properties": { + "bytes": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "running": { + "type": "boolean" + }, + "sandbox_name": { + "type": "string" + } + } + }, + "RouteRefreshResponse": { + "type": "object", + "required": [ + "route_count", + "message" + ], + "properties": { + "message": { + "type": "string", + "description": "Human-readable message" + }, + "route_count": { + "type": "integer", + "description": "Number of routes loaded", + "minimum": 0 + } + } + }, + "RouteResponse": { + "type": "object", + "required": [ + "id", + "domain", + "host", + "port", + "enabled", + "route_type", + "created_at", + "updated_at" + ], + "properties": { + "created_at": { + "type": "integer", + "format": "int64" + }, + "domain": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "host": { + "type": "string" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "port": { + "type": "integer", + "format": "int32" + }, + "route_type": { + "type": "string", + "description": "Route type: \"http\" or \"tls\"" + }, + "updated_at": { + "type": "integer", + "format": "int64" + } + } + }, + "RouteRole": { + "type": "object", + "required": [ + "id", + "name", + "created_at", + "updated_at" + ], + "properties": { + "created_at": { + "type": "integer", + "format": "int64", + "example": "1683900000000" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "updated_at": { + "type": "integer", + "format": "int64", + "example": "1683900000000" + } + } + }, + "RouteUser": { + "type": "object", + "required": [ + "id", + "name", + "username", + "email", + "image", + "mfa_enabled", + "email_verified", + "created_at", + "updated_at" + ], + "properties": { + "created_at": { + "type": "integer", + "format": "int64", + "example": "1683900000000" + }, + "deleted_at": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "email": { + "type": "string" + }, + "email_verified": { + "type": "boolean" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "image": { + "type": "string" + }, + "mfa_enabled": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "updated_at": { + "type": "integer", + "format": "int64", + "example": "1683900000000" + }, + "username": { + "type": "string" + } + } + }, + "RouteUserWithRoles": { + "type": "object", + "required": [ + "user", + "roles" + ], + "properties": { + "roles": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RouteRole" + } + }, + "user": { + "$ref": "#/components/schemas/RouteUser" + } + } + }, + "RunBackupRequest": { + "type": "object", + "required": [ + "backup_type" + ], + "properties": { + "backup_type": { + "type": "string", + "description": "Type of backup to perform", + "example": "full" + } + } + }, + "RunExternalServiceBackupRequest": { + "type": "object", + "properties": { + "backup_type": { + "type": [ + "string", + "null" + ], + "description": "Type of backup to perform (e.g., \"full\", \"incremental\")", + "example": "full" + }, + "s3_source_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "ID of the S3 source to store the backup. If omitted, the current default S3 source is used.", + "example": 1 + } + } + }, + "S3ConnectionTestResponse": { + "type": "object", + "description": "Response body for an S3 connection test.", + "required": [ + "ok", + "message" + ], + "properties": { + "message": { + "type": "string", + "description": "Human-readable message (success confirmation or error detail)." + }, + "ok": { + "type": "boolean", + "description": "Whether the connection and credentials worked." + } + } + }, + "S3CredentialsResponse": { + "type": "object", + "description": "S3 credentials distributed to agents for backup/restore operations.", + "required": [ + "access_key_id", + "secret_key", + "region", + "bucket_name", + "force_path_style" + ], + "properties": { + "access_key_id": { + "type": "string" + }, + "bucket_name": { + "type": "string" + }, + "endpoint": { + "type": [ + "string", + "null" + ] + }, + "force_path_style": { + "type": "boolean" + }, + "region": { + "type": "string" + }, + "secret_key": { + "type": "string" + } + } + }, + "S3SourceResponse": { + "type": "object", + "description": "Response type for S3 source", + "required": [ + "id", + "name", + "bucket_name", + "bucket_path", + "access_key_id", + "secret_key", + "region", + "is_default", + "created_at", + "updated_at" + ], + "properties": { + "access_key_id": { + "type": "string", + "example": "AKIAXXXXXXXXXXXXXXXX" + }, + "bucket_name": { + "type": "string" + }, + "bucket_path": { + "type": "string" + }, + "created_at": { + "type": "integer", + "format": "int64" + }, + "endpoint": { + "type": [ + "string", + "null" + ], + "example": "http://minio.example.com:9000" + }, + "force_path_style": { + "type": [ + "boolean", + "null" + ] + }, + "id": { + "type": "integer", + "format": "int32" + }, + "is_default": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "region": { + "type": "string" + }, + "secret_key": { + "type": "string", + "writeOnly": true + }, + "updated_at": { + "type": "integer", + "format": "int64" + } + } + }, + "SandboxDomainResponse": { + "type": "object", + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string" + } + } + }, + "SandboxEvent": { + "type": "object", + "description": "One entry in a sandbox's operations timeline.", + "required": [ + "event_type", + "at" + ], + "properties": { + "at": { + "type": "integer", + "format": "int64", + "description": "Unix epoch milliseconds." + }, + "detail": { + "description": "Optional structured context (shape depends on `event_type`)." + }, + "event_type": { + "type": "string", + "description": "Machine-readable operation (`created`, `stopped`, `resumed`,\n`restarted`, `timeout_extended`, `resized`, `preview_password_set`,\n`preview_password_cleared`, `preview_share_link_created`, `source_seeded`,\n`destroyed`)." + } + } + }, + "SandboxEventsResponse": { + "type": "object", + "required": [ + "events" + ], + "properties": { + "events": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SandboxEvent" + } + } + } + }, + "SandboxInner": { + "type": "object", + "description": "Inner `sandbox` object in `@vercel/sandbox` responses. Strict shape \u2014\nthe SDK's zod validator rejects missing required fields.", + "required": [ + "id", + "memory", + "vcpus", + "region", + "runtime", + "timeout", + "status", + "requestedAt", + "createdAt", + "updatedAt", + "cwd", + "name", + "preview_url_template" + ], + "properties": { + "agent_run_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Agent run this sandbox executes (autofixer / workflow agent).\n`None` for sandboxes created via this API." + }, + "backend": { + "type": [ + "string", + "null" + ], + "description": "Isolation backend: \"docker\" | \"firecracker\". `None` on legacy rows\ncreated before the backend was recorded." + }, + "createdAt": { + "type": "integer", + "format": "int64" + }, + "cwd": { + "type": "string" + }, + "disk_size_mb": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Configured root disk size in MB (Firecracker). `None` when unknown or\nthe default.", + "minimum": 0 + }, + "id": { + "type": "string" + }, + "image": { + "type": [ + "string", + "null" + ] + }, + "memory": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "name": { + "type": "string" + }, + "preview_password_hint": { + "type": [ + "string", + "null" + ] + }, + "preview_url_template": { + "type": "string" + }, + "region": { + "type": "string" + }, + "requestedAt": { + "type": "integer", + "format": "int64", + "description": "Creation time as Unix epoch milliseconds." + }, + "runtime": { + "type": "string" + }, + "status": { + "type": "string" + }, + "timeout": { + "type": "integer", + "format": "int64", + "description": "Idle timeout in milliseconds (SDK convention).", + "minimum": 0 + }, + "updatedAt": { + "type": "integer", + "format": "int64" + }, + "vcpus": { + "type": "number", + "format": "double" + } + } + }, + "SandboxResponse": { + "type": "object", + "description": "`@vercel/sandbox` wraps every single-sandbox response as\n`{ sandbox: {...}, routes: [...] }`. The SDK reads both.", + "required": [ + "sandbox", + "routes" + ], + "properties": { + "routes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SandboxRoute" + } + }, + "sandbox": { + "$ref": "#/components/schemas/SandboxInner" + } + } + }, + "SandboxRoute": { + "type": "object", + "description": "A single preview route, one per declared port. We don't know ports\nupfront, so we surface an empty array by default \u2014 SDK clients use\ntheir own port when calling `sandbox.domain(port)`.", + "required": [ + "url", + "subdomain", + "port" + ], + "properties": { + "port": { + "type": "integer", + "format": "int32", + "minimum": 0 + }, + "subdomain": { + "type": "string" + }, + "url": { + "type": "string" + } + } + }, + "SandboxStatusResponse": { + "type": "object", + "required": [ + "docker_available", + "image_ready", + "image_name", + "firecracker_available" + ], + "properties": { + "docker_available": { + "type": "boolean" + }, + "error": { + "type": [ + "string", + "null" + ] + }, + "firecracker_available": { + "type": "boolean" + }, + "image_name": { + "type": "string" + }, + "image_ready": { + "type": "boolean" + } + } + }, + "SaveAgentTokenRequest": { + "type": "object", + "required": [ + "token" + ], + "properties": { + "token": { + "type": "string", + "description": "The OAuth token from `claude setup-token` or an API key.\nWill be encrypted before storage." + } + } + }, + "SaveAgentTokenResponse": { + "type": "object", + "required": [ + "saved" + ], + "properties": { + "saved": { + "type": "boolean" + } + } + }, + "SaveCredentialRequest": { + "type": "object", + "required": [ + "auth_type", + "credential" + ], + "properties": { + "auth_type": { + "type": "string", + "description": "Auth flavor id (must match one of the provider's catalog entries)." + }, + "credential": { + "type": "string", + "description": "Plaintext credential body (API key, OAuth token, or full config file\ncontents). Encrypted with `EncryptionService` before being persisted\ninside the `agent_sandbox.providers` JSON map." + } + } + }, + "SaveCredentialResponse": { + "type": "object", + "required": [ + "saved", + "provider_id", + "auth_type" + ], + "properties": { + "auth_type": { + "type": "string" + }, + "provider_id": { + "type": "string" + }, + "saved": { + "type": "boolean" + } + } + }, + "ScalewayCredentialsRequest": { + "type": "object", + "required": [ + "api_key", + "project_id" + ], + "properties": { + "api_key": { + "type": "string", + "example": "scw-secret-key-12345" + }, + "project_id": { + "type": "string", + "example": "12345678-1234-1234-1234-123456789012" + } + } + }, + "ScanResponse": { + "type": "object", + "required": [ + "id", + "project_id", + "scanner_type", + "status", + "total_count", + "critical_count", + "high_count", + "medium_count", + "low_count", + "unknown_count", + "started_at", + "created_at", + "updated_at" + ], + "properties": { + "branch": { + "type": [ + "string", + "null" + ] + }, + "commit_hash": { + "type": [ + "string", + "null" + ] + }, + "completed_at": { + "type": [ + "string", + "null" + ], + "example": "2025-12-08T12:15:47.609192Z" + }, + "created_at": { + "type": "string", + "example": "2025-12-08T12:15:47.609192Z" + }, + "critical_count": { + "type": "integer", + "format": "int32" + }, + "deployment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "error_message": { + "type": [ + "string", + "null" + ] + }, + "high_count": { + "type": "integer", + "format": "int32" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "low_count": { + "type": "integer", + "format": "int32" + }, + "medium_count": { + "type": "integer", + "format": "int32" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "scanner_type": { + "type": "string" + }, + "scanner_version": { + "type": [ + "string", + "null" + ] + }, + "started_at": { + "type": "string", + "example": "2025-12-08T12:15:47.609192Z" + }, + "status": { + "type": "string" + }, + "total_count": { + "type": "integer", + "format": "int32" + }, + "unknown_count": { + "type": "integer", + "format": "int32" + }, + "updated_at": { + "type": "string", + "example": "2025-12-08T12:15:47.609192Z" + } + } + }, + "ScheduleRunEntry": { + "type": "object", + "description": "A single run-history entry for the schedule detail page (deliverable 1).\n\nCombines one `backups` row with the most-recent `backup_jobs` row for that\nbackup via a lateral JOIN. Fields from `backup_jobs` are `None` for legacy\nbackup rows that pre-date ADR-014.", + "required": [ + "backup_id", + "backup_uuid", + "state", + "started_at", + "s3_location" + ], + "properties": { + "attempts": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Number of claim-and-run attempts so far. `None` for legacy rows." + }, + "backup_id": { + "type": "integer", + "format": "int32", + "description": "DB id of the `backups` row." + }, + "backup_uuid": { + "type": "string", + "description": "UUID string (`backups.backup_id`)." + }, + "current_step": { + "type": [ + "string", + "null" + ], + "description": "Last completed step reported by the engine (e.g. `\"upload\"`).\n`None` when no step has been persisted yet." + }, + "error_message": { + "type": [ + "string", + "null" + ], + "description": "Engine-reported error message when `state = \"failed\"`." + }, + "finished_at": { + "type": [ + "string", + "null" + ], + "description": "When the backup finished, if known." + }, + "job_id": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Most recent `backup_jobs.id` for this backup. `None` for legacy rows." + }, + "s3_location": { + "type": "string", + "description": "S3 object key or URL where the backup data lives." + }, + "size_bytes": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Final size in bytes once completed. `None` while running." + }, + "started_at": { + "type": "string", + "description": "When the backup was started (ISO 8601 / RFC 3339)." + }, + "state": { + "type": "string", + "description": "Current state: `\"pending\"`, `\"running\"`, `\"completed\"`, `\"failed\"`." + } + } + }, + "ScheduleRunJobEntry": { + "type": "object", + "description": "A single job entry inside an expanded schedule run, returned by\n[`BackupService::list_schedule_run_jobs`].", + "required": [ + "backup_id", + "backup_uuid", + "engine", + "service_name", + "state", + "started_at", + "s3_source_id" + ], + "properties": { + "backup_id": { + "type": "integer", + "format": "int32", + "description": "`backups.id` for this job." + }, + "backup_uuid": { + "type": "string", + "description": "`backups.backup_id` UUID string." + }, + "engine": { + "type": "string", + "description": "Engine key (e.g. `\"control_plane\"`, `\"redis\"`)." + }, + "error_message": { + "type": [ + "string", + "null" + ], + "description": "Engine-reported error message when `state = \"failed\"`." + }, + "finished_at": { + "type": [ + "string", + "null" + ], + "description": "When this child backup finished, if known." + }, + "s3_source_id": { + "type": "integer", + "format": "int32", + "description": "FK to `s3_sources.id` \u2014 needed for the backup detail link." + }, + "service_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "`external_services.id` \u2014 `NULL` for the control-plane job." + }, + "service_name": { + "type": "string", + "description": "Name of the external service, or `\"control plane\"` for the\ncontrol-plane job." + }, + "size_bytes": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Size in bytes once completed; `None` while running." + }, + "started_at": { + "type": "string", + "description": "When this child backup started (ISO 8601 / RFC 3339)." + }, + "state": { + "type": "string", + "description": "Current state of this child backup." + } + } + }, + "ScheduleRunListResponse": { + "type": "object", + "description": "Paginated run-history response for a backup schedule (deliverable 1).", + "required": [ + "runs", + "total", + "page", + "page_size" + ], + "properties": { + "page": { + "type": "integer", + "format": "int64", + "description": "Current page (1-based)." + }, + "page_size": { + "type": "integer", + "format": "int64", + "description": "Number of items per page (clamped to 1\u2013100)." + }, + "runs": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ScheduleRunEntry" + }, + "description": "Run entries, newest first." + }, + "total": { + "type": "integer", + "format": "int64", + "description": "Total number of runs across all pages." + } + } + }, + "ScheduleRunResponse": { + "type": "object", + "description": "HTTP response body for `POST /api/backups/schedules/{id}/run` (fan-out).", + "required": [ + "schedule_run_id", + "jobs" + ], + "properties": { + "jobs": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EnqueuedJob" + }, + "description": "All jobs that were enqueued in this fan-out." + }, + "schedule_run_id": { + "type": "integer", + "format": "int64", + "description": "The `schedule_runs.id` of the newly created run." + } + } + }, + "ScheduleRunSummary": { + "type": "object", + "description": "Summary of one scheduler tick (or one \"Run now\" click), returned by\n[`BackupService::list_schedule_runs`].\n\nThe `aggregate_state` is computed at read time from child backup counts:\n- `\"running\"` \u2014 at least one child is `\"pending\"` or `\"running\"`.\n- `\"failed\"` \u2014 at least one child is `\"failed\"` and none are running.\n- `\"completed\"` \u2014 all children are `\"completed\"`.", + "required": [ + "run_id", + "schedule_id", + "triggered_by", + "started_at", + "aggregate_state", + "total_jobs", + "completed_jobs", + "failed_jobs", + "running_jobs", + "pending_jobs" + ], + "properties": { + "aggregate_state": { + "type": "string", + "description": "Aggregate state computed from child counts (see struct docs)." + }, + "completed_jobs": { + "type": "integer", + "format": "int64", + "description": "Number of children in `state = \"completed\"`." + }, + "failed_jobs": { + "type": "integer", + "format": "int64", + "description": "Number of children in `state = \"failed\"`." + }, + "finished_at": { + "type": [ + "string", + "null" + ], + "description": "When all children reached a terminal state. `None` while any child is\nstill `\"pending\"` or `\"running\"`." + }, + "pending_jobs": { + "type": "integer", + "format": "int64", + "description": "Number of children in `state = \"pending\"`." + }, + "run_id": { + "type": "integer", + "format": "int64", + "description": "`schedule_runs.id` for this tick." + }, + "running_jobs": { + "type": "integer", + "format": "int64", + "description": "Number of children in `state = \"running\"`." + }, + "schedule_id": { + "type": "integer", + "format": "int32", + "description": "FK to `backup_schedules.id`." + }, + "started_at": { + "type": "string", + "description": "When the fan-out started (ISO 8601 / RFC 3339)." + }, + "total_jobs": { + "type": "integer", + "format": "int64", + "description": "Total number of child backup jobs in this run." + }, + "triggered_by": { + "type": "string", + "description": "How the run was triggered: `\"cron\"` or `\"manual\"`." + } + } + }, + "ScheduleRunSummaryList": { + "type": "object", + "description": "Paginated list of schedule run summaries returned by the new\n[`BackupService::list_schedule_runs`].", + "required": [ + "runs", + "total", + "page", + "page_size" + ], + "properties": { + "page": { + "type": "integer", + "format": "int64", + "description": "Current page (1-based)." + }, + "page_size": { + "type": "integer", + "format": "int64", + "description": "Number of items per page." + }, + "runs": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ScheduleRunSummary" + }, + "description": "Run summaries, newest first. Includes synthetic single-job rows for\nlegacy `backups` rows that have `schedule_id` set but no\n`schedule_run_id` (pre-fan-out history)." + }, + "total": { + "type": "integer", + "format": "int64", + "description": "Total number of run entries across all pages." + } + } + }, + "ScreenshotSettings": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "default": false + }, + "provider": { + "type": "string", + "default": "local" + }, + "url": { + "type": "string", + "default": "" + } + } + }, + "SearchLogsRequest": { + "type": "object", + "required": [ + "project_id" + ], + "properties": { + "container_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Filter to specific containers (Docker container IDs). Empty = all\ncontainers. Drives \"filter by container / show all\" in a project's\nhistory, which spans multiple deployments and containers." + }, + "context_lines": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "grep -C: number of raw context lines to include before and after each\nmatch (0 = none, default). Clamped to 50 server-side. The surrounding\nlines ignore the level/text filters \u2014 they are the actual adjacent log\nlines, merged across overlapping matches.", + "minimum": 0 + }, + "cursor": { + "type": [ + "string", + "null" + ], + "description": "Pagination cursor" + }, + "deploy_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Filter by deployment ID (deployments.id)" + }, + "end_time": { + "type": [ + "string", + "null" + ], + "description": "End of time range (ISO 8601). Defaults to now." + }, + "envs": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Filter by environments" + }, + "external_service_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "When set, search an imported/managed external service's logs instead\nof a project's. `project_id` is ignored in this mode." + }, + "levels": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Filter by log levels" + }, + "node_ids": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "description": "Filter to specific worker nodes (node_id). Empty = all nodes, including\ncontrol-plane-local logs." + }, + "page_size": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Page size (default: 100, max: 500)", + "minimum": 0 + }, + "project_id": { + "type": "integer", + "format": "int32", + "description": "Project ID (integer, as used by the rest of the platform)" + }, + "services": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Filter by services" + }, + "start_time": { + "type": [ + "string", + "null" + ], + "description": "Start of time range (ISO 8601). Defaults to 1 hour ago." + }, + "text": { + "type": [ + "string", + "null" + ], + "description": "Full text search query" + } + } + }, + "SearchLogsResponse": { + "type": "object", + "required": [ + "lines", + "search_mode", + "total_scanned" + ], + "properties": { + "available_sources": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LogSource" + }, + "description": "Distinct containers/nodes/services available in the queried scope, for\nthe filter dropdowns. Populated on the first page (no cursor)." + }, + "lines": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LogSearchLine" + } + }, + "next_cursor": { + "type": [ + "string", + "null" + ] + }, + "search_mode": { + "$ref": "#/components/schemas/SearchMode" + }, + "total_scanned": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + }, + "SearchMode": { + "type": "string", + "description": "Search execution mode", + "enum": [ + "index", + "archive" + ] + }, + "Seasonality": { + "type": "string", + "description": "Seasonality model for an anomaly baseline.", + "enum": [ + "none", + "hourly", + "daily", + "weekly" + ] + }, + "SecretResponse": { + "type": "object", + "required": [ + "id", + "name", + "secret_type", + "value", + "created_at", + "updated_at" + ], + "properties": { + "created_at": { + "type": "string" + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "id": { + "type": "integer", + "format": "int32" + }, + "mount_path": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": "string" + }, + "secret_type": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "value": { + "type": "string", + "description": "Always masked in responses" + } + } + }, + "SecurityConfig": { + "type": "object", + "description": "Security configuration for projects and environments\n\nThis configuration can be set at three levels:\n1. Global (in settings table) - applies to all projects\n2. Project level - overrides global settings for specific project\n3. Environment level - overrides project settings for specific environment\n\nThe inheritance chain: Environment > Project > Global", + "properties": { + "attackMode": { + "type": [ + "string", + "null" + ], + "description": "Attack mode configuration (future: \"off\", \"challenge\", \"block\")\nPlaceholder for DDoS protection, bot detection, etc." + }, + "challengeConfig": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/ChallengeConfig", + "description": "Challenge configuration (future: CAPTCHA, JS challenge, etc.)" + } + ] + }, + "enabled": { + "type": [ + "boolean", + "null" + ], + "description": "Enable/disable security features at this level\nIf None, inherits from parent level" + }, + "geoRestrictions": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/GeoRestrictionsConfig", + "description": "Geographic restrictions (future: country blocking, etc.)" + } + ] + }, + "headers": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/SecurityHeadersConfig", + "description": "Security headers configuration" + } + ] + }, + "passwordProtection": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/PasswordProtectionConfig", + "description": "Password protection: shows an HTML password form before allowing access" + } + ] + }, + "rateLimiting": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/RateLimitConfig", + "description": "Rate limiting configuration" + } + ] + } + } + }, + "SecurityHeadersConfig": { + "type": "object", + "description": "Security headers configuration (subset of global SecurityHeadersSettings)", + "properties": { + "contentSecurityPolicy": { + "type": [ + "string", + "null" + ], + "description": "Custom CSP (only used if preset is \"custom\")" + }, + "preset": { + "type": [ + "string", + "null" + ], + "description": "Use a preset: \"strict\", \"moderate\", \"permissive\", \"disabled\", \"custom\"" + }, + "referrerPolicy": { + "type": [ + "string", + "null" + ], + "description": "Referrer-Policy override" + }, + "strictTransportSecurity": { + "type": [ + "string", + "null" + ], + "description": "HSTS override" + }, + "xFrameOptions": { + "type": [ + "string", + "null" + ], + "description": "X-Frame-Options override" + } + } + }, + "SecurityHeadersSettings": { + "type": "object", + "properties": { + "content_security_policy": { + "type": [ + "string", + "null" + ], + "default": "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'self'" + }, + "enabled": { + "type": "boolean", + "default": false + }, + "permissions_policy": { + "type": [ + "string", + "null" + ], + "default": "geolocation=(), microphone=(), camera=()" + }, + "preset": { + "type": "string", + "default": "moderate" + }, + "referrer_policy": { + "type": "string", + "default": "strict-origin-when-cross-origin" + }, + "strict_transport_security": { + "type": "string", + "default": "max-age=31536000; includeSubDomains" + }, + "x_content_type_options": { + "type": "string", + "default": "nosniff" + }, + "x_frame_options": { + "type": "string", + "default": "SAMEORIGIN" + }, + "x_xss_protection": { + "type": "string", + "default": "1; mode=block" + } + } + }, + "SendEmailRequestBody": { + "type": "object", + "required": [ + "from", + "to", + "subject" + ], + "properties": { + "bcc": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + }, + "description": "BCC recipients" + }, + "cc": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + }, + "description": "CC recipients" + }, + "from": { + "type": "string", + "description": "Sender email address (domain will be auto-extracted for lookup)", + "example": "hello@updates.example.com" + }, + "from_name": { + "type": [ + "string", + "null" + ], + "description": "Sender display name", + "example": "My App" + }, + "headers": { + "type": [ + "object", + "null" + ], + "description": "Custom headers", + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + } + }, + "html": { + "type": [ + "string", + "null" + ], + "description": "HTML body content", + "example": "

    Hello World

    " + }, + "reply_to": { + "type": [ + "string", + "null" + ], + "description": "Reply-to address" + }, + "subject": { + "type": "string", + "description": "Email subject", + "example": "Welcome to our platform!" + }, + "tags": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + }, + "description": "Tags for categorization", + "example": [ + "welcome", + "onboarding" + ] + }, + "text": { + "type": [ + "string", + "null" + ], + "description": "Plain text body content", + "example": "Hello World" + }, + "to": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Recipient email addresses", + "example": [ + "user@example.com" + ] + }, + "track_clicks": { + "type": [ + "boolean", + "null" + ], + "description": "Enable click tracking (link rewriting). Defaults to false." + }, + "track_opens": { + "type": [ + "boolean", + "null" + ], + "description": "Enable open tracking (tracking pixel injection). Defaults to false." + } + } + }, + "SendEmailResponseBody": { + "type": "object", + "required": [ + "id", + "status" + ], + "properties": { + "id": { + "type": "string", + "description": "Email ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "provider_message_id": { + "type": [ + "string", + "null" + ], + "description": "Provider message ID" + }, + "status": { + "type": "string", + "description": "Email status", + "example": "sent" + } + } + }, + "SendMessageRequest": { + "type": "object", + "required": [ + "content" + ], + "properties": { + "content": { + "type": "string" + }, + "page_context": { + "type": [ + "string", + "null" + ], + "description": "Optional, client-supplied description of the page/entity the user is\ncurrently viewing (e.g. a trace in a project). Injected into the model's\nview of this turn only \u2014 never stored or shown in history. Capped server\nside; oversized values are ignored rather than rejected." + } + } + }, + "SensitiveConfigValueResponse": { + "type": "object", + "required": [ + "value" + ], + "properties": { + "value": { + "type": "string" + } + } + }, + "SensitiveMcpConfigValueResponse": { + "type": "object", + "required": [ + "value" + ], + "properties": { + "value": { + "type": "string" + } + } + }, + "SensitiveValueResponse": { + "type": "object", + "required": [ + "value" + ], + "properties": { + "value": { + "type": "string" + } + } + }, + "SentryChunkUploadResponse": { + "type": "object", + "required": [ + "url", + "chunkSize", + "chunksPerRequest", + "maxFileSize", + "maxRequestSize", + "concurrency", + "hashAlgorithm", + "compression", + "accept" + ], + "properties": { + "accept": { + "type": "array", + "items": { + "type": "string" + } + }, + "chunkSize": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "chunksPerRequest": { + "type": "integer", + "format": "int32", + "minimum": 0 + }, + "compression": { + "type": "array", + "items": { + "type": "string" + } + }, + "concurrency": { + "type": "integer", + "format": "int32", + "minimum": 0 + }, + "hashAlgorithm": { + "type": "string" + }, + "maxFileSize": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "maxRequestSize": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "url": { + "type": "string" + } + } + }, + "SentryCreateReleaseRequest": { + "type": "object", + "required": [ + "version" + ], + "properties": { + "projects": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Project slugs this release belongs to" + }, + "version": { + "type": "string", + "description": "Release version identifier" + } + } + }, + "SentryEventRequest": { + "type": "object", + "properties": { + "event_id": { + "type": [ + "string", + "null" + ] + }, + "message": { + "type": [ + "string", + "null" + ] + }, + "platform": { + "type": [ + "string", + "null" + ] + }, + "timestamp": { + "type": [ + "string", + "null" + ] + } + } + }, + "SentryEventResponse": { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "string" + } + } + }, + "SentryReleaseFileResponse": { + "type": "object", + "required": [ + "id", + "name", + "headers", + "size", + "sha1", + "dateCreated" + ], + "properties": { + "dateCreated": { + "type": "string" + }, + "dist": { + "type": [ + "string", + "null" + ] + }, + "headers": {}, + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "sha1": { + "type": "string" + }, + "size": { + "type": "integer", + "format": "int64" + } + } + }, + "SentryReleaseProjectRef": { + "type": "object", + "required": [ + "name", + "slug" + ], + "properties": { + "name": { + "type": "string" + }, + "slug": { + "type": "string" + } + } + }, + "SentryReleaseResponse": { + "type": "object", + "required": [ + "version", + "dateCreated", + "shortVersion", + "projects" + ], + "properties": { + "dateCreated": { + "type": "string" + }, + "dateReleased": { + "type": [ + "string", + "null" + ] + }, + "projects": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SentryReleaseProjectRef" + } + }, + "shortVersion": { + "type": "string" + }, + "version": { + "type": "string" + } + } + }, + "SeriesStateEntry": { + "type": "object", + "description": "One series' persisted state snapshot for a dynamic rule (ADR-026 follow-up):\nthe state after the latest tick, the value evaluated this tick, and the open\nalarm id (when firing). Serialized into the `series_states` jsonb column keyed\nby the human-readable [`series_label`]; the alert response decodes it back.", + "required": [ + "state", + "value" + ], + "properties": { + "alarm_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "The open alarm's id when the series is firing; `null` when ok." + }, + "state": { + "type": "string", + "description": "`firing` or `ok` for this series after the latest tick." + }, + "value": { + "type": "number", + "format": "double", + "description": "The value the rule evaluated for this series this tick." + } + } + }, + "ServiceAccessInfo": { + "type": "object", + "description": "Response containing information about how the service is being accessed", + "required": [ + "access_mode", + "can_create_domains" + ], + "properties": { + "access_mode": { + "type": "string", + "description": "Mode of access: \"local\", \"direct\", \"nat\", or \"cloudflare_tunnel\"" + }, + "can_create_domains": { + "type": "boolean", + "description": "Whether domain creation is allowed in this mode" + }, + "domain_creation_error": { + "type": [ + "string", + "null" + ], + "description": "Error message if domain creation is not allowed" + }, + "private_ip": { + "type": [ + "string", + "null" + ], + "description": "Server's private/local IP address (always returned if available)" + }, + "public_ip": { + "type": [ + "string", + "null" + ], + "description": "Server's public IP address (always returned if available)" + } + } + }, + "ServiceAction": { + "type": "string", + "description": "What to do with a service during migration", + "enum": [ + "create", + "link-external", + "skip" + ] + }, + "ServiceAlertRuleResponse": { + "type": "object", + "description": "Wire representation of a monitoring alert rule.\n\nRegistered under a domain-prefixed OpenAPI schema name to avoid colliding\nwith `temps-error-tracking`'s unrelated `AlertRuleResponse` (utoipa keys\nschemas by their bare struct name, so without `as = ...` the last crate to\nregister would silently shadow this one in the merged spec / generated SDK).", + "required": [ + "id", + "name", + "metric_name", + "threshold", + "comparator", + "severity", + "for_duration_secs", + "enabled" + ], + "properties": { + "comparator": { + "type": "string" + }, + "deployment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "enabled": { + "type": "boolean" + }, + "for_duration_secs": { + "type": "integer", + "format": "int32" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "metric_name": { + "type": "string" + }, + "name": { + "type": "string" + }, + "service_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "severity": { + "type": "string" + }, + "silenced_until": { + "type": [ + "string", + "null" + ] + }, + "threshold": { + "type": "number", + "format": "double" + } + } + }, + "ServiceBackupEntryResponse": { + "type": "object", + "description": "A single backup entry in the per-service backup list.", + "required": [ + "id", + "backup_id", + "name", + "state", + "backup_type", + "started_at", + "s3_location", + "compression_type", + "s3_source_id", + "s3_source_name", + "external_service_backup_id" + ], + "properties": { + "backup_id": { + "type": "string", + "description": "UUID string assigned at backup creation time." + }, + "backup_type": { + "type": "string", + "description": "Backup variant (e.g. \"full\", \"incremental\")." + }, + "compression_type": { + "type": "string", + "description": "Compression algorithm used (e.g. \"gzip\")." + }, + "error_message": { + "type": [ + "string", + "null" + ], + "description": "Engine-reported error message, populated when `state = \"failed\"`." + }, + "external_service_backup_id": { + "type": "integer", + "format": "int32", + "description": "Row ID from `external_service_backups`." + }, + "finished_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the backup finished, if known.", + "example": "2025-01-15T14:35:00Z" + }, + "id": { + "type": "integer", + "format": "int32", + "description": "Row ID from the `backups` table." + }, + "name": { + "type": "string", + "description": "Human-friendly display name." + }, + "s3_location": { + "type": "string", + "description": "Object key or `s3://` URL for the backup data." + }, + "s3_source_id": { + "type": "integer", + "format": "int32", + "description": "FK to `s3_sources.id`." + }, + "s3_source_name": { + "type": "string", + "description": "Human-readable name of the S3 source." + }, + "size_bytes": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Size of the backup in bytes, if available." + }, + "started_at": { + "type": "string", + "description": "ISO 8601 timestamp when the backup started.", + "example": "2025-01-15T14:30:00Z" + }, + "state": { + "type": "string", + "description": "Current state: \"completed\", \"running\", \"failed\"." + } + } + }, + "ServiceBackupListResponse": { + "type": "object", + "description": "Paginated list of backups for a specific external service.\n\nReturned by `GET /backups/external-services/{service_id}/backups`.", + "required": [ + "backups", + "total", + "page", + "page_size" + ], + "properties": { + "backups": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ServiceBackupEntryResponse" + }, + "description": "Backups belonging to this service, newest first." + }, + "page": { + "type": "integer", + "format": "int64", + "description": "Current page (1-based)." + }, + "page_size": { + "type": "integer", + "format": "int64", + "description": "Number of items per page." + }, + "total": { + "type": "integer", + "format": "int64", + "description": "Total number of backups for this service across all pages." + } + } + }, + "ServiceCreateAlertRuleRequest": { + "type": "object", + "description": "Request body for creating an alert rule on an external service.\n\nDomain-prefixed schema name \u2014 see [`AlertRuleResponse`] for why.", + "required": [ + "name", + "metric_name", + "threshold", + "comparator", + "severity" + ], + "properties": { + "comparator": { + "type": "string", + "description": "One of `>`, `<`, `>=`, `<=`." + }, + "enabled": { + "type": "boolean" + }, + "for_duration_secs": { + "type": "integer", + "format": "int32", + "description": "Seconds the breach must persist before the alarm fires (0 = immediate)." + }, + "metric_name": { + "type": "string" + }, + "name": { + "type": "string" + }, + "severity": { + "type": "string", + "description": "`\"warning\"` or `\"critical\"`." + }, + "threshold": { + "type": "number", + "format": "double" + } + } + }, + "ServiceHealthResponse": { + "type": "object", + "required": [ + "service_id", + "consecutive_failures", + "recent_checks" + ], + "properties": { + "consecutive_failures": { + "type": "integer", + "format": "int32", + "description": "Consecutive failed probes. Alert fires at 3." + }, + "last_checked_at": { + "type": [ + "string", + "null" + ] + }, + "last_error": { + "type": [ + "string", + "null" + ] + }, + "recent_checks": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HealthCheckEntryResponse" + }, + "description": "Most recent checks, newest-first (capped at `limit`)." + }, + "response_time_ms": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "service_id": { + "type": "integer", + "format": "int32" + }, + "status": { + "type": [ + "string", + "null" + ], + "description": "Current health. `null` if the service has not been probed yet.", + "example": "operational" + }, + "uptime_24h_percent": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Uptime percentage over the last 24 hours (0.0 \u2014 100.0).\n`null` when there is not enough history." + } + } + }, + "ServiceHealthStatusBatchResponse": { + "type": "object", + "required": [ + "statuses" + ], + "properties": { + "statuses": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ServiceHealthStatusEntryResponse" + } + } + } + }, + "ServiceHealthStatusEntryResponse": { + "type": "object", + "required": [ + "service_id", + "consecutive_failures" + ], + "properties": { + "consecutive_failures": { + "type": "integer", + "format": "int32" + }, + "last_checked_at": { + "type": [ + "string", + "null" + ] + }, + "service_id": { + "type": "integer", + "format": "int32" + }, + "status": { + "type": [ + "string", + "null" + ], + "description": "\"operational\" | \"degraded\" | \"down\". `null` when the service has not\nbeen probed yet.", + "example": "operational" + } + } + }, + "ServiceMemberInfo": { + "type": "object", + "description": "Public info about a cluster member.", + "required": [ + "id", + "role", + "container_name", + "status", + "ordinal" + ], + "properties": { + "compute_ip": { + "type": [ + "string", + "null" + ], + "description": "Container's IP on the `temps-overlay` multi-host network. Populated\nby the lifecycle hook (ADR-011 Phase 3); `None` on single-host\nclusters where the overlay isn't attached." + }, + "container_name": { + "type": "string" + }, + "hostname": { + "type": [ + "string", + "null" + ] + }, + "id": { + "type": "integer", + "format": "int32" + }, + "live_state": { + "type": [ + "string", + "null" + ], + "description": "Live FSM state from the pg_auto_failover monitor (`primary`,\n`secondary`, `catchingup`, `report_lsn`, \u2026). `None` when the\nmonitor is unreachable, the service is not a cluster, or the row\nis the monitor itself.\n\n**The UI must render the role badge from this field**, falling\nback to `role` only when `live_state` is null. `role` is now\nconfig-only (`monitor` or `replica`); flipping the badge to\n\"primary\" when the monitor elects a new one used to require a\nreconciler that lagged ~5s behind real failovers \u2014 and during\nthat window the UI showed two primaries. `live_state` is read\ndirectly from the monitor on every list, so it can never lag." + }, + "node_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "ordinal": { + "type": "integer", + "format": "int32" + }, + "port": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "provisioning_error": { + "type": [ + "string", + "null" + ], + "description": "Most recent provisioning failure message, when `status='failed'`.\nSet by the background task so the UI can show *why* the new\nreplica didn't come up." + }, + "provisioning_step": { + "type": [ + "string", + "null" + ], + "description": "Last-attempted phase of the async `add_cluster_member` background\ntask (e.g. `validating`, `provisioning_container`, `done`,\n`failed`). `None` for members not created through that flow \u2014\nthe UI falls back to the `status` column for those." + }, + "role": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "ServiceParameter": { + "type": "object", + "required": [ + "name", + "required", + "encrypted", + "description" + ], + "properties": { + "choices": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "default_value": { + "type": [ + "string", + "null" + ] + }, + "description": { + "type": "string" + }, + "encrypted": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "validation_pattern": { + "type": [ + "string", + "null" + ] + } + } + }, + "ServicePlan": { + "type": "object", + "description": "Plan for migrating a single service (database, cache, etc.)", + "required": [ + "name", + "service_type", + "action", + "action_description" + ], + "properties": { + "action": { + "$ref": "#/components/schemas/ServiceAction", + "description": "What to do with this service" + }, + "action_description": { + "type": "string", + "description": "Human-readable explanation of what this action means" + }, + "data_implications": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DataImplication" + }, + "description": "Data implications specific to this service" + }, + "env_var_mappings": { + "type": "object", + "description": "Environment variable key mappings: source_key -> temps_key\n\nFor example, Vercel's `POSTGRES_URL` might map to Temps' `DATABASE_URL`.\nBoth keys will be set during migration so the app works with either.", + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + } + }, + "name": { + "type": "string", + "description": "Human-readable service name" + }, + "parameters": { + "type": "object", + "description": "Parameters for creating the service in Temps", + "additionalProperties": {}, + "propertyNames": { + "type": "string" + } + }, + "service_type": { + "type": "string", + "description": "Service type (maps to temps-providers ServiceType)" + }, + "version": { + "type": [ + "string", + "null" + ], + "description": "Service version to create (e.g., \"16\" for Postgres 16)" + } + } + }, + "ServiceResourceLimits": { + "type": "object", + "description": "Optional cgroup resource limits applied to a service container.\n\nAll fields are `Option`: `None` means \"no limit\" (the kernel default),\nmatching Docker's behavior when the corresponding `HostConfig` field is\nleft at zero. Operators opt in to limits explicitly through the\n`PATCH /external-services/{id}/resources` endpoint or by writing the\n`resources` block into `ServiceConfig::parameters` at create time.\n\nThese map directly onto bollard fields:\n- `memory_mb` \u2192 `HostConfig.memory` (bytes)\n- `memory_swap_mb`\u2192 `HostConfig.memory_swap` (bytes; \u2265 memory)\n- `nano_cpus` \u2192 `HostConfig.nano_cpus` (1e9 = 1 full CPU)\n- `cpu_shares` \u2192 `HostConfig.cpu_shares` (relative weight, default 1024)\n- `shm_size_mb` \u2192 `HostConfig.shm_size` (bytes; default 64 MiB)\n\nIMPORTANT: enabling hard memory limits causes the kernel OOM killer to\nterminate the container when the working set exceeds the limit. The\ncontainer will restart (RestartPolicy::ALWAYS) but in-flight queries\nfail. Surface this clearly in any UI that lets users set limits.", + "properties": { + "cpu_shares": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Relative CPU weight (default 1024). Only used when `nano_cpus` is None." + }, + "memory_mb": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Hard memory limit in MiB. None = unlimited." + }, + "memory_swap_mb": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Memory + swap limit in MiB. None = unlimited.\nMUST be >= memory_mb when both are set; Docker rejects the request otherwise.\nSet equal to `memory_mb` to disable swap entirely." + }, + "nano_cpus": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "CPU quota in nano-cpus. 1_000_000_000 = 1 full CPU core. None = unlimited." + }, + "shm_size_mb": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Shared memory (/dev/shm) size in MiB. None = Docker default (64 MiB).\nMaps to HostConfig.shm_size (bytes). PostgreSQL uses /dev/shm for parallel\nquery workers and large work_mem; the 64 MiB default causes \"could not\nresize shared memory segment ... No space left on device\" under load.\nNOTE: shm_size is fixed at container-create time \u2014 Docker's live update\nAPI cannot change it, so changing this value recreates the container." + } + } + }, + "ServiceRuntimeReport": { + "type": "object", + "description": "Aggregate runtime info for an external service. For standalone services,\n`members` has exactly one entry. For clusters, one entry per member.", + "required": [ + "service_id", + "topology", + "members" + ], + "properties": { + "members": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ContainerRuntimeInfo" + } + }, + "service_id": { + "type": "integer", + "format": "int32" + }, + "topology": { + "type": "string" + } + } + }, + "ServiceStatsReport": { + "type": "object", + "required": [ + "service_id", + "topology", + "members" + ], + "properties": { + "members": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ContainerStatsSample" + } + }, + "service_id": { + "type": "integer", + "format": "int32" + }, + "topology": { + "type": "string" + } + } + }, + "ServiceTypeInfo": { + "type": "object", + "required": [ + "service_type", + "parameters" + ], + "properties": { + "parameters": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ServiceParameter" + }, + "example": "[{\"name\": \"host\", \"required\": true, \"encrypted\": false, \"description\": \"Database host\"}]" + }, + "service_type": { + "$ref": "#/components/schemas/ServiceTypeRoute" + } + } + }, + "ServiceTypeRoute": { + "type": "string", + "enum": [ + "mariadb", + "mongodb", + "postgres", + "redis", + "s3", + "kv", + "blob", + "rustfs", + "minio" + ] + }, + "ServiceUpdateAlertRuleRequest": { + "type": "object", + "description": "Request body for updating an existing alert rule.\n\nDomain-prefixed schema name \u2014 see [`AlertRuleResponse`] for why.", + "properties": { + "comparator": { + "type": [ + "string", + "null" + ] + }, + "enabled": { + "type": [ + "boolean", + "null" + ] + }, + "for_duration_secs": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "metric_name": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "severity": { + "type": [ + "string", + "null" + ] + }, + "threshold": { + "type": [ + "number", + "null" + ], + "format": "double" + } + } + }, + "SesCredentialsRequest": { + "type": "object", + "required": [ + "access_key_id", + "secret_access_key" + ], + "properties": { + "access_key_id": { + "type": "string", + "example": "AKIAIOSFODNN7EXAMPLE" + }, + "secret_access_key": { + "type": "string", + "example": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" + } + } + }, + "SessionDetails": { + "type": "object", + "required": [ + "session_id", + "visitor_id", + "started_at", + "duration_seconds", + "is_bounced", + "is_engaged", + "page_views" + ], + "properties": { + "duration_seconds": { + "type": "integer", + "format": "int64" + }, + "ended_at": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "example": "2024-01-01T00:00:00" + }, + "entry_path": { + "type": [ + "string", + "null" + ] + }, + "exit_path": { + "type": [ + "string", + "null" + ] + }, + "is_bounced": { + "type": "boolean" + }, + "is_engaged": { + "type": "boolean" + }, + "page_views": { + "type": "integer", + "format": "int64" + }, + "referrer": { + "type": [ + "string", + "null" + ] + }, + "session_id": { + "type": "integer", + "format": "int32" + }, + "started_at": { + "type": "string", + "format": "date-time", + "example": "2024-01-01T00:00:00" + }, + "visitor_id": { + "type": "string" + } + } + }, + "SessionDetailsQuery": { + "type": "object", + "required": [ + "project_id" + ], + "properties": { + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "project_id": { + "type": "integer", + "format": "int32" + } + } + }, + "SessionEvent": { + "type": "object", + "required": [ + "id", + "timestamp" + ], + "properties": { + "event_data": {}, + "event_name": { + "type": [ + "string", + "null" + ] + }, + "event_type": { + "type": [ + "string", + "null" + ] + }, + "id": { + "type": "integer", + "format": "int32" + }, + "page_title": { + "type": [ + "string", + "null" + ] + }, + "page_url": { + "type": [ + "string", + "null" + ] + }, + "timestamp": { + "type": "string" + } + } + }, + "SessionEventDto": { + "type": "object", + "required": [ + "id", + "session_id", + "data", + "timestamp" + ], + "properties": { + "data": {}, + "event_type": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "session_id": { + "type": "integer", + "format": "int32" + }, + "timestamp": { + "type": "integer", + "format": "int64" + } + } + }, + "SessionEventsQuery": { + "type": "object", + "required": [ + "project_id" + ], + "properties": { + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "project_id": { + "type": "integer", + "format": "int32" + } + } + }, + "SessionEventsResponse": { + "type": "object", + "required": [ + "session_id", + "events", + "total_count", + "offset", + "limit" + ], + "properties": { + "events": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SessionEvent" + } + }, + "limit": { + "type": "integer", + "format": "int32" + }, + "offset": { + "type": "integer", + "format": "int32" + }, + "session_id": { + "type": "integer", + "format": "int32" + }, + "total_count": { + "type": "integer", + "format": "int64" + } + } + }, + "SessionLogsQuery": { + "type": "object", + "required": [ + "project_id" + ], + "properties": { + "end_date": { + "type": [ + "string", + "null" + ], + "format": "date-time" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "limit": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "offset": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "sort_order": { + "type": [ + "string", + "null" + ] + }, + "start_date": { + "type": [ + "string", + "null" + ], + "format": "date-time" + }, + "visitor_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + } + }, + "SessionLogsResponse": { + "type": "object", + "required": [ + "session_id", + "logs", + "total_count", + "offset", + "limit" + ], + "properties": { + "limit": { + "type": "integer", + "format": "int32" + }, + "logs": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SessionRequestLog" + } + }, + "offset": { + "type": "integer", + "format": "int32" + }, + "session_id": { + "type": "integer", + "format": "int32" + }, + "total_count": { + "type": "integer", + "format": "int64" + } + } + }, + "SessionReplayEventsRequest": { + "type": "object", + "required": [ + "sessionId", + "events" + ], + "properties": { + "events": { + "type": "string" + }, + "sessionId": { + "type": "string" + } + } + }, + "SessionReplayInfoDto": { + "type": "object", + "required": [ + "id", + "visitor_id" + ], + "properties": { + "created_at": { + "type": [ + "string", + "null" + ] + }, + "duration": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "id": { + "type": "string" + }, + "language": { + "type": [ + "string", + "null" + ] + }, + "screen_height": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "screen_width": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "timezone": { + "type": [ + "string", + "null" + ] + }, + "url": { + "type": [ + "string", + "null" + ] + }, + "user_agent": { + "type": [ + "string", + "null" + ] + }, + "viewport_height": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "viewport_width": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "visitor_id": { + "type": "integer", + "format": "int32" + } + } + }, + "SessionReplayInitRequest": { + "type": "object", + "required": [ + "sessionId" + ], + "properties": { + "colorDepth": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "minimum": 0 + }, + "language": { + "type": [ + "string", + "null" + ] + }, + "screenHeight": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "minimum": 0 + }, + "screenWidth": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "minimum": 0 + }, + "sessionId": { + "type": "string" + }, + "timestamp": { + "type": [ + "string", + "null" + ] + }, + "timezone": { + "type": [ + "string", + "null" + ] + }, + "url": { + "type": [ + "string", + "null" + ] + }, + "userAgent": { + "type": [ + "string", + "null" + ] + }, + "viewportHeight": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "minimum": 0 + }, + "viewportWidth": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "minimum": 0 + } + } + }, + "SessionReplayInitResponse": { + "type": "object", + "required": [ + "session_id", + "message" + ], + "properties": { + "message": { + "type": "string" + }, + "session_id": { + "type": "string" + } + } + }, + "SessionReplayWithEventsDto": { + "type": "object", + "required": [ + "session", + "events" + ], + "properties": { + "events": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SessionEventDto" + } + }, + "session": { + "$ref": "#/components/schemas/SessionReplayWithVisitorDto" + } + } + }, + "SessionReplayWithVisitorDto": { + "type": "object", + "required": [ + "id", + "session_replay_id", + "visitor_id", + "visitor_uuid", + "visitor_project_id", + "visitor_environment_id", + "visitor_first_seen", + "visitor_last_seen", + "visitor_is_crawler" + ], + "properties": { + "browser": { + "type": [ + "string", + "null" + ] + }, + "browser_version": { + "type": [ + "string", + "null" + ] + }, + "created_at": { + "type": [ + "string", + "null" + ] + }, + "device_type": { + "type": [ + "string", + "null" + ] + }, + "duration": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "language": { + "type": [ + "string", + "null" + ] + }, + "operating_system": { + "type": [ + "string", + "null" + ] + }, + "operating_system_version": { + "type": [ + "string", + "null" + ] + }, + "screen_height": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "screen_width": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "session_replay_id": { + "type": "string" + }, + "timezone": { + "type": [ + "string", + "null" + ] + }, + "url": { + "type": [ + "string", + "null" + ] + }, + "user_agent": { + "type": [ + "string", + "null" + ] + }, + "viewport_height": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "viewport_width": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "visitor_city": { + "type": [ + "string", + "null" + ] + }, + "visitor_country": { + "type": [ + "string", + "null" + ] + }, + "visitor_country_code": { + "type": [ + "string", + "null" + ] + }, + "visitor_crawler_name": { + "type": [ + "string", + "null" + ] + }, + "visitor_custom_data": {}, + "visitor_environment_id": { + "type": "integer", + "format": "int32" + }, + "visitor_first_seen": { + "type": "string" + }, + "visitor_id": { + "type": "integer", + "format": "int32" + }, + "visitor_is_crawler": { + "type": "boolean" + }, + "visitor_last_seen": { + "type": "string" + }, + "visitor_project_id": { + "type": "integer", + "format": "int32" + }, + "visitor_region": { + "type": [ + "string", + "null" + ] + }, + "visitor_uuid": { + "type": "string" + } + } + }, + "SessionRequestLog": { + "type": "object", + "required": [ + "id", + "method", + "path", + "status_code", + "created_at" + ], + "properties": { + "created_at": { + "type": "string", + "format": "date-time", + "example": "2024-01-01T00:00:00" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "method": { + "type": "string" + }, + "path": { + "type": "string" + }, + "referrer": { + "type": [ + "string", + "null" + ] + }, + "request_headers": { + "type": [ + "string", + "null" + ] + }, + "response_headers": { + "type": [ + "string", + "null" + ] + }, + "response_time_ms": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "status_code": { + "type": "integer", + "format": "int32" + }, + "user_agent": { + "type": [ + "string", + "null" + ] + } + } + }, + "SessionSummary": { + "type": "object", + "required": [ + "session_id", + "started_at", + "duration_seconds", + "page_views", + "events_count", + "requests_count", + "is_bounced", + "is_engaged" + ], + "properties": { + "duration_seconds": { + "type": "integer", + "format": "int64" + }, + "ended_at": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "example": "2024-01-01T00:00:00" + }, + "entry_path": { + "type": [ + "string", + "null" + ] + }, + "events_count": { + "type": "integer", + "format": "int64" + }, + "exit_path": { + "type": [ + "string", + "null" + ] + }, + "is_bounced": { + "type": "boolean" + }, + "is_engaged": { + "type": "boolean" + }, + "page_views": { + "type": "integer", + "format": "int64" + }, + "referrer": { + "type": [ + "string", + "null" + ] + }, + "requests_count": { + "type": "integer", + "format": "int64" + }, + "session_id": { + "type": "integer", + "format": "int32" + }, + "started_at": { + "type": "string", + "format": "date-time", + "example": "2024-01-01T00:00:00" + } + } + }, + "SetFlagEnvironmentRequest": { + "type": "object", + "properties": { + "enabled": { + "type": [ + "boolean", + "null" + ], + "description": "The kill switch. `false` makes the flag serve its default regardless of\nany override \u2014 and, once targeting exists, regardless of any rule." + }, + "value": { + "description": "Tri-state: absent leaves the override, `null` clears it (inherit the\nflag default), anything else sets it. Must match `value_type`." + } + } + }, + "SetPreviewPasswordBody": { + "type": "object", + "required": [ + "password" + ], + "properties": { + "password": { + "type": "string", + "description": "Plaintext password to protect the sandbox's preview URLs. Hashed\nserver-side with argon2id \u2014 we never persist or echo this back.\nMust be between 8 and 256 characters." + } + } + }, + "SetPreviewPasswordResponse": { + "type": "object", + "required": [ + "preview_password_hint" + ], + "properties": { + "preview_password_hint": { + "type": "string", + "description": "Last 4 chars of the password we just stored. Surface in the UI so\nusers can confirm which password is live without re-entering it." + } + } + }, + "SetRequest": { + "type": "object", + "description": "Request to set a value", + "required": [ + "key", + "value" + ], + "properties": { + "ex": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Expire in seconds", + "example": 3600 + }, + "key": { + "type": "string", + "description": "The key to set", + "example": "user:123" + }, + "nx": { + "type": "boolean", + "description": "Only set if key does not exist" + }, + "project_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Project ID (required for API key/session auth, optional for deployment tokens)", + "example": 1 + }, + "px": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Expire in milliseconds" + }, + "value": { + "description": "The value to store (can be any JSON value)" + }, + "xx": { + "type": "boolean", + "description": "Only set if key exists" + } + } + }, + "SetResponse": { + "type": "object", + "description": "Response for set operation", + "required": [ + "result" + ], + "properties": { + "result": { + "type": "string", + "description": "Always \"OK\" on success", + "example": "OK" + } + } + }, + "SettingsUpdateResponse": { + "type": "object", + "description": "Response for successful settings update", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } + }, + "SetupDnsChallengeRequest": { + "type": "object", + "description": "Request to setup DNS challenge records using a configured DNS provider", + "required": [ + "dns_provider_id" + ], + "properties": { + "dns_provider_id": { + "type": "integer", + "format": "int32", + "description": "The ID of the DNS provider to use for creating the TXT records" + } + } + }, + "SetupDnsChallengeResponse": { + "type": "object", + "description": "Response from DNS challenge setup operation", + "required": [ + "success", + "records_created", + "total_records", + "results", + "message" + ], + "properties": { + "message": { + "type": "string", + "description": "Human-readable summary message" + }, + "records_created": { + "type": "integer", + "format": "int32", + "description": "Number of TXT records that were successfully created", + "minimum": 0 + }, + "results": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DnsChallengeRecordResult" + }, + "description": "Results for each individual TXT record" + }, + "success": { + "type": "boolean", + "description": "Overall success status (true if all records were created)" + }, + "total_records": { + "type": "integer", + "format": "int32", + "description": "Total number of TXT records required for the challenge", + "minimum": 0 + } + } + }, + "SetupDnsRequest": { + "type": "object", + "description": "Request to setup DNS records using a configured DNS provider", + "required": [ + "dns_provider_id" + ], + "properties": { + "dns_provider_id": { + "type": "integer", + "format": "int32", + "description": "The ID of the DNS provider to use for creating records" + } + } + }, + "SetupDnsResponse": { + "type": "object", + "description": "Response from DNS setup operation", + "required": [ + "success", + "records_created", + "total_records", + "results", + "message" + ], + "properties": { + "message": { + "type": "string", + "description": "Human-readable summary message" + }, + "records_created": { + "type": "integer", + "format": "int32", + "description": "Number of records that were successfully created", + "minimum": 0 + }, + "results": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DnsRecordSetupResult" + }, + "description": "Results for each individual record" + }, + "success": { + "type": "boolean", + "description": "Overall success status" + }, + "total_records": { + "type": "integer", + "format": "int32", + "description": "Total number of records attempted", + "minimum": 0 + } + } + }, + "SiblingRef": { + "type": "object", + "description": "A sibling project that shares the same `trace_id` and has opted in to\ncross-project trace sharing (`cross_project_trace_sharing = TRUE`).\n\nReturned by `CrossProjectTraceService::find_sibling_projects` and exposed\nby the Phase 1 `GET /otel/traces/cross-project/{trace_id}` endpoint.", + "required": [ + "project_id", + "project_name", + "project_slug", + "first_seen" + ], + "properties": { + "first_seen": { + "type": "string", + "format": "date-time" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "project_name": { + "type": "string" + }, + "project_slug": { + "type": "string", + "description": "URL slug used to link into the sibling project's single-project trace view." + } + } + }, + "SkillDefinitionResponse": { + "type": "object", + "required": [ + "id", + "slug", + "name", + "content", + "has_archive", + "created_at", + "updated_at" + ], + "properties": { + "content": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "has_archive": { + "type": "boolean" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "project_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "slug": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + } + }, + "SlackConfig": { + "type": "object", + "required": [ + "webhook_url" + ], + "properties": { + "channel": { + "type": [ + "string", + "null" + ] + }, + "webhook_url": { + "type": "string" + } + } + }, + "SlowQueriesResponse": { + "type": "object", + "description": "Response envelope for the slow-queries list endpoint.", + "required": [ + "queries", + "page", + "page_size", + "total_count" + ], + "properties": { + "page": { + "type": "integer", + "format": "int32", + "description": "Current page number (1-based).", + "minimum": 0 + }, + "page_size": { + "type": "integer", + "format": "int32", + "description": "Number of rows per page used for this request.", + "minimum": 0 + }, + "queries": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SlowQueryRow" + }, + "description": "Ordered list of query stats, slowest first by mean_exec_time_ms." + }, + "total_count": { + "type": "integer", + "format": "int64", + "description": "Total number of qualifying rows across all pages.", + "minimum": 0 + } + } + }, + "SlowQueryRow": { + "type": "object", + "description": "A single entry from `pg_stat_statements`, representing one normalized\nquery fingerprint and its aggregate execution stats.", + "required": [ + "query", + "database", + "calls", + "total_exec_time_ms", + "mean_exec_time_ms", + "rows" + ], + "properties": { + "cache_hit_ratio": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Shared block cache hit ratio (0.0\u20131.0).\n`None` when total block accesses are zero (e.g. function-only queries)." + }, + "calls": { + "type": "integer", + "format": "int64", + "description": "Number of times this query was executed." + }, + "database": { + "type": "string", + "description": "Name of the database this query ran against. `(dropped database)`\nwhen the originating database no longer exists but\n`pg_stat_statements` still holds stats for it." + }, + "mean_exec_time_ms": { + "type": "number", + "format": "double", + "description": "Average wall-clock time per execution, in milliseconds." + }, + "query": { + "type": "string", + "description": "Normalized query text (parameter literals replaced with `$N`)." + }, + "rows": { + "type": "integer", + "format": "int64", + "description": "Total number of rows returned or affected." + }, + "total_exec_time_ms": { + "type": "number", + "format": "double", + "description": "Total wall-clock time spent executing this query, in milliseconds." + } + } + }, + "SmartFilter": { + "oneOf": [ + { + "type": "object", + "description": "Match specific page path", + "required": [ + "value", + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "page_path" + ] + }, + "value": { + "type": "string", + "description": "Match specific page path" + } + } + }, + { + "type": "object", + "description": "Match specific hostname", + "required": [ + "value", + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "hostname" + ] + }, + "value": { + "type": "string", + "description": "Match specific hostname" + } + } + }, + { + "type": "object", + "description": "Match UTM source", + "required": [ + "value", + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "utm_source" + ] + }, + "value": { + "type": "string", + "description": "Match UTM source" + } + } + }, + { + "type": "object", + "description": "Match UTM campaign", + "required": [ + "value", + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "utm_campaign" + ] + }, + "value": { + "type": "string", + "description": "Match UTM campaign" + } + } + }, + { + "type": "object", + "description": "Match UTM medium", + "required": [ + "value", + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "utm_medium" + ] + }, + "value": { + "type": "string", + "description": "Match UTM medium" + } + } + }, + { + "type": "object", + "description": "Match referrer hostname", + "required": [ + "value", + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "referrer_hostname" + ] + }, + "value": { + "type": "string", + "description": "Match referrer hostname" + } + } + }, + { + "type": "object", + "description": "Match specific channel (organic, paid, direct, referral, etc.)", + "required": [ + "value", + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "channel" + ] + }, + "value": { + "type": "string", + "description": "Match specific channel (organic, paid, direct, referral, etc.)" + } + } + }, + { + "type": "object", + "description": "Match device type (mobile, desktop, tablet)", + "required": [ + "value", + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "device_type" + ] + }, + "value": { + "type": "string", + "description": "Match device type (mobile, desktop, tablet)" + } + } + }, + { + "type": "object", + "description": "Match browser", + "required": [ + "value", + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "browser" + ] + }, + "value": { + "type": "string", + "description": "Match browser" + } + } + }, + { + "type": "object", + "description": "Match operating system", + "required": [ + "value", + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "operating_system" + ] + }, + "value": { + "type": "string", + "description": "Match operating system" + } + } + }, + { + "type": "object", + "description": "Match language", + "required": [ + "value", + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "language" + ] + }, + "value": { + "type": "string", + "description": "Match language" + } + } + }, + { + "type": "object", + "description": "Match custom event_data by JSON path\nFormat: {\"path\": \"user.plan\", \"value\": \"premium\"}\nThis will match events where event_data->'user'->>'plan' = 'premium'", + "required": [ + "value", + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "custom_data" + ] + }, + "value": { + "type": "object", + "description": "Match custom event_data by JSON path\nFormat: {\"path\": \"user.plan\", \"value\": \"premium\"}\nThis will match events where event_data->'user'->>'plan' = 'premium'", + "required": [ + "path", + "value" + ], + "properties": { + "path": { + "type": "string" + }, + "value": { + "type": "string" + } + } + } + } + } + ], + "description": "Smart filter presets for common funnel patterns" + }, + "SmokeTestResponse": { + "type": "object", + "required": [ + "passed", + "environment", + "cli_installed", + "cli_authenticated" + ], + "properties": { + "auth_info": { + "type": [ + "string", + "null" + ], + "description": "Auth email / method" + }, + "cli_authenticated": { + "type": "boolean", + "description": "Claude CLI authenticated?" + }, + "cli_installed": { + "type": "boolean", + "description": "Claude CLI installed?" + }, + "cli_version": { + "type": [ + "string", + "null" + ], + "description": "Claude CLI version" + }, + "detail": { + "type": [ + "string", + "null" + ], + "description": "Full output for debugging" + }, + "environment": { + "type": "string", + "description": "Where the test ran: \"host\" or \"sandbox\"" + }, + "passed": { + "type": "boolean", + "description": "Whether the smoke test passed" + }, + "setup_hint": { + "type": [ + "string", + "null" + ], + "description": "What the user needs to do if the test failed" + } + } + }, + "SmtpCredentialsRequest": { + "type": "object", + "description": "Generic SMTP credentials request body.\n\nWorks with any SMTP relay \u2014 AWS SES SMTP endpoints, Sendgrid, Mailgun,\nPostmark, or a self-hosted Postfix. Use this when you only have SMTP\ncredentials (i.e. you cannot create identities via the upstream API).", + "required": [ + "host", + "port" + ], + "properties": { + "accept_invalid_certs": { + "type": "boolean", + "description": "Accept self-signed certificates. Only safe for local testing." + }, + "encryption": { + "$ref": "#/components/schemas/SmtpEncryptionRoute", + "description": "TLS mode. Defaults to STARTTLS." + }, + "host": { + "type": "string", + "description": "SMTP host, e.g. `email-smtp.eu-west-1.amazonaws.com`.", + "example": "email-smtp.eu-west-1.amazonaws.com" + }, + "password": { + "type": [ + "string", + "null" + ], + "description": "SMTP password / API token. Required when `username` is set." + }, + "port": { + "type": "integer", + "format": "int32", + "description": "SMTP port (587 for STARTTLS, 465 for implicit TLS, 25/1025 for plain).", + "example": 587, + "minimum": 0 + }, + "username": { + "type": [ + "string", + "null" + ], + "description": "SMTP username. Leave empty for unauthenticated relays.", + "example": "AKIAIOSFODNN7EXAMPLE" + } + } + }, + "SmtpEncryptionRoute": { + "type": "string", + "description": "TLS mode for the SMTP relay.", + "enum": [ + "starttls", + "tls", + "none" + ] + }, + "SmtpResult": { + "type": "object", + "description": "SMTP validation result", + "required": [ + "can_connect_smtp", + "has_full_inbox", + "is_catch_all", + "is_deliverable", + "is_disabled" + ], + "properties": { + "can_connect_smtp": { + "type": "boolean", + "description": "Whether we could connect to the SMTP server" + }, + "error": { + "type": [ + "string", + "null" + ], + "description": "Error message if SMTP check failed" + }, + "has_full_inbox": { + "type": "boolean", + "description": "Whether the mailbox appears to have a full inbox" + }, + "is_catch_all": { + "type": "boolean", + "description": "Whether this is a catch-all domain" + }, + "is_deliverable": { + "type": "boolean", + "description": "Whether the email is deliverable" + }, + "is_disabled": { + "type": "boolean", + "description": "Whether the mailbox is disabled" + } + } + }, + "SourceArchiveUpload": { + "type": "object", + "required": [ + "file" + ], + "properties": { + "file": { + "type": "string", + "format": "binary" + } + } + }, + "SourceBackupEntry": { + "type": "object", + "description": "Entry in the source backup index. Covers both DB-tracked backups\n(have a row in `backups`) and S3-scan discoveries (raw S3 objects with\nno DB row \u2014 used for disaster-recovery from another Temps instance).", + "required": [ + "id", + "backup_id", + "name", + "backup_type", + "created_at", + "location", + "metadata_location", + "source", + "state" + ], + "properties": { + "backup_id": { + "type": "string", + "description": "UUID identifier from the DB row. Empty for S3-scan entries.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "backup_type": { + "type": "string", + "description": "Backup variant as recorded by the backup pipeline (e.g. \"full\").", + "example": "full" + }, + "created_at": { + "type": "string", + "description": "When the backup was created. For S3-scan entries this is the\nobject's LastModified time.", + "example": "2024-01-15T14:30:00.123Z" + }, + "engine": { + "type": [ + "string", + "null" + ], + "description": "Engine that produced the backup (\"postgres\", \"redis\", \"mongodb\",\n\"s3\", \"rustfs\"). Used by the UI to mark engine-compat with the\ntarget service.", + "example": "postgres" + }, + "format": { + "type": [ + "string", + "null" + ], + "description": "Storage format: \"walg\" for continuous-archive (PITR-capable),\n\"pg_dump\" for point-in-time dumps, \"\" for non-postgres.", + "example": "walg" + }, + "id": { + "type": "integer", + "format": "int32", + "description": "DB row id. Zero for S3-scan entries that have no DB row.", + "example": 1 + }, + "location": { + "type": "string", + "description": "Raw S3 URL / key where the backup sits. For Postgres WAL-G backups\nthis starts with `s3://`; for pg_dump-style backups it's the\nrelative object key.", + "example": "s3://bucket/external_services/postgres/svc-name/walg" + }, + "metadata_location": { + "type": "string", + "description": "Sidecar metadata.json location, if any. Empty when none.", + "example": "" + }, + "name": { + "type": "string", + "description": "Human-friendly display name (\"postgres backup (svc-name)\" for DB\nrows, or a synthesized label derived from the S3 path for scans).", + "example": "postgres backup (postgres-n4ea)" + }, + "origin_service_name": { + "type": [ + "string", + "null" + ], + "description": "Name of the service that produced the backup. For S3-scan entries\nthis is parsed from the S3 path.", + "example": "postgres-n4ea" + }, + "size_bytes": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Size of the backup in bytes, if known.", + "example": 1024000 + }, + "source": { + "type": "string", + "description": "Provenance: \"db\" for rows in this Temps, \"s3_scan\" for objects\ndiscovered by the S3 bucket walk (e.g., backups made by another\nTemps instance).", + "example": "db" + }, + "state": { + "type": "string", + "description": "Observed state (\"completed\", \"running\", \"failed\") \u2014 DB only.\nEmpty string for S3-scan entries.", + "example": "completed" + } + } + }, + "SourceBackupIndexResponse": { + "type": "object", + "description": "Response type for source backup index", + "required": [ + "backups", + "last_updated" + ], + "properties": { + "backups": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SourceBackupEntry" + }, + "description": "List of backups in the source" + }, + "last_updated": { + "type": "string", + "description": "When the index was last updated", + "example": "2024-01-15T14:30:00.123Z" + } + } + }, + "SourceBody": { + "oneOf": [ + { + "type": "object", + "required": [ + "url", + "type" + ], + "properties": { + "depth": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "minimum": 0 + }, + "git_connection_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "password": { + "type": [ + "string", + "null" + ] + }, + "revision": { + "type": [ + "string", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "git" + ] + }, + "url": { + "type": "string" + }, + "username": { + "type": [ + "string", + "null" + ] + } + } + }, + { + "type": "object", + "required": [ + "url", + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "tarball" + ] + }, + "url": { + "type": "string" + } + } + } + ], + "description": "Initial content to seed into the sandbox work dir. Mirrors the\n`@vercel/sandbox` `source` option. `type` is one of:\n- `git` \u2014 clone `url`; optionally check out `revision`\n- `tarball` \u2014 download `url` (must be tar or tar.gz) and extract\n\nFor private git repos, pass credentials one of two ways:\n1. **Inline (SDK-compatible):** `username` + `password`. GitHub\n tokens use `username: \"x-access-token\"`.\n2. **Stored connection (temps-native):** `git_connection_id`\n references a row in the caller's git provider connections. Temps\n resolves the token server-side and injects it safely.\n\n`git_connection_id` is mutually exclusive with `username`/`password`." + }, + "SourceFileListResponse": { + "type": "object", + "required": [ + "source_files", + "total" + ], + "properties": { + "source_files": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SourceFileResponse" + } + }, + "total": { + "type": "integer", + "minimum": 0 + } + } + }, + "SourceFileResponse": { + "type": "object", + "required": [ + "id", + "project_id", + "release", + "file_path", + "size_bytes", + "created_at" + ], + "properties": { + "checksum": { + "type": [ + "string", + "null" + ] + }, + "created_at": { + "type": "string", + "example": "2025-10-12T12:15:47.609192Z" + }, + "file_path": { + "type": "string" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "release": { + "type": "string" + }, + "size_bytes": { + "type": "integer", + "format": "int64" + } + } + }, + "SourceMapListResponse": { + "type": "object", + "required": [ + "source_maps", + "total" + ], + "properties": { + "source_maps": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SourceMapResponse" + } + }, + "total": { + "type": "integer", + "minimum": 0 + } + } + }, + "SourceMapResponse": { + "type": "object", + "required": [ + "id", + "project_id", + "release", + "file_path", + "size_bytes", + "created_at" + ], + "properties": { + "checksum": { + "type": [ + "string", + "null" + ] + }, + "created_at": { + "type": "string", + "example": "2025-10-12T12:15:47.609192Z" + }, + "dist": { + "type": [ + "string", + "null" + ] + }, + "file_path": { + "type": "string" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "release": { + "type": "string" + }, + "size_bytes": { + "type": "integer", + "format": "int64" + } + } + }, + "SourceType": { + "type": "string", + "description": "Source type for project deployments\n\nDetermines where the deployment artifacts come from:\n- `Git`: Source code from a Git repository (traditional flow)\n- `DockerImage`: Pre-built Docker image from external registry\n- `StaticFiles`: Pre-built static files uploaded as a bundle\n- `UploadedSource`: Source archive uploaded without a Git repository\n- `Manual`: Flexible type that accepts any deployment method", + "enum": [ + "git", + "docker_image", + "static_files", + "uploaded_source", + "manual" + ] + }, + "SpanEvent": { + "type": "object", + "description": "A span event (log-like annotation on a span).", + "required": [ + "timestamp", + "name", + "attributes" + ], + "properties": { + "attributes": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + } + }, + "name": { + "type": "string" + }, + "timestamp": { + "type": "string", + "format": "date-time" + } + } + }, + "SpanKind": { + "type": "string", + "description": "Span kind.", + "enum": [ + "UNSPECIFIED", + "INTERNAL", + "SERVER", + "CLIENT", + "PRODUCER", + "CONSUMER" + ] + }, + "SpanRecord": { + "type": "object", + "description": "A single trace span ready for storage.", + "required": [ + "project_id", + "resource", + "trace_id", + "span_id", + "name", + "kind", + "start_time", + "end_time", + "duration_ms", + "status_code", + "status_message", + "attributes", + "events" + ], + "properties": { + "attributes": { + "type": "object", + "description": "Raw key/value pairs exactly as reported by the instrumenting library.\nNumeric values are NOT guaranteed to share `duration_ms`'s unit \u2014 they\nmay be seconds, milliseconds, microseconds, or nanoseconds depending on\nthe exporter's own convention, and the unit is not labeled here.", + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + } + }, + "deployment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "duration_ms": { + "type": "number", + "format": "double", + "description": "Span duration in milliseconds. The only field on this struct guaranteed\nto be in milliseconds." + }, + "end_time": { + "type": "string", + "format": "date-time" + }, + "events": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SpanEvent" + } + }, + "kind": { + "$ref": "#/components/schemas/SpanKind" + }, + "name": { + "type": "string" + }, + "parent_span_id": { + "type": [ + "string", + "null" + ] + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "resource": { + "$ref": "#/components/schemas/ResourceInfo" + }, + "span_id": { + "type": "string" + }, + "start_time": { + "type": "string", + "format": "date-time" + }, + "status_code": { + "$ref": "#/components/schemas/SpanStatusCode" + }, + "status_message": { + "type": "string" + }, + "trace_id": { + "type": "string" + } + } + }, + "SpanRow": { + "type": "object", + "required": [ + "id", + "ts", + "trace_id", + "span_id", + "service", + "operation", + "attributes", + "attributes_truncated" + ], + "properties": { + "attributes": {}, + "attributes_truncated": { + "type": "boolean" + }, + "deployment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "duration_ms": { + "type": [ + "number", + "null" + ], + "format": "double" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "id": { + "type": "string" + }, + "operation": { + "type": "string" + }, + "parent_span_id": { + "type": [ + "string", + "null" + ] + }, + "service": { + "type": "string" + }, + "span_id": { + "type": "string" + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "trace_id": { + "type": "string" + }, + "ts": { + "type": "string", + "format": "date-time" + } + } + }, + "SpanStatusCode": { + "type": "string", + "description": "Span status code.", + "enum": [ + "UNSET", + "OK", + "ERROR" + ] + }, + "SpeedMetricsPayload": { + "type": "object", + "description": "Speed metrics payload for recording web vitals", + "properties": { + "cls": { + "type": [ + "number", + "null" + ], + "format": "float", + "description": "Cumulative Layout Shift (score)" + }, + "fcp": { + "type": [ + "number", + "null" + ], + "format": "float", + "description": "First Contentful Paint (milliseconds)" + }, + "fid": { + "type": [ + "number", + "null" + ], + "format": "float", + "description": "First Input Delay (milliseconds)" + }, + "inp": { + "type": [ + "number", + "null" + ], + "format": "float", + "description": "Interaction to Next Paint (milliseconds)" + }, + "language": { + "type": [ + "string", + "null" + ], + "description": "Browser language" + }, + "lcp": { + "type": [ + "number", + "null" + ], + "format": "float", + "description": "Largest Contentful Paint (milliseconds)" + }, + "pathname": { + "type": [ + "string", + "null" + ], + "description": "Page pathname" + }, + "query": { + "type": [ + "string", + "null" + ], + "description": "Query string" + }, + "screenHeight": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Screen height in pixels" + }, + "screenWidth": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Screen width in pixels" + }, + "ttfb": { + "type": [ + "number", + "null" + ], + "format": "float", + "description": "Time to First Byte (milliseconds)" + }, + "viewportHeight": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Viewport height in pixels" + }, + "viewportWidth": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Viewport width in pixels" + } + } + }, + "SpeedSegmentFilters": { + "type": "object", + "description": "Optional segment filters for the performance read endpoints, mirroring\nanalytics' `VisitorSegmentFilters`. Each filter narrows results to samples\nmatching the dimension value, so metrics can be scoped to e.g. one page,\none browser, or one country. Geographic filters resolve via\n`ip_geolocations`; the rest live directly on `performance_metrics`.", + "properties": { + "filter_browser": { + "type": [ + "string", + "null" + ], + "description": "Browser name (matches `performance_metrics.browser`)" + }, + "filter_city": { + "type": [ + "string", + "null" + ], + "description": "Geolocation city (matches `ip_geolocations.city`)" + }, + "filter_country": { + "type": [ + "string", + "null" + ], + "description": "Geolocation country (matches `ip_geolocations.country`)" + }, + "filter_operating_system": { + "type": [ + "string", + "null" + ], + "description": "Operating system (matches `performance_metrics.operating_system`)" + }, + "filter_path": { + "type": [ + "string", + "null" + ], + "description": "Page pathname (matches `performance_metrics.pathname`)" + }, + "filter_region": { + "type": [ + "string", + "null" + ], + "description": "Geolocation region (matches `ip_geolocations.region`)" + } + } + }, + "StaleSlot": { + "type": "object", + "required": [ + "slot_name", + "active", + "retained_bytes" + ], + "properties": { + "active": { + "type": "boolean" + }, + "retained_bytes": { + "type": "integer", + "format": "int64" + }, + "slot_name": { + "type": "string" + } + } + }, + "StartAnalysisRequest": { + "type": "object", + "required": [ + "error_group_id" + ], + "properties": { + "branch": { + "type": [ + "string", + "null" + ], + "description": "Branch to clone instead of the project's main branch." + }, + "error_group_id": { + "type": "integer", + "format": "int32" + }, + "max_turns": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Per-run turn cap applied to every phase (1\u2013200). Only enforced for\nCLIs with a turn flag (Claude Code). `None` uses the provider's\nconfigured defaults." + }, + "model": { + "type": [ + "string", + "null" + ], + "description": "Model id for the chosen provider. `None` uses the provider's saved\ndefault model." + }, + "provider": { + "type": [ + "string", + "null" + ], + "description": "AI provider id (\"claude_cli\", \"codex_cli\", \"opencode\"). `None` uses\nthe platform default provider." + }, + "user_context": { + "type": [ + "string", + "null" + ], + "description": "Free-text notes for the model (extra context about the error, retry\nguidance, constraints). Included verbatim in the analysis prompt." + } + } + }, + "StartPgUpgradeRequest": { + "type": "object", + "required": [ + "from_version", + "to_version", + "from_image", + "to_image" + ], + "properties": { + "from_image": { + "type": "string", + "example": "postgres:16-bookworm" + }, + "from_version": { + "type": "string", + "example": "16" + }, + "to_image": { + "type": "string", + "example": "postgres:17-bookworm" + }, + "to_version": { + "type": "string", + "example": "17" + } + } + }, + "StartRestoreRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/RestoreRequestMode", + "description": "Requested restore mode. See `RestoreRequestMode`." + }, + { + "type": "object", + "properties": { + "backup_engine": { + "type": [ + "string", + "null" + ], + "description": "Engine of the backup when specified by `backup_location`\n(\"postgres\", \"redis\", \"mongodb\", \"s3\"). Ignored when `backup_id`\nis used \u2014 we infer from the DB row." + }, + "backup_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "DB id of the backup to restore from. Either `backup_id` or\n`backup_location` MUST be provided. Use `backup_id` when restoring\na backup this Temps instance recorded." + }, + "backup_location": { + "type": [ + "string", + "null" + ], + "description": "Raw S3 URL / key of the backup \u2014 used when restoring a backup\ndiscovered by S3 scan (i.e., produced by another Temps instance).\nRequires `backup_engine` and `s3_source_id` to also be set." + }, + "s3_source_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "S3 source the `backup_location` lives in. Ignored when `backup_id`\nis used." + } + } + } + ] + }, + "StatResponse": { + "type": "object", + "required": [ + "path", + "exists", + "is_dir", + "is_file", + "size" + ], + "properties": { + "exists": { + "type": "boolean" + }, + "is_dir": { + "type": "boolean" + }, + "is_file": { + "type": "boolean" + }, + "path": { + "type": "string" + }, + "size": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + }, + "StaticBundleResponse": { + "type": "object", + "required": [ + "id", + "project_id", + "blob_path", + "content_type", + "size_bytes", + "uploaded_at", + "created_at" + ], + "properties": { + "blob_path": { + "type": "string" + }, + "checksum": { + "type": [ + "string", + "null" + ] + }, + "content_type": { + "type": "string" + }, + "created_at": { + "type": "string", + "format": "date-time", + "example": "2025-10-12T12:15:47.609192Z" + }, + "format": { + "type": [ + "string", + "null" + ] + }, + "id": { + "type": "integer", + "format": "int32" + }, + "metadata": {}, + "original_filename": { + "type": [ + "string", + "null" + ] + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "size_bytes": { + "type": "integer", + "format": "int64" + }, + "uploaded_at": { + "type": "string", + "format": "date-time", + "example": "2025-10-12T12:15:47.609192Z" + } + } + }, + "StaticParams": { + "type": "object", + "description": "Static threshold detector: compare the aggregated `value` against `threshold`.", + "required": [ + "comparator", + "threshold" + ], + "properties": { + "comparator": { + "$ref": "#/components/schemas/Comparator", + "description": "How `value` is compared against `threshold`." + }, + "threshold": { + "type": "number", + "format": "double", + "description": "The threshold the aggregated value is compared against." + } + } + }, + "StaticPresetConfig": { + "type": "object", + "description": "Configuration for static site presets (Vite, Next.js, Docusaurus, etc.)\nThese presets build static sites that are served via a web server", + "properties": { + "buildCommand": { + "type": [ + "string", + "null" + ], + "description": "Custom build command (overrides preset default)", + "example": "npm run build:production" + }, + "buildContext": { + "type": [ + "string", + "null" + ], + "description": "Custom build context path (relative to repository root)\nUseful for monorepo setups where the app is in a subdirectory", + "example": "./apps/frontend" + }, + "installCommand": { + "type": [ + "string", + "null" + ], + "description": "Custom install command (overrides auto-detected package manager)", + "example": "npm ci" + }, + "outputDir": { + "type": [ + "string", + "null" + ], + "description": "Custom output directory (overrides preset default)\nCommon values: \"dist\", \"build\", \".next\", \"out\"", + "example": "dist" + } + } + }, + "StatsFilters": { + "type": "object", + "description": "Filters for statistics queries", + "properties": { + "client_ip": { + "type": [ + "string", + "null" + ] + }, + "deployment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "device_type": { + "type": [ + "string", + "null" + ] + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "has_project": { + "type": [ + "boolean", + "null" + ], + "description": "When true, only count requests that matched a project (project_id IS NOT NULL).\nUsed by the health dashboard so totals match the per-project cards." + }, + "host": { + "type": [ + "string", + "null" + ] + }, + "is_bot": { + "type": [ + "boolean", + "null" + ] + }, + "method": { + "type": [ + "string", + "null" + ] + }, + "project_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "request_source": { + "type": [ + "string", + "null" + ] + }, + "routing_status": { + "type": [ + "string", + "null" + ] + }, + "status_code": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "status_code_class": { + "type": [ + "string", + "null" + ], + "description": "Filter by status code class (e.g. \"2xx\", \"3xx\", \"4xx\", \"5xx\")" + } + } + }, + "StatusBucket": { + "type": "object", + "required": [ + "bucket_start", + "status", + "total_checks", + "operational_count", + "degraded_count", + "down_count", + "uptime_percentage" + ], + "properties": { + "avg_response_time_ms": { + "type": [ + "number", + "null" + ], + "format": "double" + }, + "bucket_start": { + "type": "string", + "format": "date-time" + }, + "degraded_count": { + "type": "integer", + "format": "int64" + }, + "down_count": { + "type": "integer", + "format": "int64" + }, + "max_response_time_ms": { + "type": [ + "number", + "null" + ], + "format": "double" + }, + "min_response_time_ms": { + "type": [ + "number", + "null" + ], + "format": "double" + }, + "operational_count": { + "type": "integer", + "format": "int64" + }, + "p50_response_time_ms": { + "type": [ + "number", + "null" + ], + "format": "double" + }, + "p95_response_time_ms": { + "type": [ + "number", + "null" + ], + "format": "double" + }, + "p99_response_time_ms": { + "type": [ + "number", + "null" + ], + "format": "double" + }, + "status": { + "type": "string" + }, + "total_checks": { + "type": "integer", + "format": "int64" + }, + "uptime_percentage": { + "type": "number", + "format": "double" + } + } + }, + "StatusBucketedResponse": { + "type": "object", + "required": [ + "monitor_id", + "interval", + "buckets" + ], + "properties": { + "buckets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/StatusBucket" + } + }, + "interval": { + "type": "string" + }, + "monitor_id": { + "type": "integer", + "format": "int32" + } + } + }, + "StatusCodeCount": { + "type": "object", + "required": [ + "status_code", + "count", + "percentage" + ], + "properties": { + "count": { + "type": "integer", + "format": "int64" + }, + "percentage": { + "type": "number", + "format": "double" + }, + "status_code": { + "type": "integer", + "format": "int32" + } + } + }, + "StatusCodesQuery": { + "type": "object", + "required": [ + "start_date", + "end_date", + "project_id" + ], + "properties": { + "deployment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "end_date": { + "type": "string", + "format": "date-time" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "limit": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "start_date": { + "type": "string", + "format": "date-time" + } + } + }, + "StatusPageOverview": { + "type": "object", + "required": [ + "status", + "monitors", + "recent_incidents" + ], + "properties": { + "monitors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MonitorStatus" + } + }, + "recent_incidents": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IncidentResponse" + } + }, + "status": { + "type": "string" + } + } + }, + "StepConversionResponse": { + "type": "object", + "required": [ + "step_id", + "step_name", + "step_order", + "completions", + "conversion_rate", + "drop_off_rate", + "average_time_to_complete_seconds" + ], + "properties": { + "average_time_to_complete_seconds": { + "type": "number", + "format": "double" + }, + "completions": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "conversion_rate": { + "type": "number", + "format": "double" + }, + "drop_off_rate": { + "type": "number", + "format": "double" + }, + "step_id": { + "type": "integer", + "format": "int32" + }, + "step_name": { + "type": "string" + }, + "step_order": { + "type": "integer", + "format": "int32" + } + } + }, + "StepResourceType": { + "type": "string", + "description": "What kind of resource a migration step operates on", + "enum": [ + "project", + "environment", + "deployment", + "environment-variable", + "service", + "domain", + "git-link", + "other" + ] + }, + "StepResult": { + "type": "object", + "description": "Result of executing a single migration step", + "required": [ + "step_id", + "step_title", + "success", + "skipped", + "message", + "created_resources", + "duration_seconds" + ], + "properties": { + "created_resources": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CreatedResource" + }, + "description": "Resources created by this step" + }, + "duration_seconds": { + "type": "number", + "format": "double", + "description": "Duration of this step" + }, + "message": { + "type": "string", + "description": "Human-readable message about what happened" + }, + "skipped": { + "type": "boolean", + "description": "Whether this step was skipped" + }, + "step_id": { + "type": "string", + "description": "Step ID (matches `MigrationStep.id`)" + }, + "step_title": { + "type": "string", + "description": "Step title (for display)" + }, + "success": { + "type": "boolean", + "description": "Whether this step succeeded" + } + } + }, + "StepUpResponse": { + "type": "object", + "required": [ + "expires_at" + ], + "properties": { + "expires_at": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 timestamp after which sensitive actions require verification\nagain." + } + } + }, + "StopSequence": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "StorageQuota": { + "type": "object", + "description": "Quota usage information for a project.", + "required": [ + "project_id", + "metrics_bytes", + "traces_bytes", + "logs_bytes", + "total_bytes", + "limit_bytes", + "usage_pct" + ], + "properties": { + "limit_bytes": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "logs_bytes": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "metrics_bytes": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "total_bytes": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "traces_bytes": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "usage_pct": { + "type": "number", + "format": "double" + } + } + }, + "StripeConfig": { + "type": "object", + "properties": { + "include_unpriced_charges": { + "type": "boolean", + "description": "When an allowlist is set, should we still ingest charges that\nlack a price reference (e.g. standalone `charge.succeeded` without\na subscription)? Default true \u2014 charges don't belong to a SKU." + }, + "metered_mode": { + "$ref": "#/components/schemas/MeteredMode", + "description": "How to compute MRR for metered / tiered / hybrid subscriptions." + }, + "price_allowlist": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Only events tagged with one of these Stripe price IDs are ingested.\nEmpty = accept all prices." + }, + "product_allowlist": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Only events tagged with one of these Stripe product IDs are\ningested. Empty = accept all products. Combined with\n`price_allowlist` via OR \u2014 if either list has a match, accept." + } + } + }, + "SyncedRepositoryListQuery": { + "type": "object", + "properties": { + "direction": { + "type": [ + "string", + "null" + ] + }, + "git_provider_connection_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "language": { + "type": [ + "string", + "null" + ] + }, + "owner": { + "type": [ + "string", + "null" + ] + }, + "page": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + }, + "per_page": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + }, + "private": { + "type": [ + "boolean", + "null" + ] + }, + "search": { + "type": [ + "string", + "null" + ] + }, + "sort": { + "type": [ + "string", + "null" + ] + } + } + }, + "SyntaxResult": { + "type": "object", + "description": "Syntax validation result", + "required": [ + "is_valid_syntax" + ], + "properties": { + "domain": { + "type": [ + "string", + "null" + ], + "description": "The domain part of the email", + "example": "gmail.com" + }, + "is_valid_syntax": { + "type": "boolean", + "description": "Whether the email syntax is valid" + }, + "suggestion": { + "type": [ + "string", + "null" + ], + "description": "Suggested email correction if available" + }, + "username": { + "type": [ + "string", + "null" + ], + "description": "The username part of the email", + "example": "someone" + } + } + }, + "TagInfo": { + "type": "object", + "required": [ + "name", + "commit_sha" + ], + "properties": { + "commit_sha": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "TagListResponse": { + "type": "object", + "required": [ + "tags" + ], + "properties": { + "tags": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TagInfo" + } + } + } + }, + "TailLogsRequest": { + "type": "object", + "required": [ + "project_id", + "service", + "env" + ], + "properties": { + "env": { + "type": "string" + }, + "external_service_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "When set, tail an imported/managed external service's logs instead of\na project's (`project_id` is ignored in this mode)." + }, + "levels": { + "type": "array", + "items": { + "type": "string" + } + }, + "project_id": { + "type": "integer", + "format": "int32", + "description": "Project ID (integer, as used by the rest of the platform)" + }, + "service": { + "type": "string" + }, + "text": { + "type": [ + "string", + "null" + ] + } + } + }, + "TargetRecommendation": { + "type": "object", + "description": "The temps/Hetzner target sizing and savings estimate", + "required": [ + "server_type", + "vcpus", + "memory_gb", + "monthly_eur", + "fits_single_node", + "sizing_basis", + "rationale" + ], + "properties": { + "fits_single_node": { + "type": "boolean", + "description": "Whether the workloads fit a single recommended server. When `false`,\nthe rationale explains the multi-node option (temps worker nodes)." + }, + "memory_gb": { + "type": "integer", + "format": "int32", + "description": "Memory (GB) of the recommended server" + }, + "monthly_eur": { + "type": "number", + "format": "double", + "description": "Estimated monthly price of the recommended server in EUR" + }, + "monthly_savings_usd": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Estimated monthly savings in USD (current cost minus target cost,\ntreating EUR\u2248USD for the rough comparison \u2014 disclaimed in `notes`).\n`None` when the current cost is unknown." + }, + "rationale": { + "type": "string", + "description": "Human-readable recommendation summary" + }, + "server_type": { + "type": "string", + "description": "Recommended Hetzner server type (e.g. \"cpx32\")" + }, + "sizing_basis": { + "type": "string", + "description": "What the sizing was based on, e.g. \"2\u00d7 measured usage + temps\nplatform overhead\" or \"resource requests (no metrics available)\"" + }, + "vcpus": { + "type": "integer", + "format": "int32", + "description": "vCPUs of the recommended server" + }, + "yearly_savings_usd": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "`monthly_savings_usd \u00d7 12`" + } + } + }, + "TeamListResponse": { + "type": "object", + "required": [ + "teams", + "total", + "page", + "page_size" + ], + "properties": { + "page": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "page_size": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "teams": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TeamResponse" + } + }, + "total": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + }, + "TeamMemberResponse": { + "type": "object", + "required": [ + "id", + "team_id", + "user_id", + "role", + "added_by", + "created_at", + "updated_at" + ], + "properties": { + "added_by": { + "type": "integer", + "format": "int32" + }, + "created_at": { + "type": "string", + "format": "date-time", + "example": "2026-07-30T12:15:47.609192Z" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "role": { + "$ref": "#/components/schemas/TeamRole", + "description": "The source of this member's project-scoped permissions, intersected\nwith `project_team_access.role`." + }, + "team_id": { + "type": "integer", + "format": "int32" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "example": "2026-07-30T12:15:47.609192Z" + }, + "user_email": { + "type": [ + "string", + "null" + ], + "description": "The member's email, joined from `users`." + }, + "user_id": { + "type": "integer", + "format": "int32" + }, + "user_name": { + "type": [ + "string", + "null" + ], + "description": "The member's display name, joined from `users`. `None` if the\nreferenced user no longer exists." + } + } + }, + "TeamResponse": { + "type": "object", + "required": [ + "id", + "name", + "slug", + "created_by", + "created_at", + "updated_at" + ], + "properties": { + "created_at": { + "type": "string", + "format": "date-time", + "example": "2026-07-30T12:15:47.609192Z" + }, + "created_by": { + "type": "integer", + "format": "int32" + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "slug": { + "type": "string" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "example": "2026-07-30T12:15:47.609192Z" + } + } + }, + "TeamRole": { + "type": "string", + "description": "Role a user holds within a team, or that a team holds on a project.\n\nNamed `TeamRole` rather than `Role` to keep it distinct from\n`temps_auth::permissions::Role`, which is the instance-wide role\n(Admin/User/\u2026) attached to a session. The two are orthogonal: the\ninstance-wide role decides whether you may touch a resource *kind* at\nall, `TeamRole` decides what you may do *within a project* you have\nteam access to. See `temps_teams::fixed_role_permissions` for the\nproject-scoped permission set each variant maps to.\n\nStored as a `varchar(32)` rather than a Postgres enum so the role set\ncan evolve in pure migration code without a schema-level enum\nalteration blocking a downgrade.", + "enum": [ + "owner", + "admin", + "deployer", + "viewer" + ] + }, + "TemplateResponse": { + "type": "object", + "description": "Response type for a single template", + "required": [ + "slug", + "name", + "git", + "preset", + "tags", + "features", + "services", + "env_vars", + "is_featured" + ], + "properties": { + "description": { + "type": [ + "string", + "null" + ], + "description": "Short description" + }, + "env_vars": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EnvVarTemplateResponse" + }, + "description": "Environment variables template" + }, + "exposed_port": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Container port the prebuilt image listens on (image deploys only)." + }, + "features": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Feature highlights" + }, + "git": { + "$ref": "#/components/schemas/GitRefResponse", + "description": "Git repository reference" + }, + "health_check_path": { + "type": [ + "string", + "null" + ], + "description": "HTTP health-check path probed after the container starts (image deploys)." + }, + "image": { + "type": [ + "string", + "null" + ], + "description": "Prebuilt Docker image reference. When set, the one-click deploy pulls and\nruns this image directly (no build); when absent it builds from `git`." + }, + "image_url": { + "type": [ + "string", + "null" + ], + "description": "URL to template image/icon" + }, + "is_featured": { + "type": "boolean", + "description": "Whether the template is featured/promoted" + }, + "name": { + "type": "string", + "description": "Display name" + }, + "preset": { + "type": "string", + "description": "Framework/preset to use" + }, + "screenshot_url": { + "type": [ + "string", + "null" + ], + "description": "URL to a wide screenshot/banner preview of the deployed template.\nAbsent for templates that don't have one captured yet." + }, + "services": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Required external services" + }, + "slug": { + "type": "string", + "description": "Unique identifier for the template (used in URLs)" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Tags/categories for filtering" + } + } + }, + "TestEmailRequest": { + "type": "object", + "description": "Request body for testing an email provider", + "required": [ + "from" + ], + "properties": { + "from": { + "type": "string", + "description": "Sender email address (must be verified with the provider)", + "example": "test@example.com" + }, + "from_name": { + "type": [ + "string", + "null" + ], + "description": "Sender display name", + "example": "My App" + } + } + }, + "TestEmailResponse": { + "type": "object", + "description": "Response for test email endpoint", + "required": [ + "success", + "sent_to" + ], + "properties": { + "error": { + "type": [ + "string", + "null" + ], + "description": "Error message if the test failed" + }, + "provider_message_id": { + "type": [ + "string", + "null" + ], + "description": "Provider message ID if successful" + }, + "sent_to": { + "type": "string", + "description": "The email address the test was sent to", + "example": "user@example.com" + }, + "success": { + "type": "boolean", + "description": "Whether the test email was sent successfully" + } + } + }, + "TestProviderKeyRequest": { + "type": "object", + "required": [ + "provider", + "api_key" + ], + "properties": { + "api_key": { + "type": "string", + "description": "The raw API key to test" + }, + "base_url": { + "type": [ + "string", + "null" + ], + "description": "Optional custom base URL" + }, + "provider": { + "type": "string", + "description": "Provider ID: \"openai\", \"anthropic\", \"xai\", \"gemini\"" + } + } + }, + "TestProviderKeyResponse": { + "type": "object", + "required": [ + "success", + "provider", + "latency_ms" + ], + "properties": { + "error": { + "type": [ + "string", + "null" + ], + "description": "Error message if the test failed" + }, + "latency_ms": { + "type": "integer", + "format": "int64", + "description": "Response time in milliseconds", + "minimum": 0 + }, + "provider": { + "type": "string" + }, + "success": { + "type": "boolean" + } + } + }, + "TestProviderResponse": { + "type": "object", + "required": [ + "success" + ], + "properties": { + "message": { + "type": [ + "string", + "null" + ] + }, + "success": { + "type": "boolean" + } + } + }, + "TimeBucketStats": { + "type": "object", + "description": "Time bucket statistics response", + "required": [ + "bucket", + "request_count", + "avg_response_time_ms", + "error_count", + "total_request_bytes", + "total_response_bytes" + ], + "properties": { + "avg_response_time_ms": { + "type": "number", + "format": "double", + "description": "Average response time in milliseconds" + }, + "bucket": { + "type": "string", + "description": "Bucket timestamp in RFC3339 format", + "example": "2025-10-23T12:00:00Z" + }, + "error_count": { + "type": "integer", + "format": "int64", + "description": "Number of errors (status >= 400)" + }, + "request_count": { + "type": "integer", + "format": "int64", + "description": "Total number of requests in this bucket" + }, + "total_request_bytes": { + "type": "integer", + "format": "int64", + "description": "Total request bytes" + }, + "total_response_bytes": { + "type": "integer", + "format": "int64", + "description": "Total response bytes" + } + } + }, + "TimeBucketStatsResponse": { + "type": "object", + "description": "Response for time bucket stats", + "required": [ + "stats", + "start_time", + "end_time", + "bucket_interval" + ], + "properties": { + "bucket_interval": { + "type": "string" + }, + "end_time": { + "type": "string" + }, + "start_time": { + "type": "string" + }, + "stats": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TimeBucketStats" + } + } + } + }, + "TimeseriesBucket": { + "type": "object", + "required": [ + "bucket", + "request_count", + "input_tokens", + "output_tokens", + "avg_latency_ms" + ], + "properties": { + "avg_latency_ms": { + "type": "number", + "format": "double" + }, + "bucket": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "input_tokens": { + "type": "integer", + "format": "int64" + }, + "output_tokens": { + "type": "integer", + "format": "int64" + }, + "request_count": { + "type": "integer", + "format": "int64" + } + } + }, + "TimeseriesQueryParams": { + "type": "object", + "properties": { + "bucket": { + "type": [ + "string", + "null" + ], + "description": "Bucket size: \"hour\", \"day\", \"week\" (defaults to \"day\")" + }, + "conversation_id": { + "type": [ + "string", + "null" + ], + "description": "Filter by conversation ID" + }, + "from": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 start time (defaults to 24h ago)" + }, + "model": { + "type": [ + "string", + "null" + ], + "description": "Filter by model name" + }, + "provider": { + "type": [ + "string", + "null" + ], + "description": "Filter by provider name" + }, + "tags": { + "type": [ + "string", + "null" + ], + "description": "Filter by tags (comma-separated, AND logic)" + }, + "to": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 end time (defaults to now)" + }, + "user_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Filter by user ID" + } + } + }, + "TlsMode": { + "type": "string", + "enum": [ + "None", + "Starttls", + "Tls" + ] + }, + "TodayStatsResponse": { + "type": "object", + "description": "Today's stats response", + "required": [ + "total_requests", + "date" + ], + "properties": { + "date": { + "type": "string", + "description": "Date for which stats are returned", + "example": "2025-10-23" + }, + "total_requests": { + "type": "integer", + "format": "int64", + "description": "Total requests today" + } + } + }, + "ToggleAiDataAccessRequest": { + "type": "object", + "required": [ + "enabled" + ], + "properties": { + "enabled": { + "type": "boolean", + "description": "Whether the AI assistant may read row data from this service.", + "example": false + } + } + }, + "ToggleDeploymentMetricsRequest": { + "type": "object", + "description": "Request body to toggle OTLP metric ingestion for a deployment.", + "required": [ + "enabled" + ], + "properties": { + "enabled": { + "type": "boolean", + "description": "Whether to enable (`true`) or disable (`false`) metric ingestion." + }, + "path": { + "type": [ + "string", + "null" + ], + "description": "Prometheus scrape path (optional, defaults to `/metrics`)." + }, + "port": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Prometheus scrape port (optional).", + "minimum": 0 + } + } + }, + "ToggleServiceMetricsRequest": { + "type": "object", + "description": "Request body to toggle metric collection for an external service.", + "required": [ + "enabled" + ], + "properties": { + "enabled": { + "type": "boolean", + "description": "Whether to enable (`true`) or disable (`false`) metric collection." + } + } + }, + "TokenRenewalRequest": { + "type": "object", + "required": [ + "refresh_token" + ], + "properties": { + "refresh_token": { + "type": "string" + } + } + }, + "ToolCallEvent": { + "type": "object", + "description": "Payload for the `tool_call` SSE event: the model is about to run a tool.\nSerialized as compact single-line JSON onto one `data:` line.", + "required": [ + "id", + "name", + "arguments" + ], + "properties": { + "arguments": { + "type": "string", + "description": "The raw JSON-args string the model emitted." + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "ToolInfo": { + "type": "object", + "description": "One persisted tool invocation + its result, attached to an assistant message.", + "required": [ + "id", + "name", + "arguments" + ], + "properties": { + "arguments": { + "type": "string" + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "result": { + "type": [ + "string", + "null" + ] + } + } + }, + "ToolResultEvent": { + "type": "object", + "description": "Payload for the `tool_result` SSE event: a tool finished running. Serialized\nas compact single-line JSON; `content` is JSON-string-escaped so it stays on\none `data:` line even when long.", + "required": [ + "id", + "name", + "content" + ], + "properties": { + "content": { + "type": "string" + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "TopModelsQueryParams": { + "type": "object", + "properties": { + "from": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 start time (defaults to 24h ago)" + }, + "limit": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Max results (defaults to 10)", + "minimum": 0 + }, + "tags": { + "type": [ + "string", + "null" + ], + "description": "Filter by tags (comma-separated, AND logic)" + }, + "to": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 end time (defaults to now)" + }, + "user_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Filter by user ID" + } + } + }, + "TraceProjectRef": { + "type": "object", + "description": "All projects that contributed spans to a trace, including their sharing flag.\n\nReturned by `CrossProjectTraceService::find_trace_projects`.", + "required": [ + "project_id", + "project_name", + "project_slug", + "first_seen", + "sharing" + ], + "properties": { + "first_seen": { + "type": "string", + "format": "date-time" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "project_name": { + "type": "string" + }, + "project_slug": { + "type": "string", + "description": "URL slug used to link into the project's single-project trace view." + }, + "sharing": { + "type": "boolean", + "description": "Whether this project has `cross_project_trace_sharing = true`." + } + } + }, + "TraceSummariesResponse": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TraceSummary" + } + }, + "total": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Total traces matching the filters, ignoring pagination. Omitted when\nthe request passed `include_total=false`, in which case the caller\nasked not to pay for the count \u2014 treat its absence as \"unknown\", not\nas zero.", + "minimum": 0 + } + } + }, + "TraceSummary": { + "type": "object", + "description": "A trace summary for the list view \u2014 one row per trace, aggregated from spans.", + "required": [ + "trace_id", + "root_span_name", + "service_name", + "kind", + "status_code", + "start_time", + "duration_ms", + "span_count", + "error_count" + ], + "properties": { + "deployment_environment": { + "type": [ + "string", + "null" + ], + "description": "The deployment environment from the root span's resource attributes (e.g. \"production\")." + }, + "duration_ms": { + "type": "number", + "format": "double" + }, + "error_count": { + "type": "integer", + "format": "int64" + }, + "kind": { + "$ref": "#/components/schemas/SpanKind" + }, + "root_span_name": { + "type": "string" + }, + "service_name": { + "type": "string" + }, + "span_count": { + "type": "integer", + "format": "int64" + }, + "start_time": { + "type": "string", + "format": "date-time" + }, + "status_code": { + "$ref": "#/components/schemas/SpanStatusCode" + }, + "trace_id": { + "type": "string" + } + } + }, + "TracesResponse": { + "type": "object", + "required": [ + "data", + "count" + ], + "properties": { + "count": { + "type": "integer", + "minimum": 0 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SpanRecord" + } + } + } + }, + "TrackedLinkResponse": { + "type": "object", + "description": "Tracked link with click count", + "required": [ + "link_index", + "original_url", + "click_count" + ], + "properties": { + "click_count": { + "type": "integer", + "format": "int32" + }, + "link_index": { + "type": "integer", + "format": "int32" + }, + "original_url": { + "type": "string" + } + } + }, + "TrackingEventResponse": { + "type": "object", + "description": "Email tracking event", + "required": [ + "id", + "email_id", + "event_type", + "created_at" + ], + "properties": { + "created_at": { + "type": "string" + }, + "email_id": { + "type": "string" + }, + "event_type": { + "type": "string" + }, + "id": { + "type": "integer", + "format": "int64" + }, + "ip_address": { + "type": [ + "string", + "null" + ] + }, + "link_index": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "link_url": { + "type": [ + "string", + "null" + ] + }, + "user_agent": { + "type": [ + "string", + "null" + ] + } + } + }, + "TriggerAgentRequest": { + "type": "object", + "properties": { + "trigger_source_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "trigger_source_type": { + "type": [ + "string", + "null" + ] + }, + "user_context": { + "type": [ + "string", + "null" + ], + "description": "Optional context from the user (e.g. a research topic, bug description, or instructions)." + } + } + }, + "TriggerDigestResponse": { + "type": "object", + "required": [ + "success", + "message" + ], + "properties": { + "message": { + "type": "string" + }, + "success": { + "type": "boolean" + } + } + }, + "TriggerPipelinePayload": { + "type": "object", + "properties": { + "branch": { + "type": [ + "string", + "null" + ] + }, + "commit": { + "type": [ + "string", + "null" + ] + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Optional environment ID - if not provided, will use the project's preview environment" + }, + "tag": { + "type": [ + "string", + "null" + ] + } + } + }, + "TriggerPipelineResponse": { + "type": "object", + "required": [ + "message", + "project_id", + "environment_id" + ], + "properties": { + "branch": { + "type": [ + "string", + "null" + ] + }, + "commit": { + "type": [ + "string", + "null" + ] + }, + "environment_id": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "tag": { + "type": [ + "string", + "null" + ] + } + } + }, + "TriggerScanRequest": { + "type": "object", + "required": [ + "environment_id" + ], + "properties": { + "environment_id": { + "type": "integer", + "format": "int32", + "description": "Environment ID to scan (uses the current deployment for this environment)", + "example": 1 + } + } + }, + "TriggerScanResponse": { + "type": "object", + "required": [ + "scan_id", + "status", + "message" + ], + "properties": { + "message": { + "type": "string" + }, + "scan_id": { + "type": "integer", + "format": "int32" + }, + "status": { + "type": "string" + } + } + }, + "TtlRequest": { + "type": "object", + "description": "Request to get TTL for a key", + "required": [ + "key" + ], + "properties": { + "key": { + "type": "string", + "description": "The key to check TTL for", + "example": "session:abc" + }, + "project_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Project ID (required for API key/session auth, optional for deployment tokens)", + "example": 1 + } + } + }, + "TtlResponse": { + "type": "object", + "description": "Response for TTL operation", + "required": [ + "ttl" + ], + "properties": { + "ttl": { + "type": "integer", + "format": "int64", + "description": "TTL in seconds, -1 if no expiration, -2 if key doesn't exist", + "example": 3600 + } + } + }, + "TxtRecord": { + "type": "object", + "required": [ + "name", + "value" + ], + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, + "UiManifest": { + "type": "object", + "description": "Describes the plugin's embedded UI bundle.", + "required": [ + "entry_js" + ], + "properties": { + "css": { + "type": "array", + "items": { + "type": "string" + }, + "description": "CSS files to load" + }, + "entry_js": { + "type": "string", + "description": "JavaScript entry point filename relative to the bundle root" + }, + "routes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UiRoute" + }, + "description": "Client-side routes the plugin handles" + } + } + }, + "UiRoute": { + "type": "object", + "description": "A client-side route provided by the plugin UI.", + "required": [ + "path", + "title" + ], + "properties": { + "path": { + "type": "string", + "description": "Route path pattern (e.g., \"/my-plugin\", \"/my-plugin/:id\")" + }, + "title": { + "type": "string", + "description": "Page title for breadcrumbs" + } + } + }, + "UndrainNodeResponse": { + "type": "object", + "description": "Response after undraining (reactivating) a node.", + "required": [ + "id", + "name", + "status", + "message" + ], + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "name": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "UnifiedTrace": { + "type": "object", + "description": "Merged cross-project trace result (Phase 2 unified waterfall).\n\nSpans are sorted by `start_time ASC`. At most 20 projects and 10,000\nspans total are included; `truncated` / `truncated_projects` signal when\nthe caps were hit.", + "required": [ + "trace_id", + "projects", + "spans", + "start_time", + "end_time", + "total_duration_ms", + "span_count", + "error_count", + "has_redacted_spans", + "truncated", + "truncated_projects" + ], + "properties": { + "end_time": { + "type": "string", + "format": "date-time" + }, + "error_count": { + "type": "integer", + "minimum": 0 + }, + "has_redacted_spans": { + "type": "boolean", + "description": "`true` when at least one project has `cross_project_trace_sharing = false`\nand its spans were therefore excluded from the result set." + }, + "projects": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProjectRef" + }, + "description": "Projects that contributed spans to this result set." + }, + "span_count": { + "type": "integer", + "minimum": 0 + }, + "spans": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AnnotatedSpan" + }, + "description": "Annotated, merged span list sorted by `start_time ASC`." + }, + "start_time": { + "type": "string", + "format": "date-time" + }, + "total_duration_ms": { + "type": "number", + "format": "double", + "description": "Trace wall-clock duration in milliseconds (`end_time \u2013 start_time`)." + }, + "trace_id": { + "type": "string" + }, + "truncated": { + "type": "boolean", + "description": "`true` when the 20-project or 10,000-span cap was hit." + }, + "truncated_projects": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "description": "project_ids excluded due to truncation (most-recent first_seen dropped first)." + } + } + }, + "UniqueCountsQuery": { + "type": "object", + "description": "Query parameters for unique counts over time frame", + "required": [ + "start_date", + "end_date" + ], + "properties": { + "deployment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Optional deployment filter" + }, + "end_date": { + "type": "string", + "format": "date-time", + "description": "End date for the query range" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Optional environment filter" + }, + "metric": { + "type": "string", + "description": "Metric to count: \"sessions\" (unique sessions), \"visitors\" (unique visitors),\n\"returning_visitors\" (visitors seen before the range), or \"page_views\"\n(total page views) (default: \"sessions\")" + }, + "start_date": { + "type": "string", + "format": "date-time", + "description": "Start date for the query range" + } + } + }, + "UniqueCountsResponse": { + "type": "object", + "required": [ + "count" + ], + "properties": { + "count": { + "type": "integer", + "format": "int64" + } + } + }, + "UnsupportedFeature": { + "type": "object", + "description": "A feature from the source platform that cannot be migrated", + "required": [ + "feature", + "reason" + ], + "properties": { + "alternative": { + "type": [ + "string", + "null" + ], + "description": "Suggested alternative in Temps (if any)" + }, + "feature": { + "type": "string", + "description": "Feature name (e.g., \"Edge Middleware\", \"Serverless Functions\", \"Cron Jobs\")" + }, + "reason": { + "type": "string", + "description": "Why it can't be migrated" + } + } + }, + "UpdateAdminGateRequest": { + "type": "object", + "required": [ + "allowed_ips", + "allowed_hosts", + "trust_forwarded_for" + ], + "properties": { + "allowed_hosts": { + "type": "array", + "items": { + "type": "string" + } + }, + "allowed_ips": { + "type": "array", + "items": { + "type": "string" + } + }, + "trust_forwarded_for": { + "type": "boolean" + } + } + }, + "UpdateAiProviderRequest": { + "type": "object", + "description": "Body for `PATCH /settings/ai-providers/{provider_id}` \u2014 updates\nprovider-scoped settings (just the default model for now) without\ntouching the credential. Keeping credentials out of this shape means\nthe UI can auto-save model changes on select, without forcing the user\nto re-paste their token or config file.\nName-spaced schema name avoids an OpenAPI collision with\n`temps-notifications::UpdateProviderRequest`, which has different fields.\nBoth are exposed as `utoipa::ToSchema`; without the override the merged\nOpenAPI doc would silently shadow one struct with the other and break\ngenerated CLI/web clients.", + "properties": { + "default_model": { + "type": [ + "string", + "null" + ], + "description": "New default model id. `None` or an empty string clears the stored\nvalue so the CLI falls back to its own default." + }, + "max_turns_analysis": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Default max turns for the autofixer analysis phase (1\u2013200). `0`\nclears the stored value (built-in default applies); omitted/`None`\nleaves the current value unchanged \u2014 so a PATCH that only updates\n`default_model` doesn't wipe the turn settings." + }, + "max_turns_feedback": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Default max turns for autofixer feedback rounds (1\u2013200). `0` clears;\nomitted leaves unchanged." + }, + "max_turns_fix": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Default max turns for the autofixer fix phase (1\u2013200). `0` clears;\nomitted leaves unchanged." + } + } + }, + "UpdateAiProviderResponse": { + "type": "object", + "required": [ + "provider_id" + ], + "properties": { + "default_model": { + "type": [ + "string", + "null" + ] + }, + "max_turns_analysis": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "max_turns_feedback": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "max_turns_fix": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "provider_id": { + "type": "string" + } + } + }, + "UpdateAlertRuleRequest": { + "type": "object", + "properties": { + "cooldown_minutes": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "enabled": { + "type": [ + "boolean", + "null" + ] + }, + "environment_filter": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "error_level_filter": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "notification_priority": { + "type": [ + "string", + "null" + ] + }, + "trigger_config": {}, + "trigger_type": { + "type": [ + "string", + "null" + ] + } + } + }, + "UpdateApiKeyRequest": { + "type": "object", + "properties": { + "expires_at": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "example": "2024-12-31T23:59:59Z" + }, + "is_active": { + "type": [ + "boolean", + "null" + ] + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "permissions": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + }, + "example": [ + "projects:read", + "deployments:read" + ] + } + } + }, + "UpdateAutomaticDeployRequest": { + "type": "object", + "required": [ + "automatic_deploy" + ], + "properties": { + "automatic_deploy": { + "type": "boolean" + } + } + }, + "UpdateBackupScheduleRequest": { + "type": "object", + "description": "Request body for updating an existing backup schedule via `PATCH /api/backups/schedules/{id}`.\n\nAll fields are optional; only present fields are updated. Absent fields\nleave the corresponding column unchanged.", + "properties": { + "description": { + "type": [ + "string", + "null" + ], + "description": "New human-readable description. Pass an empty string `\"\"` to clear." + }, + "enabled": { + "type": [ + "boolean", + "null" + ], + "description": "Enable or disable the schedule. Skipped when `None`." + }, + "include_control_plane": { + "type": [ + "boolean", + "null" + ], + "description": "Toggle whether the control-plane backup is produced on every run." + }, + "max_runtime_secs": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Per-schedule wall-clock timeout override (seconds).\n\n- `None` (field absent) \u2014 leave current value unchanged\n- `Some(None)` (field present, JSON `null`) \u2014 clear override; fall back to engine default\n- `Some(Some(n))` \u2014 set to `n` seconds (must be >= 60)" + }, + "name": { + "type": [ + "string", + "null" + ], + "description": "New schedule name. Skipped when `None`. Must not be empty if provided." + }, + "retention_period": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Days to retain backups produced by this schedule. Must be >= 1." + }, + "schedule_expression": { + "type": [ + "string", + "null" + ], + "description": "New cron expression. When changed, `next_run` is recomputed." + }, + "tags": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + }, + "description": "Replace the full tag list. Skipped when `None`." + }, + "target_all_services": { + "type": [ + "boolean", + "null" + ], + "description": "Toggle between \"back up every database\" (`true`) and \"back up only\nthe explicit list\" (`false`). When set to `true`, the server clears\nthe explicit membership rows for this schedule." + } + } + }, + "UpdateBlobRequest": { + "type": "object", + "description": "Request to update Blob service configuration", + "properties": { + "docker_image": { + "type": [ + "string", + "null" + ], + "description": "Docker image to use (e.g., \"rustfs/rustfs:1.0.0-alpha.98\")", + "example": "rustfs/rustfs:1.0.0-alpha.98" + } + } + }, + "UpdateBlobResponse": { + "type": "object", + "description": "Response after updating Blob service", + "required": [ + "success", + "message", + "status" + ], + "properties": { + "message": { + "type": "string", + "description": "Human-readable message", + "example": "Blob service updated successfully" + }, + "status": { + "$ref": "#/components/schemas/BlobStatusResponse", + "description": "Current status" + }, + "success": { + "type": "boolean", + "description": "Whether the operation succeeded", + "example": true + } + } + }, + "UpdateCloudflareProviderRequest": { + "type": "object", + "required": [ + "config" + ], + "properties": { + "config": { + "$ref": "#/components/schemas/CloudflareConfig" + }, + "enabled": { + "type": [ + "boolean", + "null" + ] + }, + "name": { + "type": [ + "string", + "null" + ] + } + } + }, + "UpdateConfigBody": { + "type": "object", + "properties": { + "config": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/ProviderConfig", + "description": "Typed provider configuration. Setting `config` to `null` clears\nthe stored config back to the accept-everything default. The\nconfig's `provider` tag must match the integration's provider." + } + ] + } + } + }, + "UpdateCustomDomainRequest": { + "type": "object", + "properties": { + "branch": { + "type": [ + "string", + "null" + ] + }, + "domain": { + "type": [ + "string", + "null" + ] + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "redirect_to": { + "type": [ + "string", + "null" + ] + }, + "service_name": { + "type": [ + "string", + "null" + ], + "description": "Docker Compose service name this domain routes to (empty string clears it)" + }, + "status_code": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + } + }, + "UpdateDashboardRequest": { + "type": "object", + "properties": { + "layout": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/DashboardLayout" + } + ] + }, + "name": { + "type": [ + "string", + "null" + ] + } + } + }, + "UpdateDeploymentConfigRequest": { + "type": "object", + "properties": { + "automaticDeploy": { + "type": [ + "boolean", + "null" + ] + }, + "cpuLimit": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "cpuRequest": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "crossArchitectureBuilds": { + "type": [ + "boolean", + "null" + ], + "description": "Build one image per architecture the eligible nodes run. Off by\ndefault; environments inherit this and may override it. Cross-builds\nare emulated on the control plane and substantially slower, so they are\nopted into rather than triggered by cluster topology." + }, + "exposedPort": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "memoryLimit": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "memoryRequest": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "performanceMetricsEnabled": { + "type": [ + "boolean", + "null" + ] + }, + "replicas": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "security": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/SecurityConfig" + } + ] + }, + "sessionRecordingEnabled": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "UpdateDeploymentTokenRequest": { + "type": "object", + "properties": { + "expires_at": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "example": "2024-12-31T23:59:59Z" + }, + "is_active": { + "type": [ + "boolean", + "null" + ] + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "permissions": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + }, + "example": [ + "visitors:enrich", + "emails:send" + ] + } + } + }, + "UpdateDnsProviderRequest": { + "type": "object", + "description": "Request to update a DNS provider", + "properties": { + "credentials": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/DnsProviderCredentials", + "description": "New credentials" + } + ] + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "New description" + }, + "is_active": { + "type": [ + "boolean", + "null" + ], + "description": "Active status" + }, + "name": { + "type": [ + "string", + "null" + ], + "description": "New name" + } + } + }, + "UpdateEmailProviderRequest": { + "type": "object", + "description": "Request body for `PATCH /email-providers/{id}`.\n\nAll fields are optional. Omit any field to leave it unchanged. The\n`provider_type` is immutable \u2014 to switch providers, delete the row and\ncreate a new one. For credentials, supplying any credential variant\nre-encrypts the stored blob; omitting them preserves the existing secret\n(so operators can rename without re-typing passwords).", + "properties": { + "is_active": { + "type": [ + "boolean", + "null" + ] + }, + "name": { + "type": [ + "string", + "null" + ], + "example": "My AWS SES" + }, + "region": { + "type": [ + "string", + "null" + ], + "example": "us-east-1" + }, + "scaleway_credentials": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/ScalewayCredentialsRequest" + } + ] + }, + "ses_credentials": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/SesCredentialsRequest" + } + ] + }, + "smtp_credentials": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/SmtpCredentialsRequest" + } + ] + }, + "sns_topic_arn": { + "type": [ + "string", + "null" + ], + "description": "Rotate or clear the exact SNS topic allowed for this SES provider.\nOmit to preserve it, send `null` to clear it, or send a string to set it." + } + } + }, + "UpdateEnvironmentSettingsRequest": { + "type": "object", + "properties": { + "anti_affinity": { + "type": [ + "boolean", + "null" + ], + "description": "Anti-affinity: spread replicas across different nodes.\nWhen enabled, the scheduler avoids placing two replicas of the same\nenvironment on the same node. Defaults to `true`." + }, + "attack_mode": { + "type": [ + "boolean", + "null" + ], + "description": "Per-environment CAPTCHA attack-mode override (tri-state):\n- absent \u2192 leave the current override unchanged\n- JSON `null` \u2192 clear the override (inherit the project-level setting)\n- `true`/`false` \u2192 override the project setting for this environment" + }, + "automatic_deploy": { + "type": [ + "boolean", + "null" + ], + "description": "Enable/disable automatic deployments for this environment" + }, + "branch": { + "type": [ + "string", + "null" + ] + }, + "cpu_limit": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Maximum (limit) CPU in microcores. Send JSON `null` to clear \u2192 \"no limit\".\nAbsent leaves the current value unchanged." + }, + "cpu_request": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Minimum (request) CPU in microcores. Send JSON `null` to clear (no request).\nAbsent leaves the current value unchanged." + }, + "cross_architecture_builds": { + "type": [ + "boolean", + "null" + ], + "description": "Build one image per architecture the eligible nodes run (overrides the\nproject-level setting). Off by default: cross-architecture builds are\nemulated on the control plane and substantially slower, so they are\nopted into per environment rather than triggered by cluster topology." + }, + "exposed_port": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Port exposed by the container (overrides project-level port for this environment)\n\nPriority order for port resolution:\n1. Image EXPOSE directive (auto-detected from built image)\n2. This environment-level exposed_port (overrides project setting)\n3. Project-level exposed_port (fallback)\n4. Default: 3000", + "example": 8080 + }, + "force_https": { + "type": [ + "boolean", + "null" + ], + "description": "Per-environment HTTP\u2192HTTPS redirect override (tri-state):\n- absent \u2192 leave the current override unchanged\n- JSON `null` \u2192 clear the override (inherit the proxy default, which\n redirects only when the host has an active TLS certificate)\n- `true` \u2192 always redirect plain HTTP to HTTPS for this environment,\n even when no local certificate exists (TLS terminated upstream)\n- `false` \u2192 never redirect this environment, even when a certificate does\n exist\n\nRequests under `/.well-known/acme-challenge/` are never redirected\nregardless of this setting, so ACME HTTP-01 validation always completes." + }, + "idle_timeout_seconds": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Seconds of inactivity before stopping containers (60-86400). Default: 300." + }, + "memory_limit": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Maximum (limit) memory in MB. Send JSON `null` to clear \u2192 \"no limit\".\nAbsent leaves the current value unchanged." + }, + "memory_request": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Minimum (request) memory in MB. Send JSON `null` to clear (no request).\nAbsent leaves the current value unchanged." + }, + "on_demand": { + "type": [ + "boolean", + "null" + ], + "description": "Enable on-demand mode (scale-to-zero). Containers are stopped after\nidle_timeout_seconds of no traffic and started on the next request." + }, + "password": { + "type": [ + "string", + "null" + ], + "description": "Set a password to protect this environment. The proxy will show an HTML\npassword form before allowing access. The password is bcrypt-hashed\nserver-side and never stored in plaintext.\nSend an empty string to remove password protection." + }, + "performance_metrics_enabled": { + "type": [ + "boolean", + "null" + ], + "description": "Enable/disable performance metrics collection" + }, + "protected": { + "type": [ + "boolean", + "null" + ], + "description": "When true, git pushes do NOT auto-deploy to this environment.\nDeployments must be promoted from another environment." + }, + "replicas": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "security": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/SecurityConfig", + "description": "Security configuration for this environment (overrides project-level settings)" + } + ] + }, + "session_recording_enabled": { + "type": [ + "boolean", + "null" + ], + "description": "Enable/disable session recording" + }, + "target_labels": { + "description": "Label selector for node-based scheduling (overrides project-level setting).\nSame key with array value -> OR, different keys -> AND.\nExample: `{\"region\": [\"us\", \"asia\"], \"gpu\": \"true\"}`" + }, + "target_nodes": { + "type": [ + "array", + "null" + ], + "items": { + "type": "integer", + "format": "int32" + }, + "description": "Optional list of node IDs to deploy to (overrides project-level setting)" + }, + "wake_timeout_seconds": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Max seconds to wait for containers to start on wake (5-120). Default: 30." + } + } + }, + "UpdateEnvironmentSubdomainRequest": { + "type": "object", + "description": "Request to rename an environment's auto-managed subdomain.\n\nThe subdomain is the host label inserted in front of the platform's\npreview domain (e.g. `myapp` in `myapp.preview.temps.sh`). Renaming\nreplaces the previous subdomain entirely \u2014 the old hostname stops\nresolving immediately after this request succeeds.", + "required": [ + "subdomain" + ], + "properties": { + "subdomain": { + "type": "string", + "description": "New subdomain label. Must be a DNS-safe slug (lowercase letters,\ndigits, and hyphens, 1-63 characters). The value is slugified\nserver-side, so casing and disallowed characters are normalized.", + "example": "myapp" + } + } + }, + "UpdateEnvironmentVariableRequest": { + "type": "object", + "required": [ + "key", + "environment_ids" + ], + "properties": { + "environment_ids": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + }, + "include_in_preview": { + "type": "boolean" + }, + "is_secret": { + "type": [ + "boolean", + "null" + ], + "description": "Optional secret-flag transition.\n- `Some(true)` promotes a regular var to a secret.\n- `Some(false)` is rejected if the row is already secret (one-way flag).\n- `None` (omitted) leaves the flag unchanged." + }, + "key": { + "type": "string" + }, + "value": { + "type": [ + "string", + "null" + ], + "description": "New plaintext value. `None` (omitted) keeps the existing ciphertext,\nwhich is the only way to edit a secret env var without re-typing its\nvalue (e.g. changing which environments it applies to)." + } + } + }, + "UpdateErrorGroupRequest": { + "type": "object", + "required": [ + "status" + ], + "properties": { + "assigned_to": { + "type": [ + "string", + "null" + ] + }, + "status": { + "type": "string" + } + } + }, + "UpdateExternalServiceRequest": { + "type": "object", + "required": [ + "parameters" + ], + "properties": { + "docker_image": { + "type": [ + "string", + "null" + ], + "description": "Docker image to use for the service (e.g., \"gotempsh/postgres-walg:18-bookworm\", \"timescale/timescaledb-ha:pg18\")\nWhen provided, the service will be recreated with the new image while preserving data" + }, + "parameters": { + "type": "object", + "additionalProperties": {}, + "propertyNames": { + "type": "string" + } + } + } + }, + "UpdateFlagRequest": { + "type": "object", + "properties": { + "client_visible": { + "type": [ + "boolean", + "null" + ] + }, + "default_value": { + "description": "Must match the flag's existing `value_type`." + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Tri-state: absent leaves it, `null` clears it, a string sets it." + } + } + }, + "UpdateGitSettingsRequest": { + "type": "object", + "required": [ + "main_branch", + "repo_owner", + "repo_name", + "directory" + ], + "properties": { + "directory": { + "type": "string" + }, + "git_provider_connection_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "git_url": { + "type": [ + "string", + "null" + ], + "description": "Git clone URL for public repositories" + }, + "is_public_repo": { + "type": [ + "boolean", + "null" + ], + "description": "Whether this is a public repository (no git provider connection needed)" + }, + "main_branch": { + "type": "string" + }, + "preset": { + "type": [ + "string", + "null" + ] + }, + "preset_config": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/PresetConfigSchema", + "description": "Preset-specific configuration (e.g., Dockerfile path for Docker preset)\n\nExample for Dockerfile preset:\n```json\n{\n \"dockerfilePath\": \"docker/Dockerfile\",\n \"buildContext\": \"./api\"\n}\n```" + } + ] + }, + "repo_name": { + "type": "string" + }, + "repo_owner": { + "type": "string" + } + } + }, + "UpdateIncidentStatusRequest": { + "type": "object", + "required": [ + "status", + "message" + ], + "properties": { + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "UpdateIpAccessControlRequest": { + "type": "object", + "description": "Request to update an IP access control rule", + "properties": { + "action": { + "type": [ + "string", + "null" + ], + "description": "Optional new action" + }, + "ip_address": { + "type": [ + "string", + "null" + ], + "description": "Optional new IP address" + }, + "reason": { + "type": [ + "string", + "null" + ], + "description": "Optional new reason" + } + } + }, + "UpdateKvRequest": { + "type": "object", + "description": "Request to update KV service configuration", + "properties": { + "docker_image": { + "type": [ + "string", + "null" + ], + "description": "Docker image to use (e.g., \"gotempsh/redis-walg:8-bookworm\")", + "example": "gotempsh/redis-walg:8-bookworm" + } + } + }, + "UpdateKvResponse": { + "type": "object", + "description": "Response after updating KV service", + "required": [ + "success", + "message", + "status" + ], + "properties": { + "message": { + "type": "string", + "description": "Status message", + "example": "KV service updated successfully" + }, + "status": { + "$ref": "#/components/schemas/KvStatusResponse", + "description": "Current service status" + }, + "success": { + "type": "boolean", + "description": "Whether the operation succeeded" + } + } + }, + "UpdateManagedDomainApiRequest": { + "type": "object", + "description": "Request to update a managed domain's settings.", + "properties": { + "auto_manage": { + "type": [ + "boolean", + "null" + ], + "description": "Toggle automatic DNS management for this domain." + }, + "generated_hostname_mode": { + "type": [ + "string", + "null" + ], + "description": "`\"standard\"` or `\"flat\"`. Persisted as-is; switching to `\"flat\"` does not\nrecompute existing hostnames \u2014 use the apply endpoint for that." + }, + "sync_generated_records": { + "type": [ + "boolean", + "null" + ], + "description": "Toggle DNS record sync for this domain." + } + } + }, + "UpdateMcpRequest": { + "type": "object", + "required": [ + "config" + ], + "properties": { + "config": { + "type": "object" + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": [ + "string", + "null" + ] + } + } + }, + "UpdateMemberRoleRequest": { + "type": "object", + "description": "The new fixed role for an existing membership.", + "required": [ + "role" + ], + "properties": { + "role": { + "$ref": "#/components/schemas/TeamRole" + } + } + }, + "UpdateMetricAlertRequest": { + "type": "object", + "properties": { + "aggregation": { + "type": [ + "string", + "null" + ] + }, + "detection_config": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/DetectionConfig", + "description": "Replaces the detector wholesale when present (absent = leave unchanged)." + } + ] + }, + "dynamic_alerts": { + "type": [ + "boolean", + "null" + ], + "description": "Toggles per-series (\"dynamic\") alerting (absent = leave unchanged)." + }, + "enabled": { + "type": [ + "boolean", + "null" + ] + }, + "for_duration_secs": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "group_by": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + }, + "description": "Replaces the group_by keys wholesale when present (absent = leave unchanged)." + }, + "grouped_notification_threshold": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Updates the notification-grouping threshold (absent = leave unchanged)." + }, + "label_filters": { + "type": [ + "array", + "null" + ], + "items": { + "type": "array", + "items": false, + "prefixItems": [ + { + "type": "string" + }, + { + "type": "string" + } + ] + }, + "description": "Replaces the label filters wholesale when present (absent = leave unchanged)." + }, + "max_series": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Updates the dynamic-alerting cardinality cap (absent = leave unchanged)." + }, + "metric_name": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "severity": { + "type": [ + "string", + "null" + ] + }, + "window_secs": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + } + }, + "UpdateNotificationEmailProviderRequest": { + "type": "object", + "required": [ + "config" + ], + "properties": { + "config": { + "$ref": "#/components/schemas/EmailConfig" + }, + "enabled": { + "type": [ + "boolean", + "null" + ] + }, + "name": { + "type": [ + "string", + "null" + ] + } + } + }, + "UpdateOidcProviderRequest": { + "type": "object", + "properties": { + "client_id": { + "type": [ + "string", + "null" + ] + }, + "client_secret": { + "type": [ + "string", + "null" + ] + }, + "default_role": { + "type": [ + "string", + "null" + ] + }, + "enabled": { + "type": [ + "boolean", + "null" + ] + }, + "group_claim": { + "type": [ + "string", + "null" + ] + }, + "issuer_url": { + "type": [ + "string", + "null" + ] + }, + "jit_provisioning": { + "type": [ + "boolean", + "null" + ] + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "role_claim": { + "type": [ + "string", + "null" + ] + }, + "scopes": { + "type": [ + "string", + "null" + ] + }, + "template": { + "type": [ + "string", + "null" + ] + }, + "trust_idp_email": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "UpdatePreferencesRequest": { + "type": "object", + "required": [ + "preferences" + ], + "properties": { + "preferences": { + "$ref": "#/components/schemas/NotificationPreferencesResponse" + } + } + }, + "UpdateProjectSecretRequest": { + "type": "object", + "description": "Request to update a project secret. The `value` field is optional \u2014 omit it\nto rotate only the environment scoping / preview flag without touching the\nciphertext.", + "properties": { + "environment_ids": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + }, + "include_in_preview": { + "type": "boolean" + }, + "value": { + "type": [ + "string", + "null" + ], + "description": "New plaintext value, <= 1 MiB. Omit to keep the existing value." + } + } + }, + "UpdateProjectSettingsRequest": { + "type": "object", + "properties": { + "ai_alert_summaries_enabled": { + "type": [ + "boolean", + "null" + ], + "description": "Opt in to AI summarization of metric alert notifications (ADR-021)." + }, + "ai_debug_chat_enabled": { + "type": [ + "boolean", + "null" + ], + "description": "Opt in to AI debugging chat, e.g. on deployment failures (ADR-023)." + }, + "ai_write_actions_enabled": { + "type": [ + "boolean", + "null" + ], + "description": "Opt in to AI propose-then-confirm write capability." + }, + "attack_mode": { + "type": [ + "boolean", + "null" + ], + "description": "Enable/disable attack mode (CAPTCHA protection) for all project environments" + }, + "cross_project_trace_sharing": { + "type": [ + "boolean", + "null" + ], + "description": "ADR-027 Phase 3 opt-out: set to false to suppress this project's traces\nfrom appearing in cross-project discovery results. Default true (consistent\nwith the OSS global-observability model). Omit to leave unchanged." + }, + "directory": { + "type": [ + "string", + "null" + ] + }, + "enable_preview_environments": { + "type": [ + "boolean", + "null" + ], + "description": "Enable automatic preview environment creation for each branch" + }, + "error_source_context_enabled": { + "type": [ + "boolean", + "null" + ], + "description": "Opt in to native error-tracking source context (source-file upload +\nsource code shown in stack traces)." + }, + "error_source_root": { + "type": [ + "string", + "null" + ], + "description": "Set the auto-capture source root (relative to the checkout). Send an\nempty string to clear it back to the build-context default. Omit to\nleave unchanged." + }, + "git_provider_connection_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "main_branch": { + "type": [ + "string", + "null" + ] + }, + "preset": { + "type": [ + "string", + "null" + ] + }, + "preset_config": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/PresetConfigSchema", + "description": "Preset-specific configuration (e.g., Dockerfile path for Docker preset)\n\nExample for Dockerfile preset:\n```json\n{\n \"dockerfilePath\": \"docker/Dockerfile\",\n \"buildContext\": \"./api\"\n}\n```" + } + ] + }, + "preview_envs_idle_timeout_seconds": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Idle timeout (seconds, 60..=86400) for on-demand preview environments." + }, + "preview_envs_on_demand": { + "type": [ + "boolean", + "null" + ], + "description": "When true, newly-created preview environments default to on-demand mode." + }, + "preview_envs_wake_timeout_seconds": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Wake timeout (seconds, 5..=120) for on-demand preview environments." + }, + "repo_name": { + "type": [ + "string", + "null" + ] + }, + "repo_owner": { + "type": [ + "string", + "null" + ] + }, + "slug": { + "type": [ + "string", + "null" + ] + } + } + }, + "UpdateProviderCredentialsRequest": { + "type": "object", + "description": "Partial-update payload for provider credentials. Every field is optional;\nonly the fields the user re-enters are applied. The server validates that\nthe fields supplied make sense for the provider's current auth_method\n(e.g. `app_id` + `private_key` only apply to GitHub Apps).", + "properties": { + "app_id": { + "type": [ + "string", + "null" + ], + "description": "Application ID (GitHub App integer as string; GitLab App string)." + }, + "app_secret": { + "type": [ + "string", + "null" + ], + "description": "GitLab App secret (not used by GitHub App \u2014 use `client_secret`)." + }, + "client_id": { + "type": [ + "string", + "null" + ], + "description": "OAuth client ID (GitLab OAuth, GitHub App)." + }, + "client_secret": { + "type": [ + "string", + "null" + ], + "description": "OAuth client secret (GitLab OAuth, GitHub App)." + }, + "private_key": { + "type": [ + "string", + "null" + ], + "description": "GitHub App private key (PEM)." + }, + "redirect_uri": { + "type": [ + "string", + "null" + ], + "description": "OAuth redirect URI (GitLab OAuth / GitLab App)." + }, + "token": { + "type": [ + "string", + "null" + ], + "description": "PAT for PAT-type providers." + }, + "webhook_secret": { + "type": [ + "string", + "null" + ], + "description": "GitHub App webhook secret." + } + } + }, + "UpdateProviderKeyRequest": { + "type": "object", + "properties": { + "api_key": { + "type": [ + "string", + "null" + ] + }, + "base_url": { + "type": [ + "string", + "null" + ], + "description": "Double-Option: absent = leave unchanged, present-null = clear (revert to\nthe provider's default endpoint), present-value = set." + }, + "default_model": { + "type": [ + "string", + "null" + ], + "description": "Double-Option: absent = leave unchanged, present-null = clear the pinned\nmodel (revert to the per-provider default), present-value = set." + }, + "display_name": { + "type": [ + "string", + "null" + ] + }, + "is_active": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "UpdateProviderRequest": { + "type": "object", + "properties": { + "config": {}, + "enabled": { + "type": [ + "boolean", + "null" + ] + }, + "name": { + "type": [ + "string", + "null" + ] + } + } + }, + "UpdateRouteRequest": { + "type": "object", + "required": [ + "host", + "port", + "enabled" + ], + "properties": { + "enabled": { + "type": "boolean" + }, + "host": { + "type": "string" + }, + "port": { + "type": "integer", + "format": "int32" + }, + "route_type": { + "type": [ + "string", + "null" + ], + "description": "Route type: \"http\" (default) matches on HTTP Host header,\n\"tls\" matches on TLS SNI hostname for TCP passthrough" + } + } + }, + "UpdateS3SourceRequest": { + "type": "object", + "properties": { + "access_key_id": { + "type": [ + "string", + "null" + ], + "description": "Optional new access key ID", + "example": "AKIAXXXXXXXXXXXXXXXX" + }, + "bucket_name": { + "type": [ + "string", + "null" + ], + "description": "Optional new bucket name" + }, + "bucket_path": { + "type": [ + "string", + "null" + ], + "description": "Optional new bucket path" + }, + "endpoint": { + "type": [ + "string", + "null" + ], + "description": "Optional new endpoint URL for S3-compatible services", + "example": "http://minio.example.com:9000" + }, + "force_path_style": { + "type": [ + "boolean", + "null" + ], + "description": "Optional new path-style addressing setting", + "example": true + }, + "name": { + "type": [ + "string", + "null" + ], + "description": "Optional new name for the source" + }, + "region": { + "type": [ + "string", + "null" + ], + "description": "Optional new region" + }, + "secret_key": { + "type": [ + "string", + "null" + ], + "description": "Optional new secret key" + } + } + }, + "UpdateSecretBody": { + "type": "object", + "required": [ + "signing_secret" + ], + "properties": { + "signing_secret": { + "type": "string", + "description": "New signing secret from the provider's dashboard. Encrypted at\nrest; never returned in any API response." + } + } + }, + "UpdateSelfRequest": { + "type": "object", + "properties": { + "email": { + "type": [ + "string", + "null" + ], + "example": "john.doe@example.com" + }, + "name": { + "type": [ + "string", + "null" + ], + "example": "John Doe" + } + } + }, + "UpdateSessionDurationRequest": { + "type": "object", + "required": [ + "duration" + ], + "properties": { + "duration": { + "type": "integer", + "format": "int32" + } + } + }, + "UpdateSessionDurationResponse": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } + }, + "UpdateSkillRequest": { + "type": "object", + "properties": { + "content": { + "type": [ + "string", + "null" + ] + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": [ + "string", + "null" + ] + } + } + }, + "UpdateSlackProviderRequest": { + "type": "object", + "required": [ + "config" + ], + "properties": { + "config": { + "$ref": "#/components/schemas/SlackConfig" + }, + "enabled": { + "type": [ + "boolean", + "null" + ] + }, + "name": { + "type": [ + "string", + "null" + ] + } + } + }, + "UpdateSpeedMetricsPayload": { + "type": "object", + "description": "Update speed metrics payload for late-loading metrics", + "properties": { + "cls": { + "type": [ + "number", + "null" + ], + "format": "float", + "description": "Cumulative Layout Shift (score)" + }, + "inp": { + "type": [ + "number", + "null" + ], + "format": "float", + "description": "Interaction to Next Paint (milliseconds)" + } + } + }, + "UpdateStatusResponse": { + "type": "object", + "description": "Result of the background release-update check, driving the web console's\nupgrade banner. All optional fields are set together iff\n`update_available` is true.", + "required": [ + "update_available", + "docs_url" + ], + "properties": { + "channel": { + "type": [ + "string", + "null" + ], + "description": "Channel the install tracks: `stable` or `beta`." + }, + "checked_at": { + "type": [ + "string", + "null" + ], + "description": "When the check that found the update ran (ISO 8601, UTC)." + }, + "current_version": { + "type": [ + "string", + "null" + ], + "description": "Version tag of the running binary, e.g. `v0.1.0-beta.45`." + }, + "docs_url": { + "type": "string", + "description": "Docs page with upgrade instructions. Always present so the UI links\nthe same page regardless of update state." + }, + "latest_version": { + "type": [ + "string", + "null" + ], + "description": "Newest published tag on this install's channel." + }, + "release_url": { + "type": [ + "string", + "null" + ], + "description": "Release-notes page (GitHub release) for the newer version." + }, + "update_available": { + "type": "boolean", + "description": "True when a newer release than the running binary has been published\non this install's channel." + } + } + }, + "UpdateTeamRequest": { + "type": "object", + "properties": { + "description": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": [ + "string", + "null" + ] + } + } + }, + "UpdateTokenRequest": { + "type": "object", + "required": [ + "access_token" + ], + "properties": { + "access_token": { + "type": "string" + }, + "refresh_token": { + "type": [ + "string", + "null" + ] + } + } + }, + "UpdateTokenResponse": { + "type": "object", + "required": [ + "connection_id", + "message", + "is_active" + ], + "properties": { + "connection_id": { + "type": "integer", + "format": "int32" + }, + "is_active": { + "type": "boolean" + }, + "message": { + "type": "string" + } + } + }, + "UpdateUserRequest": { + "type": "object", + "properties": { + "email": { + "type": [ + "string", + "null" + ], + "example": "john.doe@example.com" + }, + "name": { + "type": [ + "string", + "null" + ], + "example": "John Doe" + } + } + }, + "UpdateWebhookProviderRequest": { + "type": "object", + "required": [ + "config" + ], + "properties": { + "config": { + "$ref": "#/components/schemas/WebhookConfig" + }, + "enabled": { + "type": [ + "boolean", + "null" + ] + }, + "name": { + "type": [ + "string", + "null" + ] + } + } + }, + "UpdateWebhookRequestBody": { + "type": "object", + "properties": { + "enabled": { + "type": [ + "boolean", + "null" + ], + "description": "Whether the webhook is enabled" + }, + "events": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + }, + "description": "Event types to subscribe to" + }, + "secret": { + "type": [ + "string", + "null" + ], + "description": "Secret for HMAC signature verification" + }, + "url": { + "type": [ + "string", + "null" + ], + "description": "Target URL for webhook delivery" + } + } + }, + "UpgradeExternalServiceRequest": { + "type": "object", + "required": [ + "docker_image" + ], + "properties": { + "docker_image": { + "type": "string", + "description": "Docker image to upgrade to (e.g., \"gotempsh/postgres-walg:18-bookworm\")\nThis will trigger pg_upgrade for PostgreSQL or equivalent upgrade procedures for other services", + "example": "gotempsh/postgres-walg:18-bookworm" + } + } + }, + "UpgradeRequest": { + "type": "object", + "required": [ + "image" + ], + "properties": { + "image": { + "type": "string", + "description": "Image reference to pull and run (e.g.\n`ghcr.io/gotempsh/temps-preview-gateway:latest`). Empty resets to default." + } + } + }, + "UpsertAgentRequest": { + "type": "object", + "properties": { + "ai_model": { + "type": [ + "string", + "null" + ], + "description": "Preferred model identifier for the CLI. `Some(\"\")` clears the stored value." + }, + "ai_provider": { + "type": [ + "string", + "null" + ] + }, + "ai_provider_key_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "api_key": { + "type": [ + "string", + "null" + ], + "description": "Plain-text API key \u2014 will be encrypted before storage" + }, + "branch_prefix": { + "type": [ + "string", + "null" + ] + }, + "config_repo_branch": { + "type": [ + "string", + "null" + ], + "description": "Branch of the config repo to use (default: \"main\")." + }, + "config_repo_url": { + "type": [ + "string", + "null" + ], + "description": "Private config repo containing .claude/ directory (skills, MCP, plugins)." + }, + "cooldown_minutes": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "daily_budget_cents": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "deliverable": { + "type": [ + "string", + "null" + ] + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "enabled": { + "type": [ + "boolean", + "null" + ] + }, + "max_turns": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "mcp_servers_config": { + "description": "MCP servers config (Claude Code settings.json mcpServers format).\nCredential-bearing legacy inline objects are write-only: normal reads\nmask them, and updates must omit this field to preserve existing values." + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "prompt": { + "type": [ + "string", + "null" + ] + }, + "sandbox_enabled": { + "type": [ + "boolean", + "null" + ] + }, + "skills_config": { + "description": "Skills config as JSON array." + }, + "slug": { + "type": [ + "string", + "null" + ] + }, + "timeout_seconds": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "tools_config": { + "description": "Tools config as JSON array. Custom-tool webhook URLs and headers are\nwrite-only; omit this field on update to preserve them." + }, + "trigger_config": { + "description": "Trigger configuration JSON: { \"error\": { \"new_issue\": true, \"regression\": true }, \"manual\": true }" + } + } + }, + "UpsertSecretRequest": { + "type": "object", + "required": [ + "name", + "value" + ], + "properties": { + "description": { + "type": [ + "string", + "null" + ] + }, + "mount_path": { + "type": [ + "string", + "null" + ], + "description": "Required for \"file\" type secrets \u2014 absolute path inside the sandbox" + }, + "name": { + "type": "string" + }, + "secret_type": { + "type": "string", + "description": "\"env\" (environment variable) or \"file\" (written to mount_path)" + }, + "value": { + "type": "string" + } + } + }, + "UptimeDataPoint": { + "type": "object", + "required": [ + "timestamp", + "status" + ], + "properties": { + "error_message": { + "type": [ + "string", + "null" + ] + }, + "response_time_ms": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "status": { + "type": "string" + }, + "timestamp": { + "type": "string", + "format": "date-time" + } + } + }, + "UptimeHistoryResponse": { + "type": "object", + "required": [ + "monitor_id", + "uptime_data" + ], + "properties": { + "monitor_id": { + "type": "integer", + "format": "int32" + }, + "uptime_data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UptimeDataPoint" + } + } + } + }, + "UsageFilter": { + "type": "object", + "description": "Filters for querying AI usage data.\n\nCost bounds are expressed in microcents (the unit stored in\n`estimated_cost_microcents`). At most one of `gte`/`gt` and one of\n`lte`/`lt` is meaningful per query; if both are set the stricter wins\nnaturally because they are ANDead together.", + "properties": { + "conversation_id": { + "type": [ + "string", + "null" + ] + }, + "cost_gt": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Cost strictly greater-than, in microcents." + }, + "cost_gte": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Cost greater-than-or-equal, in microcents." + }, + "cost_lt": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Cost strictly less-than, in microcents." + }, + "cost_lte": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Cost less-than-or-equal, in microcents." + }, + "model": { + "type": [ + "string", + "null" + ] + }, + "provider": { + "type": [ + "string", + "null" + ] + }, + "status": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Filter by HTTP status code (exact match)." + }, + "tags": { + "type": [ + "string", + "null" + ], + "description": "Comma-separated tags to filter by (AND logic)." + }, + "tokens_gt": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Total tokens (input + output) strictly greater-than." + }, + "tokens_gte": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Total tokens (input + output) greater-than-or-equal." + }, + "tokens_lt": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Total tokens (input + output) strictly less-than." + }, + "tokens_lte": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Total tokens (input + output) less-than-or-equal." + }, + "user_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + } + }, + "UsageInfo": { + "type": "object", + "required": [ + "prompt_tokens", + "completion_tokens", + "total_tokens" + ], + "properties": { + "completion_tokens": { + "type": "integer", + "format": "int64" + }, + "prompt_tokens": { + "type": "integer", + "format": "int64" + }, + "total_tokens": { + "type": "integer", + "format": "int64" + } + } + }, + "UsageLogEntry": { + "type": "object", + "required": [ + "id", + "timestamp", + "provider", + "model", + "input_tokens", + "output_tokens", + "latency_ms", + "estimated_cost_microcents", + "status", + "is_streaming", + "is_byok", + "tags" + ], + "properties": { + "conversation_id": { + "type": [ + "string", + "null" + ] + }, + "estimated_cost_microcents": { + "type": "integer", + "format": "int64" + }, + "id": { + "type": "integer", + "format": "int64" + }, + "input_tokens": { + "type": "integer", + "format": "int64" + }, + "is_byok": { + "type": "boolean" + }, + "is_streaming": { + "type": "boolean" + }, + "latency_ms": { + "type": "integer", + "format": "int32" + }, + "model": { + "type": "string" + }, + "output_tokens": { + "type": "integer", + "format": "int64" + }, + "provider": { + "type": "string" + }, + "request_id": { + "type": [ + "string", + "null" + ] + }, + "status": { + "type": "integer", + "format": "int32" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + } + }, + "timestamp": { + "type": "string" + }, + "trace_id": { + "type": [ + "string", + "null" + ] + } + } + }, + "UsageLogPage": { + "type": "object", + "description": "A page of recent usage log entries plus the total count for pagination.", + "required": [ + "entries", + "total" + ], + "properties": { + "entries": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UsageLogEntry" + }, + "description": "The usage log entries for the requested page." + }, + "total": { + "type": "integer", + "format": "int64", + "description": "Total number of entries matching the filter (across all pages)." + } + } + }, + "UsageQueryParams": { + "type": "object", + "properties": { + "conversation_id": { + "type": [ + "string", + "null" + ], + "description": "Filter by conversation ID" + }, + "from": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 start time (defaults to 24h ago)" + }, + "model": { + "type": [ + "string", + "null" + ], + "description": "Filter by model name" + }, + "provider": { + "type": [ + "string", + "null" + ], + "description": "Filter by provider name" + }, + "tags": { + "type": [ + "string", + "null" + ], + "description": "Filter by tags (comma-separated, AND logic)" + }, + "to": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 end time (defaults to now)" + }, + "user_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Filter by user ID" + } + } + }, + "UsageSource": { + "type": "string", + "description": "How the \"actual usage\" numbers were obtained", + "enum": [ + "metrics-api", + "requests-only", + "unavailable" + ] + }, + "UsageSummary": { + "type": "object", + "required": [ + "total_requests", + "total_input_tokens", + "total_output_tokens", + "total_tokens", + "avg_latency_ms", + "total_cost_microcents", + "error_count", + "streaming_count", + "byok_count" + ], + "properties": { + "avg_latency_ms": { + "type": "number", + "format": "double" + }, + "byok_count": { + "type": "integer", + "format": "int64" + }, + "error_count": { + "type": "integer", + "format": "int64" + }, + "streaming_count": { + "type": "integer", + "format": "int64" + }, + "total_cost_microcents": { + "type": "integer", + "format": "int64" + }, + "total_input_tokens": { + "type": "integer", + "format": "int64" + }, + "total_output_tokens": { + "type": "integer", + "format": "int64" + }, + "total_requests": { + "type": "integer", + "format": "int64" + }, + "total_tokens": { + "type": "integer", + "format": "int64" + } + } + }, + "UserResponse": { + "type": "object", + "required": [ + "id", + "username", + "name", + "avatar_url", + "mfa_enabled", + "role" + ], + "properties": { + "avatar_url": { + "type": "string" + }, + "email": { + "type": [ + "string", + "null" + ] + }, + "id": { + "type": "integer", + "format": "int32" + }, + "mfa_enabled": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "role": { + "type": "string", + "description": "User's role (e.g., \"admin\", \"user\", \"demo\")" + }, + "username": { + "type": "string" + } + } + }, + "ValidateEmailRequest": { + "type": "object", + "description": "Request body for validating an email address", + "required": [ + "email" + ], + "properties": { + "email": { + "type": "string", + "description": "Email address to validate", + "example": "someone@gmail.com" + } + }, + "additionalProperties": false + }, + "ValidateEmailResponse": { + "type": "object", + "description": "Complete email validation response", + "required": [ + "email", + "is_reachable", + "syntax", + "mx", + "misc", + "smtp" + ], + "properties": { + "email": { + "type": "string", + "description": "The email address that was validated", + "example": "someone@gmail.com" + }, + "is_reachable": { + "$ref": "#/components/schemas/ReachabilityStatus", + "description": "Overall reachability status: safe, risky, invalid, or unknown" + }, + "misc": { + "$ref": "#/components/schemas/MiscResult", + "description": "Miscellaneous validation result" + }, + "mx": { + "$ref": "#/components/schemas/MxResult", + "description": "MX record validation result" + }, + "smtp": { + "$ref": "#/components/schemas/SmtpResult", + "description": "SMTP validation result" + }, + "syntax": { + "$ref": "#/components/schemas/SyntaxResult", + "description": "Syntax validation result" + } + } + }, + "ValidationLevel": { + "type": "string", + "description": "Validation severity level", + "enum": [ + "info", + "warning", + "error", + "critical" + ] + }, + "ValidationReport": { + "type": "object", + "description": "Complete validation report", + "required": [ + "results", + "overall_status", + "summary" + ], + "properties": { + "overall_status": { + "$ref": "#/components/schemas/ValidationStatus", + "description": "Overall status" + }, + "results": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ValidationResult" + }, + "description": "All validation results" + }, + "summary": { + "$ref": "#/components/schemas/ValidationSummary", + "description": "Summary statistics" + } + } + }, + "ValidationResponse": { + "type": "object", + "required": [ + "connection_id", + "is_valid", + "message" + ], + "properties": { + "connection_id": { + "type": "integer", + "format": "int32" + }, + "is_valid": { + "type": "boolean" + }, + "message": { + "type": "string" + } + } + }, + "ValidationResult": { + "type": "object", + "description": "Result of a validation check", + "required": [ + "rule_id", + "rule_name", + "level", + "passed", + "message", + "affected_resources" + ], + "properties": { + "affected_resources": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Affected resources/fields" + }, + "level": { + "$ref": "#/components/schemas/ValidationLevel", + "description": "Validation level" + }, + "message": { + "type": "string", + "description": "Message describing the result" + }, + "passed": { + "type": "boolean", + "description": "Whether the validation passed" + }, + "remediation": { + "type": [ + "string", + "null" + ], + "description": "Suggested remediation (if failed)" + }, + "rule_id": { + "type": "string", + "description": "Rule that was checked" + }, + "rule_name": { + "type": "string", + "description": "Human-readable rule name" + } + } + }, + "ValidationStatus": { + "type": "string", + "description": "Overall validation status", + "enum": [ + "passed", + "passed-with-warnings", + "failed-with-warnings", + "failed" + ] + }, + "ValidationSummary": { + "type": "object", + "description": "Validation summary statistics", + "required": [ + "total_count", + "passed_count", + "failed_count", + "info_count", + "warning_count", + "error_count", + "critical_count" + ], + "properties": { + "critical_count": { + "type": "integer", + "description": "Critical-level results", + "minimum": 0 + }, + "error_count": { + "type": "integer", + "description": "Error-level results", + "minimum": 0 + }, + "failed_count": { + "type": "integer", + "description": "Validations that failed", + "minimum": 0 + }, + "info_count": { + "type": "integer", + "description": "Info-level results", + "minimum": 0 + }, + "passed_count": { + "type": "integer", + "description": "Validations that passed", + "minimum": 0 + }, + "total_count": { + "type": "integer", + "description": "Total validations run", + "minimum": 0 + }, + "warning_count": { + "type": "integer", + "description": "Warning-level results", + "minimum": 0 + } + } + }, + "VerifyMfaRequest": { + "type": "object", + "required": [ + "code" + ], + "properties": { + "code": { + "type": "string" + } + } + }, + "VerifyStepUpRequest": { + "type": "object", + "required": [ + "code" + ], + "properties": { + "code": { + "type": "string", + "description": "Current TOTP value or an unused recovery code." + } + } + }, + "ViewItem": { + "type": "object", + "required": [ + "label", + "value" + ], + "properties": { + "label": { + "type": "string", + "format": "date-time" + }, + "value": { + "type": "integer", + "format": "int64" + } + } + }, + "ViewsOverTime": { + "type": "object", + "required": [ + "items", + "metric", + "present_index" + ], + "properties": { + "comparison_labels": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "comparison_plot": { + "type": [ + "array", + "null" + ], + "items": { + "type": "integer", + "format": "int64" + } + }, + "full_intervals": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ViewItem" + } + }, + "metric": { + "type": "string" + }, + "present_index": { + "type": "integer", + "minimum": 0 + } + } + }, + "ViewsOverTimeQuery": { + "type": "object", + "required": [ + "start_date", + "end_date", + "project_id" + ], + "properties": { + "deployment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "end_date": { + "type": "string", + "format": "date-time" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "start_date": { + "type": "string", + "format": "date-time" + } + } + }, + "VisitorDetails": { + "type": "object", + "required": [ + "id", + "visitor_id", + "project_id", + "environment_id", + "first_seen", + "last_seen", + "is_crawler" + ], + "properties": { + "city": { + "type": [ + "string", + "null" + ] + }, + "country": { + "type": [ + "string", + "null" + ] + }, + "country_code": { + "type": [ + "string", + "null" + ] + }, + "crawler_name": { + "type": [ + "string", + "null" + ] + }, + "custom_data": {}, + "environment_id": { + "type": "integer", + "format": "int32" + }, + "first_channel": { + "type": [ + "string", + "null" + ], + "description": "Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")" + }, + "first_referrer": { + "type": [ + "string", + "null" + ], + "description": "Full referrer URL from the visitor's first session" + }, + "first_referrer_hostname": { + "type": [ + "string", + "null" + ], + "description": "Hostname extracted from first_referrer" + }, + "first_seen": { + "type": "string", + "format": "date-time", + "example": "2024-01-01T00:00:00" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "ip_address": { + "type": [ + "string", + "null" + ] + }, + "ip_address_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "is_crawler": { + "type": "boolean" + }, + "is_eu": { + "type": [ + "boolean", + "null" + ] + }, + "last_seen": { + "type": "string", + "format": "date-time", + "example": "2024-01-01T00:00:00" + }, + "latitude": { + "type": [ + "number", + "null" + ], + "format": "double" + }, + "longitude": { + "type": [ + "number", + "null" + ], + "format": "double" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "region": { + "type": [ + "string", + "null" + ] + }, + "timezone": { + "type": [ + "string", + "null" + ] + }, + "user_agent": { + "type": [ + "string", + "null" + ] + }, + "visitor_id": { + "type": "string" + } + } + }, + "VisitorFacetValue": { + "type": "object", + "description": "A single facet value with its visitor count. Used to populate filter\ndropdowns on the visitors page (e.g. \"Germany \u2014 1,234 visitors\").", + "required": [ + "value", + "count" + ], + "properties": { + "code": { + "type": [ + "string", + "null" + ], + "description": "Optional secondary code for the value. Currently only populated for\nthe `country` facet, where it carries the 2-letter ISO country code\nso the UI can render a flag without re-mapping." + }, + "count": { + "type": "integer", + "format": "int64", + "description": "Distinct visitor count matching this value in the current segment." + }, + "value": { + "type": "string", + "description": "The dimension value (e.g. \"United States\", \"Chrome\", \"google.com\").\n`None` is encoded as the literal string \"Direct\" for referrer and as\nthe empty string for the rest." + } + } + }, + "VisitorFacets": { + "type": "object", + "description": "All filter dropdown contents in one response. Each list is the top N\nvalues for that dimension within the current date range and segment\n(excluding the dimension being queried so the dropdown still shows\nalternatives when a value is already selected).", + "required": [ + "country", + "region", + "city", + "channel", + "referrer" + ], + "properties": { + "channel": { + "type": "array", + "items": { + "$ref": "#/components/schemas/VisitorFacetValue" + } + }, + "city": { + "type": "array", + "items": { + "$ref": "#/components/schemas/VisitorFacetValue" + } + }, + "country": { + "type": "array", + "items": { + "$ref": "#/components/schemas/VisitorFacetValue" + } + }, + "referrer": { + "type": "array", + "items": { + "$ref": "#/components/schemas/VisitorFacetValue" + } + }, + "region": { + "type": "array", + "items": { + "$ref": "#/components/schemas/VisitorFacetValue" + } + } + } + }, + "VisitorFacetsQuery": { + "allOf": [ + { + "$ref": "#/components/schemas/VisitorSegmentFilters" + }, + { + "type": "object", + "required": [ + "start_date", + "end_date", + "project_id" + ], + "properties": { + "end_date": { + "type": "string", + "format": "date-time" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "has_activity_only": { + "type": [ + "boolean", + "null" + ] + }, + "include_crawlers": { + "type": [ + "boolean", + "null" + ] + }, + "per_facet_limit": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Maximum number of values returned per dimension (default: 50, max: 200)." + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "start_date": { + "type": "string", + "format": "date-time" + } + } + } + ], + "description": "Query parameters for the visitor-facets endpoint. Mirrors the shape of\n`VisitorsListQuery` so the same segment filters apply \u2014 facet counts are\nalways computed against the *currently filtered* visitor pool, minus the\ndimension being aggregated." + }, + "VisitorInfo": { + "type": "object", + "required": [ + "id", + "visitor_id", + "project_id", + "environment_id", + "first_seen", + "last_seen", + "is_crawler" + ], + "properties": { + "city": { + "type": [ + "string", + "null" + ] + }, + "country": { + "type": [ + "string", + "null" + ] + }, + "country_code": { + "type": [ + "string", + "null" + ] + }, + "crawler_name": { + "type": [ + "string", + "null" + ] + }, + "current_page": { + "type": [ + "string", + "null" + ], + "description": "Most recent page path visited by this visitor" + }, + "custom_data": {}, + "environment_id": { + "type": "integer", + "format": "int32" + }, + "first_channel": { + "type": [ + "string", + "null" + ], + "description": "Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")" + }, + "first_referrer": { + "type": [ + "string", + "null" + ], + "description": "Full referrer URL from the visitor's first session" + }, + "first_referrer_hostname": { + "type": [ + "string", + "null" + ], + "description": "Hostname extracted from first_referrer" + }, + "first_seen": { + "type": "string", + "format": "date-time", + "example": "2024-01-01T00:00:00" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "ip_address": { + "type": [ + "string", + "null" + ] + }, + "ip_address_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "is_crawler": { + "type": "boolean" + }, + "is_eu": { + "type": [ + "boolean", + "null" + ] + }, + "last_seen": { + "type": "string", + "format": "date-time", + "example": "2024-01-01T00:00:00" + }, + "latitude": { + "type": [ + "number", + "null" + ], + "format": "double" + }, + "longitude": { + "type": [ + "number", + "null" + ], + "format": "double" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "region": { + "type": [ + "string", + "null" + ] + }, + "timezone": { + "type": [ + "string", + "null" + ] + }, + "user_agent": { + "type": [ + "string", + "null" + ] + }, + "visitor_id": { + "type": "string" + } + } + }, + "VisitorJourneyQuery": { + "type": "object", + "required": [ + "project_id" + ], + "properties": { + "limit_sessions": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "project_id": { + "type": "integer", + "format": "int32" + } + } + }, + "VisitorJourneyResponse": { + "type": "object", + "description": "Complete visitor journey response", + "required": [ + "visitor_id", + "total_sessions", + "total_events", + "sessions" + ], + "properties": { + "sessions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/JourneySession" + }, + "description": "Sessions with their events, ordered newest first" + }, + "total_events": { + "type": "integer", + "format": "int64", + "description": "Total number of events across all sessions" + }, + "total_sessions": { + "type": "integer", + "format": "int64", + "description": "Total number of sessions" + }, + "visitor_id": { + "type": "integer", + "format": "int32", + "description": "Visitor internal ID" + } + } + }, + "VisitorLocationsQuery": { + "type": "object", + "required": [ + "start_date", + "end_date", + "project_id" + ], + "properties": { + "end_date": { + "type": "string", + "format": "date-time" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "granularity": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/LocationGranularity" + } + ] + }, + "limit": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "start_date": { + "type": "string", + "format": "date-time" + } + } + }, + "VisitorRecord": { + "type": "object", + "required": [ + "id", + "visitor_id", + "project_id", + "created_at" + ], + "properties": { + "created_at": { + "type": "string", + "format": "date-time", + "example": "2024-01-01T00:00:00" + }, + "custom_data": {}, + "id": { + "type": "integer", + "format": "int32" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "visitor_id": { + "type": "string" + } + } + }, + "VisitorSegmentFilters": { + "type": "object", + "description": "Optional segment filters for [`VisitorsListQuery`]. Each filter narrows the\nresult set to visitors who match the given dimension value within the date\nrange. All filters resolve against `visitor` / `ip_geolocations` \u2014 by\ndesign we never touch the events hypertable here so filtering stays fast\nregardless of event volume.", + "properties": { + "filter_channel": { + "type": [ + "string", + "null" + ], + "description": "First-touch marketing channel (matches `visitor.first_channel`)" + }, + "filter_city": { + "type": [ + "string", + "null" + ], + "description": "Geolocation city (matches `ip_geolocations.city`)" + }, + "filter_country": { + "type": [ + "string", + "null" + ], + "description": "Geolocation country (matches `ip_geolocations.country`)" + }, + "filter_referrer": { + "type": [ + "string", + "null" + ], + "description": "First-touch referrer hostname (matches `visitor.first_referrer_hostname`)" + }, + "filter_region": { + "type": [ + "string", + "null" + ], + "description": "Geolocation region (matches `ip_geolocations.region`)" + } + } + }, + "VisitorSessionsQuery": { + "type": "object", + "required": [ + "project_id" + ], + "properties": { + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "limit": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "project_id": { + "type": "integer", + "format": "int32" + } + } + }, + "VisitorSessionsResponse": { + "type": "object", + "required": [ + "visitor_id", + "sessions", + "total_sessions" + ], + "properties": { + "sessions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SessionSummary" + } + }, + "total_sessions": { + "type": "integer", + "format": "int64" + }, + "visitor_id": { + "type": "string" + } + } + }, + "VisitorStats": { + "type": "object", + "required": [ + "visitor_id", + "first_seen", + "last_seen", + "total_sessions", + "total_page_views", + "total_events", + "average_session_duration", + "bounce_rate", + "engagement_rate", + "top_pages", + "top_referrers", + "devices_used", + "locations" + ], + "properties": { + "average_session_duration": { + "type": "number", + "format": "double" + }, + "bounce_rate": { + "type": "number", + "format": "double" + }, + "devices_used": { + "type": "array", + "items": { + "type": "string" + } + }, + "engagement_rate": { + "type": "number", + "format": "double" + }, + "first_seen": { + "type": "string", + "format": "date-time", + "example": "2024-01-01T00:00:00" + }, + "last_seen": { + "type": "string", + "format": "date-time", + "example": "2024-01-01T00:00:00" + }, + "locations": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LocationInfo" + } + }, + "top_pages": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PageVisit" + } + }, + "top_referrers": { + "type": "array", + "items": { + "type": "string" + } + }, + "total_events": { + "type": "integer", + "format": "int64" + }, + "total_page_views": { + "type": "integer", + "format": "int64" + }, + "total_sessions": { + "type": "integer", + "format": "int64" + }, + "visitor_id": { + "type": "integer", + "format": "int32" + } + } + }, + "VisitorWithGeolocation": { + "type": "object", + "required": [ + "id", + "visitor_id", + "project_id", + "environment_id", + "first_seen", + "last_seen", + "is_crawler" + ], + "properties": { + "city": { + "type": [ + "string", + "null" + ] + }, + "country": { + "type": [ + "string", + "null" + ] + }, + "country_code": { + "type": [ + "string", + "null" + ] + }, + "crawler_name": { + "type": [ + "string", + "null" + ] + }, + "custom_data": {}, + "environment_id": { + "type": "integer", + "format": "int32" + }, + "first_channel": { + "type": [ + "string", + "null" + ], + "description": "Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")" + }, + "first_referrer": { + "type": [ + "string", + "null" + ], + "description": "Full referrer URL from the visitor's first session" + }, + "first_referrer_hostname": { + "type": [ + "string", + "null" + ], + "description": "Hostname extracted from first_referrer" + }, + "first_seen": { + "type": "string", + "format": "date-time", + "example": "2024-01-01T00:00:00" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "ip_address": { + "type": [ + "string", + "null" + ] + }, + "is_crawler": { + "type": "boolean" + }, + "is_eu": { + "type": [ + "boolean", + "null" + ] + }, + "last_seen": { + "type": "string", + "format": "date-time", + "example": "2024-01-01T00:00:00" + }, + "latitude": { + "type": [ + "number", + "null" + ], + "format": "double" + }, + "longitude": { + "type": [ + "number", + "null" + ], + "format": "double" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "region": { + "type": [ + "string", + "null" + ] + }, + "timezone": { + "type": [ + "string", + "null" + ] + }, + "user_agent": { + "type": [ + "string", + "null" + ] + }, + "visitor_id": { + "type": "string" + } + } + }, + "VisitorsListQuery": { + "allOf": [ + { + "$ref": "#/components/schemas/VisitorSegmentFilters" + }, + { + "type": "object", + "required": [ + "start_date", + "end_date", + "project_id" + ], + "properties": { + "end_date": { + "type": "string", + "format": "date-time" + }, + "environment_id": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "has_activity_only": { + "type": [ + "boolean", + "null" + ], + "description": "Filter to only include visitors with recorded activity (events/sessions).\nWhen true, excludes \"ghost\" visitors that have no events." + }, + "include_crawlers": { + "type": [ + "boolean", + "null" + ] + }, + "limit": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "offset": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "start_date": { + "type": "string", + "format": "date-time" + } + } + } + ] + }, + "VisitorsResponse": { + "type": "object", + "required": [ + "visitors", + "total_count", + "filtered_count" + ], + "properties": { + "filtered_count": { + "type": "integer", + "format": "int64" + }, + "total_count": { + "type": "integer", + "format": "int64" + }, + "visitors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/VisitorInfo" + } + } + } + }, + "VolumeMount": { + "type": "object", + "description": "Volume mount in deployment", + "required": [ + "source", + "destination", + "read_only", + "type" + ], + "properties": { + "destination": { + "type": "string", + "description": "Destination path in container" + }, + "read_only": { + "type": "boolean", + "description": "Read-only flag" + }, + "source": { + "type": "string", + "description": "Source (volume name or path)" + }, + "type": { + "$ref": "#/components/schemas/VolumeType", + "description": "Volume type" + } + } + }, + "VolumeType": { + "type": "string", + "description": "Volume type", + "enum": [ + "bind", + "volume", + "tmpfs" + ] + }, + "VulnerabilityResponse": { + "type": "object", + "required": [ + "id", + "scan_id", + "vulnerability_id", + "package_name", + "installed_version", + "severity", + "title", + "created_at" + ], + "properties": { + "class": { + "type": [ + "string", + "null" + ], + "example": "os-pkgs" + }, + "created_at": { + "type": "string", + "example": "2025-12-08T12:15:47.609192Z" + }, + "cvss_score": { + "type": [ + "number", + "null" + ], + "format": "float" + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "fixed_version": { + "type": [ + "string", + "null" + ] + }, + "id": { + "type": "integer", + "format": "int32" + }, + "installed_version": { + "type": "string" + }, + "last_modified_date": { + "type": [ + "string", + "null" + ], + "example": "2025-12-08T12:15:47.609192Z" + }, + "package_name": { + "type": "string" + }, + "primary_url": { + "type": [ + "string", + "null" + ] + }, + "published_date": { + "type": [ + "string", + "null" + ], + "example": "2025-12-08T12:15:47.609192Z" + }, + "references": {}, + "scan_id": { + "type": "integer", + "format": "int32" + }, + "severity": { + "type": "string" + }, + "target": { + "type": [ + "string", + "null" + ], + "example": "alpine:3.18 (alpine 3.18.0)" + }, + "title": { + "type": "string" + }, + "type": { + "type": [ + "string", + "null" + ], + "example": "alpine" + }, + "vulnerability_id": { + "type": "string" + } + } + }, + "WalWarning": { + "oneOf": [ + { + "type": "object", + "description": "`pg_wal` is significantly larger than `max_wal_size`.", + "required": [ + "pg_wal_bytes", + "max_wal_size_bytes", + "ratio", + "kind" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "wal_bloat" + ] + }, + "max_wal_size_bytes": { + "type": "integer", + "format": "int64" + }, + "pg_wal_bytes": { + "type": "integer", + "format": "int64" + }, + "ratio": { + "type": "number", + "format": "double" + } + } + }, + { + "type": "object", + "description": "A replication slot is holding WAL it's not consuming.", + "required": [ + "slot_name", + "retained_bytes", + "active", + "kind" + ], + "properties": { + "active": { + "type": "boolean" + }, + "kind": { + "type": "string", + "enum": [ + "stale_slot" + ] + }, + "retained_bytes": { + "type": "integer", + "format": "int64" + }, + "slot_name": { + "type": "string" + } + } + }, + { + "type": "object", + "description": "`archive_status/*.ready` count exceeds threshold \u2014 `archive_command`\nis either failing or running slower than WAL generation.", + "required": [ + "ready_count", + "kind" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "archive_backlog" + ] + }, + "ready_count": { + "type": "integer", + "format": "int64" + } + } + }, + { + "type": "object", + "description": "`archive_mode = on` but `archive_command` is empty / `/bin/true`.\nWAL accumulates forever waiting for a destination that never accepts.", + "required": [ + "kind" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "archive_mode_without_command" + ] + } + } + }, + { + "type": "object", + "description": "Oldest WAL segment is older than `WAL_NOT_RECYCLED_AGE_SECS`.\nIndependent signal: something is blocking recycling even if total\nsize hasn't exploded yet.", + "required": [ + "oldest_age_secs", + "kind" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "wal_not_recycled" + ] + }, + "oldest_age_secs": { + "type": "integer", + "format": "int64" + } + } + } + ], + "description": "One actionable warning surfaced to the UI.\n\nEach variant carries the data needed to render a remediation hint without\nthe frontend re-querying anything." + }, + "WalWarningSeverity": { + "type": "string", + "enum": [ + "warning", + "critical" + ] + }, + "WebhookConfig": { + "type": "object", + "description": "Configuration for a generic webhook notification provider", + "required": [ + "url" + ], + "properties": { + "headers": { + "type": "object", + "description": "Custom headers to include in the request (e.g., for authentication tokens)", + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + }, + "example": { + "Authorization": "Bearer your-token", + "X-Custom-Header": "custom-value" + } + }, + "method": { + "type": "string", + "description": "HTTP method to use (POST, PUT, PATCH). Defaults to POST.", + "example": "POST" + }, + "timeout_secs": { + "type": "integer", + "format": "int64", + "description": "Request timeout in seconds. Defaults to 30.", + "example": 30, + "minimum": 0 + }, + "url": { + "type": "string", + "description": "The URL to send webhook requests to", + "example": "https://api.example.com/notifications" + } + } + }, + "WebhookDeliveryResponse": { + "type": "object", + "required": [ + "id", + "webhook_id", + "event_type", + "event_id", + "payload", + "success", + "attempt_number", + "created_at" + ], + "properties": { + "attempt_number": { + "type": "integer", + "format": "int32" + }, + "created_at": { + "type": "string", + "format": "date-time", + "example": "2025-10-12T12:15:47.609192Z" + }, + "delivered_at": { + "type": [ + "string", + "null" + ], + "format": "date-time" + }, + "error_message": { + "type": [ + "string", + "null" + ] + }, + "event_id": { + "type": "string" + }, + "event_type": { + "type": "string" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "payload": { + "type": "string", + "description": "JSON payload that was sent to the webhook endpoint", + "example": { + "event_type": "deployment.succeeded", + "data": { + "deployment_id": 123 + } + } + }, + "status_code": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "success": { + "type": "boolean" + }, + "webhook_id": { + "type": "integer", + "format": "int32" + } + } + }, + "WebhookResponse": { + "type": "object", + "required": [ + "id", + "project_id", + "url", + "events", + "enabled", + "has_secret", + "created_at", + "updated_at" + ], + "properties": { + "created_at": { + "type": "string", + "format": "date-time", + "example": "2025-10-12T12:15:47.609192Z" + }, + "enabled": { + "type": "boolean" + }, + "events": { + "type": "array", + "items": { + "type": "string" + } + }, + "has_secret": { + "type": "boolean" + }, + "id": { + "type": "integer", + "format": "int32" + }, + "project_id": { + "type": "integer", + "format": "int32" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "example": "2025-10-12T12:15:47.609192Z" + }, + "url": { + "type": "string" + } + } + }, + "WebhookTriggerRequest": { + "allOf": [ + { + "description": "Arbitrary JSON payload from the caller. Passed to the agent as user_context." + } + ] + }, + "WebhookTriggerResponse": { + "type": "object", + "required": [ + "run_id", + "status" + ], + "properties": { + "run_id": { + "type": "integer", + "format": "int32" + }, + "status": { + "type": "string" + } + } + }, + "WorkflowDryRunRequest": { + "type": "object", + "required": [ + "yaml" + ], + "properties": { + "cpu_limit": { + "type": [ + "number", + "null" + ], + "format": "double", + "description": "Optional CPU override applied after parsing YAML (clamped server-side).\nWhen `Some`, this takes precedence over `cpu_limit` inside the YAML \u2014\nlets the CLI pass `--cpu` without rewriting the YAML text." + }, + "error_group_id": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Optional error group to link this dry-run to. When set, the executor's\n`load_error_context` path injects `{{error_type}}` / `{{error_message}}`\n/ `{{stack_trace}}` into the prompt \u2014 same behaviour as a committed\nworkflow triggered with `trigger_source_type = \"error_group\"`. Must\nbelong to `project_id` (handler enforces)." + }, + "memory_limit_mb": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Optional memory override in MB (clamped server-side). Same precedence\nrule as `cpu_limit`.", + "minimum": 0 + }, + "user_context": { + "type": [ + "string", + "null" + ], + "description": "Optional context appended to the prompt (e.g. \"test against staging\nonly\"). Mirrors `TriggerAgentRequest.user_context`." + }, + "yaml": { + "type": "string", + "description": "Full WorkflowYamlConfig as YAML text. Server validates and re-serializes\nbefore storing on the run row." + } + } + }, + "WorkloadDescriptor": { + "type": "object", + "description": "Brief descriptor for discovered workloads (used in listing)", + "required": [ + "id", + "workload_type", + "status", + "labels" + ], + "properties": { + "created_at": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "Creation timestamp" + }, + "id": { + "$ref": "#/components/schemas/WorkloadId", + "description": "Unique ID in source system" + }, + "image": { + "type": [ + "string", + "null" + ], + "description": "Image/build reference (for containers)" + }, + "labels": { + "type": "object", + "description": "Labels/tags from source system", + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + } + }, + "name": { + "type": [ + "string", + "null" + ], + "description": "Workload name (if any)" + }, + "status": { + "$ref": "#/components/schemas/WorkloadStatus", + "description": "Current status" + }, + "workload_type": { + "$ref": "#/components/schemas/WorkloadType", + "description": "Workload type (container, function, static-site, etc.)" + } + } + }, + "WorkloadId": { + "type": "string", + "description": "Unique identifier for a workload in the source system" + }, + "WorkloadStatus": { + "type": "string", + "description": "Workload status in source system", + "enum": [ + "running", + "paused", + "stopped", + "exited", + "failed", + "deployed", + "building", + "unknown" + ] + }, + "WorkloadType": { + "type": "string", + "description": "Workload type", + "enum": [ + "container", + "function", + "static-site", + "server-side-app", + "worker", + "database", + "message-queue", + "cache", + "cron-job", + "other" + ] + }, + "WriteFileBody": { + "type": "object", + "required": [ + "path", + "contents_b64" + ], + "properties": { + "contents_b64": { + "type": "string", + "description": "File contents, base64-encoded. Required \u2014 lets callers ship binary\ndata over JSON without charset games." + }, + "mode": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "description": "Unix permission mask (e.g. 0o644). Defaults to 0o644 when absent.", + "minimum": 0 + }, + "path": { + "type": "string", + "description": "Absolute path inside the sandbox. Must start with `/`." + } + }, + "additionalProperties": false + }, + "WriteFilesBody": { + "type": "object", + "required": [ + "files" + ], + "properties": { + "files": { + "type": "array", + "items": { + "$ref": "#/components/schemas/WriteFileBody" + }, + "description": "List of files to write. Each entry must include an absolute\n`path` and base64-encoded `contents_b64`. Empty list is a no-op." + } + }, + "additionalProperties": false + }, + "WriteFilesResponse": { + "type": "object", + "required": [ + "written" + ], + "properties": { + "written": { + "type": "integer", + "description": "Number of files successfully written before the first failure\n(if any). On full success this equals `files.len()`.", + "minimum": 0 + } + } + }, + "ZoneListResponse": { + "type": "object", + "description": "Zone list response", + "required": [ + "zones" + ], + "properties": { + "zones": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DnsZone" + } + } + } + }, + "CloudCapability": { + "type": "object", + "required": [ + "configured", + "setup_path" + ], + "properties": { + "configured": { + "type": "boolean" + }, + "reason": { + "type": [ + "string", + "null" + ] + }, + "setup_path": { + "type": "string" + } + } + }, + "CloudSettings": { + "type": "object", + "description": "Non-secret managed control-plane settings stored with application settings.", + "properties": { + "backend_url": { + "type": "string", + "description": "HTTPS origin used for enrollment and telemetry mirroring.", + "default": "https://app.temps.sh" + } + } + }, + "CloudStatus": { + "type": "object", + "required": [ + "status", + "status_message", + "health", + "health_message", + "spooled_spans", + "backend_url" + ], + "properties": { + "account_email": { + "type": [ + "string", + "null" + ] + }, + "backend_url": { + "type": "string" + }, + "health": { + "type": "string" + }, + "health_message": { + "type": "string" + }, + "instance_id": { + "type": [ + "string", + "null" + ] + }, + "spooled_spans": { + "type": "integer", + "minimum": 0 + }, + "status": { + "type": "string" + }, + "status_message": { + "type": "string" + } + } + }, + "EnrollCloudRequest": { + "type": "object", + "required": [ + "enrollment_code" + ], + "properties": { + "enrollment_code": { + "type": "string", + "example": "ABCD-EFGH", + "minLength": 1 + } + } + } + }, + "securitySchemes": { + "bearer_auth": { + "type": "http", + "scheme": "bearer", + "description": "Bearer token authentication. Use format: `Bearer `. Supports API keys (starting with `tk_`), CLI tokens, and session tokens." + } + } + }, + "info": { + "title": "Temps", + "description": "An API for managing projects, deployments, and infrastructure resources", + "contact": { + "name": "Temps Support", + "url": "https://temps.sh" + }, + "version": "1.0.0" + }, + "openapi": "3.1.0", + "paths": { + "/.well-known/temps.json": { + "get": { + "tags": [ + "Platform" + ], + "summary": "Get platform information", + "operationId": "get_platform_info", + "responses": { + "200": { + "description": "Successfully retrieved platform information", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PlatformInfo" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/0/organizations/{org_slug}/chunk-upload/": { + "get": { + "tags": [ + "sentry-compat" + ], + "summary": "Chunk upload options (stub for sentry-cli compatibility).", + "description": "sentry-cli checks this endpoint to determine if chunk-based upload is supported.\nWe return a response indicating that chunk upload is NOT supported, which forces\nsentry-cli to fall back to the standard file-by-file upload.", + "operationId": "chunk_upload_options", + "parameters": [ + { + "name": "org_slug", + "in": "path", + "description": "Organization slug (ignored)", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Chunk upload options", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SentryChunkUploadResponse" + } + } + } + } + } + } + }, + "/0/organizations/{org_slug}/releases/": { + "post": { + "tags": [ + "sentry-compat" + ], + "summary": "Create a release (stub for sentry-cli compatibility).", + "description": "sentry-cli calls this before uploading files. Since Temps implicitly creates\nreleases when source maps are uploaded, this is a no-op that returns the\nexpected response format.", + "operationId": "create_release", + "parameters": [ + { + "name": "org_slug", + "in": "path", + "description": "Organization slug (ignored in single-tenant mode)", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SentryCreateReleaseRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Release created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SentryReleaseResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/0/projects/{org_slug}/{project_slug}/releases/": { + "post": { + "tags": [ + "sentry-compat" + ], + "summary": "Create a release for a specific project (stub for sentry-cli compatibility).", + "description": "sentry-cli calls this endpoint (instead of /organizations/.../releases/) when\nboth SENTRY_ORG and SENTRY_PROJECT env vars are set. Behaves identically to\nthe organizations endpoint but validates the project slug.", + "operationId": "create_project_release", + "parameters": [ + { + "name": "org_slug", + "in": "path", + "description": "Organization slug (ignored in single-tenant mode)", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "project_slug", + "in": "path", + "description": "Project slug or numeric ID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SentryCreateReleaseRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Release created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SentryReleaseResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Project not found" + } + } + } + }, + "/0/projects/{org_slug}/{project_slug}/releases/{version}/": { + "put": { + "tags": [ + "sentry-compat" + ], + "summary": "Finalize a release (stub for sentry-cli compatibility).", + "description": "sentry-cli calls `releases finalize` after uploading source maps. This sets\nthe dateReleased on the release. Since Temps stores source maps independently\nof releases, this is a no-op that returns the expected response.", + "operationId": "finalize_project_release", + "parameters": [ + { + "name": "org_slug", + "in": "path", + "description": "Organization slug (ignored)", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "project_slug", + "in": "path", + "description": "Project slug or numeric ID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "version", + "in": "path", + "description": "Release version to finalize", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Release finalized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SentryReleaseResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Project not found" + } + } + } + }, + "/0/projects/{org_slug}/{project_slug}/releases/{version}/files/": { + "get": { + "tags": [ + "sentry-compat" + ], + "summary": "List files for a release.", + "description": "Returns all source maps stored for a specific release in sentry-cli compatible format.", + "operationId": "list_release_files", + "parameters": [ + { + "name": "org_slug", + "in": "path", + "description": "Organization slug (ignored)", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "project_slug", + "in": "path", + "description": "Project slug or numeric ID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "version", + "in": "path", + "description": "Release version", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "List of release files", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SentryReleaseFileResponse" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Project not found" + } + } + }, + "post": { + "tags": [ + "sentry-compat" + ], + "summary": "Upload a source map file for a release.", + "description": "Accepts the same multipart format as the Sentry release files API.\nThe `name` field should be the URL path of the file (e.g., `~/dist/bundle.js.map`).\n\nThe route has a 50 MiB body limit applied at the router level (Fix #4).\nA per-field size check provides an additional defense-in-depth layer.", + "operationId": "upload_release_file", + "parameters": [ + { + "name": "org_slug", + "in": "path", + "description": "Organization slug (ignored)", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "project_slug", + "in": "path", + "description": "Project slug or numeric ID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "version", + "in": "path", + "description": "Release version", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "201": { + "description": "File uploaded", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SentryReleaseFileResponse" + } + } + } + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Project not found" + }, + "413": { + "description": "Source map file exceeds the 50 MiB per-field limit" + } + } + } + }, + "/_temps/event": { + "post": { + "tags": [ + "Metrics" + ], + "summary": "Record analytics event", + "operationId": "record_event_metrics", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventMetricsPayload" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Event recorded successfully" + }, + "400": { + "description": "Bad request" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/_temps/session-replay/events": { + "post": { + "tags": [ + "Analytics" + ], + "summary": "Add events to existing session replay", + "operationId": "add_session_replay_events", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionReplayEventsRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Events added successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddEventsResponse" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Session not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/_temps/session-replay/init": { + "post": { + "tags": [ + "Analytics" + ], + "summary": "Initialize session replay with metadata", + "operationId": "init_session_replay", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionReplayInitRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Session initialized successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionReplayInitResponse" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/_temps/speed": { + "post": { + "tags": [ + "Performance" + ], + "summary": "Record performance metrics from client", + "operationId": "record_speed_metrics", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SpeedMetricsPayload" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Metrics recorded successfully" + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Host not found in route table", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/_temps/speed/update": { + "post": { + "tags": [ + "Performance" + ], + "summary": "Update late performance metrics", + "operationId": "update_speed_metrics", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateSpeedMetricsPayload" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Metrics updated successfully" + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Host not found or metrics not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/admin/gate-settings": { + "get": { + "tags": [ + "AdminGate" + ], + "operationId": "get_admin_gate", + "responses": { + "200": { + "description": "Current admin gate config", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminGateResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "patch": { + "tags": [ + "AdminGate" + ], + "operationId": "patch_admin_gate", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateAdminGateRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Updated admin gate config", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminGateResponse" + } + } + } + }, + "400": { + "description": "Invalid IP/CIDR/host" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "409": { + "description": "Env-overridden or would lock out caller" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/admin/oidc/providers": { + "get": { + "tags": [ + "Authentication" + ], + "operationId": "list_oidc_providers", + "responses": { + "200": { + "description": "OIDC providers", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OidcProviderResponse" + } + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Authentication" + ], + "operationId": "create_oidc_provider", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateOidcProviderRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "OIDC provider created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OidcProviderResponse" + } + } + } + }, + "409": { + "description": "Another OIDC provider already uses that name" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/admin/oidc/providers/{provider_id}": { + "delete": { + "tags": [ + "Authentication" + ], + "operationId": "delete_oidc_provider", + "parameters": [ + { + "name": "provider_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "OIDC provider deleted" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "patch": { + "tags": [ + "Authentication" + ], + "operationId": "update_oidc_provider", + "parameters": [ + { + "name": "provider_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateOidcProviderRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OIDC provider updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OidcProviderResponse" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/admin/oidc/providers/{provider_id}/role-mappings": { + "get": { + "tags": [ + "Authentication" + ], + "operationId": "list_oidc_role_mappings", + "parameters": [ + { + "name": "provider_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OIDC role mappings", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OidcRoleMappingResponse" + } + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Authentication" + ], + "operationId": "create_oidc_role_mapping", + "parameters": [ + { + "name": "provider_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateOidcRoleMappingRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Role mapping created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OidcRoleMappingResponse" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/admin/oidc/providers/{provider_id}/test": { + "post": { + "tags": [ + "Authentication" + ], + "operationId": "test_oidc_provider", + "parameters": [ + { + "name": "provider_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Connection test result", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OidcTestConnectionResponse" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/admin/oidc/providers/{provider_id}/users": { + "get": { + "tags": [ + "Authentication" + ], + "operationId": "list_oidc_provider_users", + "parameters": [ + { + "name": "provider_id", + "in": "path", + "description": "OIDC provider ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Users authenticated via this OIDC provider", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OidcProviderUserResponse" + } + } + } + } + }, + "404": { + "description": "Provider not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/admin/oidc/role-mappings/{mapping_id}": { + "delete": { + "tags": [ + "Authentication" + ], + "operationId": "delete_oidc_role_mapping", + "parameters": [ + { + "name": "mapping_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Role mapping deleted" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/agents/webhook/{webhook_id}": { + "post": { + "tags": [ + "Agents" + ], + "summary": "Public webhook endpoint. Authenticated via `X-Webhook-Token` header.", + "description": "`POST /api/agents/webhook/{webhook_id}`\nHeader: `X-Webhook-Token: `\n\nThe `webhook_id` in the URL is a short non-secret identifier (safe to log).\nThe actual credential is the secret token in the header.\n\nAccepts any JSON body, which is passed as `user_context` to the agent run.", + "operationId": "webhook_trigger", + "parameters": [ + { + "name": "webhook_id", + "in": "path", + "description": "Webhook ID (non-secret)", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WebhookTriggerRequest" + } + } + }, + "required": true + }, + "responses": { + "202": { + "description": "Agent run created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WebhookTriggerResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid X-Webhook-Token header" + }, + "404": { + "description": "Invalid webhook ID" + }, + "422": { + "description": "Agent disabled" + } + } + } + }, + "/ai/conversations": { + "get": { + "tags": [ + "AI Chat" + ], + "summary": "List every active conversation across all projects, most-recently-active\nfirst, annotated with project name/slug. Powers the unified \"all chats\"\nswitcher in the AI assistant dock.", + "operationId": "list_all_conversations", + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GlobalConversationResponse" + } + } + } + } + }, + "401": { + "description": "" + }, + "403": { + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/ai/pricing": { + "get": { + "tags": [ + "AI Gateway Pricing" + ], + "operationId": "get_pricing", + "responses": { + "200": { + "description": "Model pricing information", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PricingResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/ai/providers": { + "get": { + "tags": [ + "AI Gateway Admin" + ], + "operationId": "list_provider_keys", + "responses": { + "200": { + "description": "List of provider keys", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProviderKeyResponse" + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "AI Gateway Admin" + ], + "operationId": "create_provider_key", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateProviderKeyRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Provider key created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProviderKeyResponse" + } + } + } + }, + "400": { + "description": "Validation error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/ai/providers/test": { + "post": { + "tags": [ + "AI Gateway Admin" + ], + "operationId": "test_provider_key_inline", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TestProviderKeyRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Test result", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TestProviderKeyResponse" + } + } + } + }, + "400": { + "description": "Validation error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/ai/providers/{id}": { + "delete": { + "tags": [ + "AI Gateway Admin" + ], + "operationId": "delete_provider_key", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Provider key deleted" + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "patch": { + "tags": [ + "AI Gateway Admin" + ], + "operationId": "update_provider_key", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateProviderKeyRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Provider key updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProviderKeyResponse" + } + } + } + }, + "400": { + "description": "Validation error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/ai/providers/{id}/test": { + "post": { + "tags": [ + "AI Gateway Admin" + ], + "operationId": "test_provider_key_by_id", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Test result", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TestProviderKeyResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Provider key not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/ai/usage/by-provider": { + "get": { + "tags": [ + "AI Gateway Usage" + ], + "operationId": "get_usage_by_provider", + "parameters": [ + { + "name": "from", + "in": "query", + "description": "ISO 8601 start time (defaults to 24h ago)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "to", + "in": "query", + "description": "ISO 8601 end time (defaults to now)", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Usage broken down by provider", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProviderUsage" + } + } + } + } + }, + "400": { + "description": "Invalid query parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/ai/usage/conversations": { + "get": { + "tags": [ + "AI Gateway Usage" + ], + "operationId": "get_conversations", + "parameters": [ + { + "name": "from", + "in": "query", + "description": "ISO 8601 start time (defaults to 24h ago)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "to", + "in": "query", + "description": "ISO 8601 end time (defaults to now)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "description": "Max results (defaults to 50, max 100)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "user_id", + "in": "query", + "description": "Filter by user ID", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "tags", + "in": "query", + "description": "Filter by tags (comma-separated)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "model", + "in": "query", + "description": "Filter by model name", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Conversation summaries", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ConversationSummary" + } + } + } + } + }, + "400": { + "description": "Invalid query parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/ai/usage/conversations/{conversation_id}": { + "get": { + "tags": [ + "AI Gateway Usage" + ], + "operationId": "get_conversation_detail", + "parameters": [ + { + "name": "conversation_id", + "in": "path", + "description": "Conversation ID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "description": "Max results (defaults to 100)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "Invocations within a conversation", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UsageLogEntry" + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/ai/usage/recent": { + "get": { + "tags": [ + "AI Gateway Usage" + ], + "operationId": "get_usage_recent", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Page size (defaults to 20, max 50)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "offset", + "in": "query", + "description": "Number of results to skip for pagination (defaults to 0)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "provider", + "in": "query", + "description": "Filter by provider name", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "model", + "in": "query", + "description": "Filter by model name", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "status", + "in": "query", + "description": "Filter by HTTP status code (exact match)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "cost_gte", + "in": "query", + "description": "Cost greater-than-or-equal, in microcents", + "required": false, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "cost_gt", + "in": "query", + "description": "Cost strictly greater-than, in microcents", + "required": false, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "cost_lte", + "in": "query", + "description": "Cost less-than-or-equal, in microcents", + "required": false, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "cost_lt", + "in": "query", + "description": "Cost strictly less-than, in microcents", + "required": false, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "tokens_gte", + "in": "query", + "description": "Total tokens greater-than-or-equal", + "required": false, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "tokens_gt", + "in": "query", + "description": "Total tokens strictly greater-than", + "required": false, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "tokens_lte", + "in": "query", + "description": "Total tokens less-than-or-equal", + "required": false, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "tokens_lt", + "in": "query", + "description": "Total tokens strictly less-than", + "required": false, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "Page of recent usage log entries", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UsageLogPage" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/ai/usage/summary": { + "get": { + "tags": [ + "AI Gateway Usage" + ], + "operationId": "get_usage_summary", + "parameters": [ + { + "name": "from", + "in": "query", + "description": "ISO 8601 start time (defaults to 24h ago)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "to", + "in": "query", + "description": "ISO 8601 end time (defaults to now)", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Usage summary for the time range", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UsageSummary" + } + } + } + }, + "400": { + "description": "Invalid query parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/ai/usage/timeseries": { + "get": { + "tags": [ + "AI Gateway Usage" + ], + "operationId": "get_usage_timeseries", + "parameters": [ + { + "name": "from", + "in": "query", + "description": "ISO 8601 start time (defaults to 24h ago)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "to", + "in": "query", + "description": "ISO 8601 end time (defaults to now)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "bucket", + "in": "query", + "description": "Bucket size: hour, day, week (defaults to day)", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Time-series usage data", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TimeseriesBucket" + } + } + } + } + }, + "400": { + "description": "Invalid query parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/ai/usage/top-models": { + "get": { + "tags": [ + "AI Gateway Usage" + ], + "operationId": "get_usage_top_models", + "parameters": [ + { + "name": "from", + "in": "query", + "description": "ISO 8601 start time (defaults to 24h ago)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "to", + "in": "query", + "description": "ISO 8601 end time (defaults to now)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "description": "Max results (defaults to 10)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "Top models by request count", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ModelUsage" + } + } + } + } + }, + "400": { + "description": "Invalid query parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/ai/v1/chat/completions": { + "post": { + "tags": [ + "AI Gateway" + ], + "operationId": "chat_completions", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChatCompletionRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Chat completion response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChatCompletionResponse" + } + } + } + }, + "400": { + "description": "Invalid request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OpenAiErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OpenAiErrorResponse" + } + } + } + }, + "404": { + "description": "Model not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OpenAiErrorResponse" + } + } + } + }, + "500": { + "description": "Internal error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OpenAiErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/ai/v1/embeddings": { + "post": { + "tags": [ + "AI Gateway" + ], + "operationId": "embeddings", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmbeddingRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Embedding response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmbeddingResponse" + } + } + } + }, + "400": { + "description": "Invalid request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OpenAiErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OpenAiErrorResponse" + } + } + } + }, + "404": { + "description": "Model not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OpenAiErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/ai/v1/models": { + "get": { + "tags": [ + "AI Gateway" + ], + "operationId": "list_models", + "responses": { + "200": { + "description": "List of available models", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelListResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OpenAiErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/analytics/active-visitors": { + "get": { + "tags": [ + "Analytics" + ], + "summary": "Get detailed active visitors", + "operationId": "get_analytics_active_visitors", + "parameters": [ + { + "name": "project_id", + "in": "query", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Environment ID (optional)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "deployment_id", + "in": "query", + "description": "Deployment ID (optional)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "window_minutes", + "in": "query", + "description": "Time window in minutes for active visitors (default: 5)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved active visitors", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ActiveVisitorsResponse" + } + } + } + }, + "400": { + "description": "Invalid parameters or project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/analytics/event-detail": { + "get": { + "tags": [ + "Analytics" + ], + "summary": "Get detailed analytics for a specific event", + "operationId": "get_event_detail", + "parameters": [ + { + "name": "event_name", + "in": "query", + "description": "Event name to get details for", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "project_id", + "in": "query", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Environment ID (optional)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "start_date", + "in": "query", + "description": "Start date (ISO 8601)", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "end_date", + "in": "query", + "description": "End date (ISO 8601)", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "bucket_interval", + "in": "query", + "description": "Bucket interval: hour, day, week, month (default: auto)", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved event details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDetailResponse" + } + } + } + }, + "400": { + "description": "Invalid parameters" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/analytics/event-entries": { + "get": { + "tags": [ + "Analytics" + ], + "summary": "Get paginated list of raw occurrences of a specific event, including custom JSON properties", + "operationId": "get_event_entries", + "parameters": [ + { + "name": "event_name", + "in": "query", + "description": "Event name to list occurrences for", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "project_id", + "in": "query", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Environment ID (optional)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "start_date", + "in": "query", + "description": "Start date (ISO 8601)", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "end_date", + "in": "query", + "description": "End date (ISO 8601)", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "page", + "in": "query", + "description": "Page number (1-based, default: 1)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "per_page", + "in": "query", + "description": "Items per page (default: 20, max: 100)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved event entries", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventEntriesResponse" + } + } + } + }, + "400": { + "description": "Invalid parameters" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/analytics/event-visitors": { + "get": { + "tags": [ + "Analytics" + ], + "summary": "Get paginated list of visitors who triggered a specific event", + "operationId": "get_event_visitors", + "parameters": [ + { + "name": "event_name", + "in": "query", + "description": "Event name to list visitors for", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "project_id", + "in": "query", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Environment ID (optional)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "start_date", + "in": "query", + "description": "Start date (ISO 8601)", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "end_date", + "in": "query", + "description": "End date (ISO 8601)", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "page", + "in": "query", + "description": "Page number (1-based, default: 1)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "per_page", + "in": "query", + "description": "Items per page (default: 20, max: 100)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved event visitors", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventVisitorsResponse" + } + } + } + }, + "400": { + "description": "Invalid parameters" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/analytics/events": { + "get": { + "tags": [ + "Analytics" + ], + "operationId": "get_analytics_events_count", + "parameters": [ + { + "name": "start_date", + "in": "query", + "description": "Start date in format YYYY-MM-DD HH:MM:SS", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "end_date", + "in": "query", + "description": "End date in format YYYY-MM-DD HH:MM:SS", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "project_id", + "in": "query", + "description": "Project ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "limit", + "in": "query", + "description": "Maximum number of results to return", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Environment ID (optional)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "custom_events_only", + "in": "query", + "description": "Only return custom events, excluding system events like page_view, page_leave, heartbeat (default: true)", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "name": "breakdown", + "in": "query", + "description": "Breakdown by geography: 'country', 'region', or 'city' (optional)", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved event counts", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EventCount" + } + } + } + } + }, + "400": { + "description": "Invalid date format, missing required parameters, or project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/analytics/general-stats": { + "get": { + "tags": [ + "Analytics" + ], + "summary": "Get general statistics across all projects for a time frame", + "operationId": "get_general_stats", + "parameters": [ + { + "name": "start_date", + "in": "query", + "description": "Start date in format YYYY-MM-DD HH:MM:SS", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "end_date", + "in": "query", + "description": "End date in format YYYY-MM-DD HH:MM:SS", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "project_ids", + "in": "query", + "description": "Optional: Filter by specific project IDs (comma-separated)", + "required": false, + "schema": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Environment ID (optional)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "include_project_breakdown", + "in": "query", + "description": "Whether to include per-project breakdown (default: false)", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved general statistics", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GeneralStatsResponse" + } + } + } + }, + "400": { + "description": "Invalid date format or parameters" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/analytics/has-events": { + "get": { + "tags": [ + "Analytics" + ], + "operationId": "check_analytics_has_events", + "parameters": [ + { + "name": "project_id", + "in": "query", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Environment ID (optional)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Analytics events existence check", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HasAnalyticsEventsResponse" + } + } + } + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/analytics/live-visitors": { + "get": { + "tags": [ + "Analytics" + ], + "summary": "Get list of currently live visitors from visitor table", + "operationId": "get_live_visitors_list", + "parameters": [ + { + "name": "project_id", + "in": "query", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Environment ID (optional)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "window_minutes", + "in": "query", + "description": "Time window in minutes for live visitors (default: 5)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved live visitors list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LiveVisitorsListResponse" + } + } + } + }, + "400": { + "description": "Invalid parameters or project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/analytics/page-flow": { + "get": { + "tags": [ + "Analytics" + ], + "summary": "Get page flow analytics: entry pages, exit pages, drop-off points, and page transitions", + "operationId": "get_page_flow", + "parameters": [ + { + "name": "project_id", + "in": "query", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Environment ID (optional)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "start_date", + "in": "query", + "description": "Start date in ISO 8601 format", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "end_date", + "in": "query", + "description": "End date in ISO 8601 format", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "description": "Max entry/exit pages to return (default: 20, max: 100)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "transitions_limit", + "in": "query", + "description": "Max page transitions to return (default: 50, max: 200)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "min_views_for_dropoff", + "in": "query", + "description": "Minimum views for drop-off analysis (default: 5)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved page flow analytics", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PageFlowResponse" + } + } + } + }, + "400": { + "description": "Invalid parameters" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/analytics/page-hourly-sessions": { + "get": { + "tags": [ + "Analytics" + ], + "operationId": "get_page_hourly_sessions", + "parameters": [ + { + "name": "page_path", + "in": "query", + "description": "The page path to get sessions for", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "project_id", + "in": "query", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Environment ID (optional)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "start_time", + "in": "query", + "description": "Start time in format YYYY-MM-DD HH:MM:SS", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "end_time", + "in": "query", + "description": "End time in format YYYY-MM-DD HH:MM:SS", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "bucket_interval", + "in": "query", + "description": "Bucket interval: 'hour', 'day', 'week', or 'month' (default: auto-determined based on range)", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved page sessions with time buckets", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PageHourlySessionsResponse" + } + } + } + }, + "400": { + "description": "Invalid parameters or project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/analytics/page-path-detail": { + "get": { + "tags": [ + "Analytics" + ], + "summary": "Get detailed analytics for a specific page path\nReturns visitors, page views, activity over time, geographic distribution, and referrers", + "operationId": "get_page_path_detail", + "parameters": [ + { + "name": "page_path", + "in": "query", + "description": "The page path to get details for (URL-encoded)", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "project_id", + "in": "query", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Environment ID (optional)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "start_date", + "in": "query", + "description": "Start date in ISO 8601 format", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "end_date", + "in": "query", + "description": "End date in ISO 8601 format", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "bucket_interval", + "in": "query", + "description": "Bucket interval for time series: 'hour', 'day', 'week', 'month' (default: auto based on date range)", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved page path detail analytics", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagePathDetailResponse" + } + } + } + }, + "400": { + "description": "Invalid parameters or project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/analytics/page-path-visitors": { + "get": { + "tags": [ + "Analytics" + ], + "summary": "Get individual visitor sessions for a specific page path", + "operationId": "get_page_path_visitors", + "parameters": [ + { + "name": "page_path", + "in": "query", + "description": "The page path to get visitors for (URL-encoded)", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "project_id", + "in": "query", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Environment ID (optional)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "start_date", + "in": "query", + "description": "Start date in ISO 8601 format", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "end_date", + "in": "query", + "description": "End date in ISO 8601 format", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "page", + "in": "query", + "description": "Page number (1-based, default: 1)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "per_page", + "in": "query", + "description": "Items per page (default: 50, max: 100)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved page path visitors", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagePathVisitorsResponse" + } + } + } + }, + "400": { + "description": "Invalid parameters" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/analytics/page-paths": { + "get": { + "tags": [ + "Analytics" + ], + "operationId": "get_page_paths", + "parameters": [ + { + "name": "project_id", + "in": "query", + "description": "Project ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Environment ID (optional)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "start_date", + "in": "query", + "description": "Start date in format YYYY-MM-DD HH:MM:SS (optional)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "end_date", + "in": "query", + "description": "End date in format YYYY-MM-DD HH:MM:SS (optional)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "description": "Maximum number of page paths to return (default: 100, max: 1000)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved page paths", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagePathsResponse" + } + } + } + }, + "400": { + "description": "Invalid parameters or project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/analytics/page-paths-sparklines": { + "get": { + "tags": [ + "Analytics" + ], + "operationId": "get_page_paths_sparklines", + "parameters": [ + { + "name": "project_id", + "in": "query", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Environment ID (optional)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "start_time", + "in": "query", + "description": "Start time in ISO 8601 format", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "end_time", + "in": "query", + "description": "End time in ISO 8601 format", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "page_paths", + "in": "query", + "description": "Comma-separated list of page paths", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Sparkline data for all requested page paths", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagePathsSparklineResponse" + } + } + } + }, + "400": { + "description": "Invalid parameters" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/analytics/recent-activity": { + "get": { + "tags": [ + "Analytics" + ], + "summary": "Get recent activity events for real-time activity feed", + "operationId": "get_recent_activity", + "parameters": [ + { + "name": "project_id", + "in": "query", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Environment ID (optional)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "since_id", + "in": "query", + "description": "Return events with ID greater than this (cursor-based polling)", + "required": false, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "limit", + "in": "query", + "description": "Max events to return (default: 50, max: 100)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved recent activity events", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RecentActivityResponse" + } + } + } + }, + "400": { + "description": "Invalid parameters" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/analytics/sessions/{session_id}": { + "get": { + "tags": [ + "Analytics" + ], + "summary": "Get detailed information about a specific session including events and request logs", + "operationId": "get_session_details", + "parameters": [ + { + "name": "session_id", + "in": "path", + "description": "Session ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "project_id", + "in": "query", + "description": "Project ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Environment ID (optional)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved session details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionDetails" + } + } + } + }, + "400": { + "description": "Invalid parameters or project not found" + }, + "404": { + "description": "Session not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/analytics/sessions/{session_id}/events": { + "get": { + "tags": [ + "Analytics" + ], + "operationId": "get_analytics_session_events", + "parameters": [ + { + "name": "session_id", + "in": "path", + "description": "Session ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "project_id", + "in": "query", + "description": "Project ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Environment ID (optional)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "start_date", + "in": "query", + "description": "Start date in format YYYY-MM-DD HH:MM:SS", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "end_date", + "in": "query", + "description": "End date in format YYYY-MM-DD HH:MM:SS", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "description": "Number of results to return (default: 100)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "offset", + "in": "query", + "description": "Number of results to skip (default: 0)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved session events", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionEventsResponse" + } + } + } + }, + "400": { + "description": "Invalid parameters or project not found" + }, + "404": { + "description": "Session not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/analytics/sessions/{session_id}/logs": { + "get": { + "tags": [ + "Analytics" + ], + "operationId": "get_session_logs", + "parameters": [ + { + "name": "session_id", + "in": "path", + "description": "Session ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "project_id", + "in": "query", + "description": "Project ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Environment ID (optional)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "start_date", + "in": "query", + "description": "Start date in format YYYY-MM-DD HH:MM:SS", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "end_date", + "in": "query", + "description": "End date in format YYYY-MM-DD HH:MM:SS", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "description": "Number of results to return (default: 100)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "offset", + "in": "query", + "description": "Number of results to skip (default: 0)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved session logs", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionLogsResponse" + } + } + } + }, + "400": { + "description": "Invalid parameters or project not found" + }, + "404": { + "description": "Session not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/analytics/visitor-facets": { + "get": { + "tags": [ + "Analytics" + ], + "summary": "Get filter dropdown contents for the visitors page. Returns the top\nvalues per dimension with distinct visitor counts so the UI can render\n\"Country \u2014 1,234 visitors\" rows. Each dimension is computed against the\nsegment minus its own filter, so a selected value never collapses its\nown dropdown.", + "operationId": "get_visitor_facets", + "parameters": [ + { + "name": "start_date", + "in": "query", + "description": "Start date in format YYYY-MM-DD HH:MM:SS", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "end_date", + "in": "query", + "description": "End date in format YYYY-MM-DD HH:MM:SS", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "project_id", + "in": "query", + "description": "Project ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Environment ID (optional)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "include_crawlers", + "in": "query", + "description": "Include crawlers (default: false)", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "name": "has_activity_only", + "in": "query", + "description": "Hide ghost visitors (default: true)", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "name": "per_facet_limit", + "in": "query", + "description": "Top N values per dimension (default: 50, max: 200)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "filter_country", + "in": "query", + "description": "Geolocation country", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "filter_region", + "in": "query", + "description": "Geolocation region", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "filter_city", + "in": "query", + "description": "Geolocation city", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "filter_channel", + "in": "query", + "description": "First-touch channel", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "filter_referrer", + "in": "query", + "description": "First-touch referrer hostname (use 'Direct' for null)", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Top values per dimension", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VisitorFacets" + } + } + } + }, + "400": { + "description": "Invalid date format or project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/analytics/visitors": { + "get": { + "tags": [ + "Analytics" + ], + "summary": "Get list of visitors with summary information", + "operationId": "get_visitors", + "parameters": [ + { + "name": "start_date", + "in": "query", + "description": "Start date in format YYYY-MM-DD HH:MM:SS", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "end_date", + "in": "query", + "description": "End date in format YYYY-MM-DD HH:MM:SS", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "project_id", + "in": "query", + "description": "Project ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Environment ID (optional)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "include_crawlers", + "in": "query", + "description": "Include crawlers (default: false)", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "name": "limit", + "in": "query", + "description": "Maximum number of visitors to return (default: 50)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "offset", + "in": "query", + "description": "Number of visitors to skip (default: 0)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "has_activity_only", + "in": "query", + "description": "Filter to only include visitors with recorded activity (events/sessions). When true, excludes ghost visitors (default: true)", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "name": "filter_country", + "in": "query", + "description": "Geolocation country", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "filter_region", + "in": "query", + "description": "Geolocation region", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "filter_city", + "in": "query", + "description": "Geolocation city", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "filter_channel", + "in": "query", + "description": "First-touch channel", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "filter_referrer", + "in": "query", + "description": "First-touch referrer hostname (use 'Direct' for null)", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved visitors", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VisitorsResponse" + } + } + } + }, + "400": { + "description": "Invalid date format, missing required parameters, or project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/analytics/visitors/guid/{visitor_id}": { + "get": { + "tags": [ + "Analytics" + ], + "summary": "Get visitor by GUID with geolocation data", + "operationId": "get_visitor_by_guid", + "parameters": [ + { + "name": "visitor_id", + "in": "path", + "description": "Visitor GUID (supports enc_ prefix for encrypted IDs)", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "project_id", + "in": "query", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Environment ID (optional)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved visitor with geolocation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VisitorWithGeolocation" + } + } + } + }, + "400": { + "description": "Invalid parameters or project not found" + }, + "404": { + "description": "Visitor not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/analytics/visitors/id/{id}": { + "get": { + "tags": [ + "Analytics" + ], + "summary": "Get visitor by numeric ID with geolocation data", + "operationId": "get_visitor_by_id", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Visitor numeric ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "project_id", + "in": "query", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Environment ID (optional)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved visitor with geolocation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VisitorWithGeolocation" + } + } + } + }, + "400": { + "description": "Invalid parameters or project not found" + }, + "404": { + "description": "Visitor not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/analytics/visitors/{visitor_id}": { + "get": { + "tags": [ + "Analytics" + ], + "summary": "Get detailed information about a specific visitor by numeric ID", + "operationId": "get_visitor_details", + "parameters": [ + { + "name": "visitor_id", + "in": "path", + "description": "Visitor numeric ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "project_id", + "in": "query", + "description": "Project ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Environment ID (optional)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved visitor details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VisitorDetails" + } + } + } + }, + "400": { + "description": "Invalid parameters or project not found" + }, + "404": { + "description": "Visitor not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/analytics/visitors/{visitor_id}/enrich": { + "put": { + "tags": [ + "Analytics" + ], + "operationId": "enrich_visitor", + "parameters": [ + { + "name": "visitor_id", + "in": "path", + "description": "Visitor ID - can be numeric ID, GUID, or encrypted GUID (enc_xxx)", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "project_id", + "in": "query", + "description": "Project ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnrichVisitorRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successfully enriched visitor data", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnrichVisitorResponse" + } + } + } + }, + "400": { + "description": "Invalid parameters or project not found" + }, + "404": { + "description": "Visitor not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/analytics/visitors/{visitor_id}/info": { + "get": { + "tags": [ + "Analytics" + ], + "summary": "Get visitor record from database", + "operationId": "get_visitor_info", + "parameters": [ + { + "name": "visitor_id", + "in": "path", + "description": "Visitor numeric ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "project_id", + "in": "query", + "description": "Project ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved visitor info", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VisitorRecord" + } + } + } + }, + "400": { + "description": "Invalid parameters or project not found" + }, + "404": { + "description": "Visitor not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/analytics/visitors/{visitor_id}/journey": { + "get": { + "tags": [ + "Analytics" + ], + "summary": "Get the complete visitor journey: all events across all sessions, grouped by session", + "operationId": "get_visitor_journey", + "parameters": [ + { + "name": "visitor_id", + "in": "path", + "description": "Visitor numeric ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "project_id", + "in": "query", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "limit_sessions", + "in": "query", + "description": "Maximum number of sessions to return (default: 50)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved visitor journey", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VisitorJourneyResponse" + } + } + } + }, + "400": { + "description": "Invalid parameters" + }, + "404": { + "description": "Visitor not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/analytics/visitors/{visitor_id}/sessions": { + "get": { + "tags": [ + "Analytics" + ], + "summary": "Get all sessions for a specific visitor by numeric ID", + "operationId": "get_analytics_visitor_sessions", + "parameters": [ + { + "name": "visitor_id", + "in": "path", + "description": "Visitor numeric ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "project_id", + "in": "query", + "description": "Project ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Environment ID (optional)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "limit", + "in": "query", + "description": "Maximum number of sessions to return (default: 100)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved visitor sessions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VisitorSessionsResponse" + } + } + } + }, + "400": { + "description": "Invalid parameters or project not found" + }, + "404": { + "description": "Visitor not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/analytics/visitors/{visitor_id}/stats": { + "get": { + "tags": [ + "Analytics" + ], + "summary": "Get visitor statistics", + "operationId": "get_visitor_stats", + "parameters": [ + { + "name": "visitor_id", + "in": "path", + "description": "Visitor numeric ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "project_id", + "in": "query", + "description": "Project ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved visitor statistics", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VisitorStats" + } + } + } + }, + "400": { + "description": "Invalid parameters or project not found" + }, + "404": { + "description": "Visitor not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/api-keys": { + "get": { + "tags": [ + "API Keys" + ], + "operationId": "list_api_keys", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "Page number (default: 1)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "page_size", + "in": "query", + "description": "Items per page (default: 20)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "API keys retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiKeyListResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "API Keys" + ], + "operationId": "create_api_key", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateApiKeyRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "API key created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateApiKeyResponse" + } + } + } + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "409": { + "description": "Conflict - API key name already exists" + }, + "428": { + "description": "Recent MFA verification required" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/api-keys/permissions": { + "get": { + "tags": [ + "API Keys" + ], + "operationId": "get_api_key_permissions", + "responses": { + "200": { + "description": "Available permissions and roles retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AvailablePermissions" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/api-keys/{id}": { + "get": { + "tags": [ + "API Keys" + ], + "operationId": "get_api_key", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "API key ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "API key retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiKeyResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "put": { + "tags": [ + "API Keys" + ], + "operationId": "update_api_key", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "API key ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateApiKeyRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "API key updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiKeyResponse" + } + } + } + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not found" + }, + "409": { + "description": "Conflict - API key name already exists" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "API Keys" + ], + "operationId": "delete_api_key", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "API key ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "API key deleted successfully" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/api-keys/{id}/activate": { + "post": { + "tags": [ + "API Keys" + ], + "operationId": "activate_api_key", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "API key ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "API key activated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiKeyResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/api-keys/{id}/deactivate": { + "post": { + "tags": [ + "API Keys" + ], + "operationId": "deactivate_api_key", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "API key ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "API key deactivated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiKeyResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/api-keys/{id}/rotate": { + "post": { + "tags": [ + "API Keys" + ], + "operationId": "rotate_api_key", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "API key ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "API key rotated successfully; the response contains the new plaintext secret, shown only once", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateApiKeyResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not found" + }, + "428": { + "description": "Recent MFA verification required" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/auth/cli/device/approve": { + "post": { + "tags": [ + "Authentication" + ], + "operationId": "cli_device_approve", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CliDeviceApproveRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Session approved; CLI can now claim the API key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CliDeviceApproveResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Browser session required" + }, + "404": { + "description": "Unknown user_code" + }, + "409": { + "description": "Already resolved" + }, + "410": { + "description": "Session expired" + }, + "428": { + "description": "Recent MFA verification required" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "session_token": [] + } + ] + } + }, + "/auth/cli/device/deny": { + "post": { + "tags": [ + "Authentication" + ], + "operationId": "cli_device_deny", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CliDeviceApproveRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Session denied", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CliDeviceApproveResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Unknown user_code" + }, + "409": { + "description": "Already resolved" + }, + "410": { + "description": "Session expired" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "session_token": [] + } + ] + } + }, + "/auth/cli/device/lookup": { + "get": { + "tags": [ + "Authentication" + ], + "operationId": "cli_device_lookup", + "parameters": [ + { + "name": "user_code", + "in": "query", + "description": "`user_code` as displayed in the CLI / pasted into the URL.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Device session metadata", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CliDeviceLookupResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Unknown user_code" + }, + "410": { + "description": "Device session expired" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "session_token": [] + } + ] + } + }, + "/auth/cli/device/poll": { + "post": { + "tags": [ + "Authentication" + ], + "operationId": "cli_device_poll", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CliDevicePollRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Poll result; check `status` field", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CliDevicePollResponse" + } + } + } + }, + "404": { + "description": "Unknown device_code" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/auth/cli/device/start": { + "post": { + "tags": [ + "Authentication" + ], + "operationId": "cli_device_start", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CliDeviceStartRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Device session created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CliDeviceStartResponse" + } + } + } + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/auth/cli/logout": { + "post": { + "tags": [ + "Authentication" + ], + "operationId": "cli_logout", + "responses": { + "204": { + "description": "API key revoked" + }, + "401": { + "description": "Not authenticated" + }, + "403": { + "description": "Endpoint requires API key authentication" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/auth/email-status": { + "get": { + "tags": [ + "Authentication" + ], + "operationId": "email_status", + "responses": { + "200": { + "description": "Email configuration status", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmailStatusResponse" + } + } + } + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/auth/login": { + "post": { + "tags": [ + "Authentication" + ], + "operationId": "login", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LoginRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Login successful, session cookie set", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthResponse" + } + } + } + }, + "401": { + "description": "Invalid credentials, or the account's role requires MFA enrollment that has not been completed" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/auth/oidc/callback": { + "get": { + "tags": [ + "Authentication" + ], + "operationId": "oidc_callback", + "parameters": [ + { + "name": "code", + "in": "query", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "state", + "in": "query", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "error", + "in": "query", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "error_description", + "in": "query", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + } + ], + "responses": { + "302": { + "description": "Redirect to app with session cookie or login error" + } + } + } + }, + "/auth/oidc/login/{slug}": { + "get": { + "tags": [ + "Authentication" + ], + "operationId": "start_oidc_login_by_slug", + "parameters": [ + { + "name": "slug", + "in": "path", + "description": "OIDC provider slug (from /email-status or /auth/oidc/providers)", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "return_to", + "in": "query", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + } + ], + "responses": { + "302": { + "description": "Redirect to IdP authorize URL" + }, + "404": { + "description": "Provider not found" + }, + "503": { + "description": "OIDC provider unreachable" + } + } + } + }, + "/auth/oidc/providers": { + "get": { + "tags": [ + "Authentication" + ], + "operationId": "list_public_providers", + "responses": { + "200": { + "description": "Enabled OIDC providers for login page", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OidcProvidersListResponse" + } + } + } + } + } + } + }, + "/auth/password-reset/request": { + "post": { + "tags": [ + "Authentication" + ], + "operationId": "request_password_reset", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmailRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Reset email sent if account exists", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthResponse" + } + } + } + }, + "503": { + "description": "Email service not configured" + } + } + } + }, + "/auth/password-reset/verify": { + "post": { + "tags": [ + "Authentication" + ], + "operationId": "reset_password", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResetPasswordRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Password reset successful", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthResponse" + } + } + } + }, + "400": { + "description": "Invalid or expired token" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/auth/step-up": { + "post": { + "tags": [ + "Authentication" + ], + "operationId": "verify_step_up", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VerifyStepUpRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Session elevated for sensitive actions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StepUpResponse" + } + } + } + }, + "400": { + "description": "Verification code is empty" + }, + "401": { + "description": "Invalid code or expired session" + }, + "403": { + "description": "Browser session required" + }, + "428": { + "description": "MFA setup required" + }, + "429": { + "description": "Too many verification attempts" + }, + "500": { + "description": "Verification infrastructure failed" + } + }, + "security": [ + { + "session_token": [] + } + ] + } + }, + "/auth/verify-email": { + "get": { + "tags": [ + "Authentication" + ], + "operationId": "verify_email", + "parameters": [ + { + "name": "token", + "in": "query", + "description": "Email verification token", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Email verified successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthResponse" + } + } + } + }, + "400": { + "description": "Invalid or expired token" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/auth/verify-mfa": { + "post": { + "tags": [ + "Authentication" + ], + "operationId": "verify_mfa_challenge", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MfaVerificationRequest" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "MFA verification successful" + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Invalid MFA code" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/backups/alerts": { + "get": { + "tags": [ + "Backups" + ], + "summary": "List open backup alerts.", + "description": "Returns all alerts that have not yet been resolved, ordered by `opened_at`\ndescending (newest first). The UI renders these as a banner above the\nBackups page content. Alerts are auto-opened by the watcher and\nauto-resolved when the triggering condition clears.\n\n**Schedule overdue** \u2014 the backup scheduler did not enqueue a job within\nthe expected window (1 hour past `next_run`). Usually means the scheduler\ntask is dead or wedged.\n\n**Job stalled** \u2014 a `backup_jobs` row has been in `state='pending'` for\nmore than 1 hour. The runner never claimed the job. Usually means the\nrunner task is dead or the runner concurrency cap is too low.", + "operationId": "list_backup_alerts", + "responses": { + "200": { + "description": "List of open backup alerts", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BackupAlertListResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/backups/cleanup": { + "post": { + "tags": [ + "Backups" + ], + "summary": "Preview or run retention using each selected schedule's configured retention days.", + "operationId": "cleanup_expired_backups", + "parameters": [ + { + "name": "dry_run", + "in": "query", + "description": "Return the backups selected by retention without deleting anything.", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "name": "schedule_id", + "in": "query", + "description": "Limit cleanup to one backup schedule.", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CleanupExpiredBackupsRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Retention cleanup completed", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RetentionCleanupReport" + } + } + } + }, + "400": { + "description": "Missing or invalid preview candidate list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Schedule or backup not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "409": { + "description": "Cleanup preview is stale", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Cleanup could not be started", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/backups/external-services/{id}/run": { + "post": { + "tags": [ + "Backups" + ], + "summary": "Run a backup for an external service manually.", + "description": "Enqueues the backup for asynchronous execution via the `BackupRunner`\n(ADR-014). Returns `202 Accepted` immediately: pending parent and child\nrows are inserted, and a `backup_jobs` row is enqueued for the resolved\nengine. Poll `GET /backups/{id}` to observe `pending \u2192 running \u2192 completed`.", + "operationId": "run_external_service_backup", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RunExternalServiceBackupRequest" + } + } + }, + "required": true + }, + "responses": { + "202": { + "description": "Backup enqueued for async execution", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExternalServiceBackupResponse" + } + } + } + }, + "400": { + "description": "Invalid request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "External service or S3 source not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/backups/external-services/{service_id}/backups": { + "get": { + "tags": [ + "Backups" + ], + "summary": "List all backups for a specific external service (DB-only, no S3 scan).", + "description": "Returns a paginated list of backups that belong to this service.\nCompletes in <100 ms regardless of S3 endpoint latency because it\nnever touches S3.", + "operationId": "list_external_service_backups", + "parameters": [ + { + "name": "service_id", + "in": "path", + "description": "External service ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "page", + "in": "query", + "description": "Page number (1-based). Defaults to 1.", + "required": false, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "page_size", + "in": "query", + "description": "Items per page. Defaults to 20, max 100.", + "required": false, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "Paginated list of backups for this service", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceBackupListResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/backups/external-services/{service_id}/schedules": { + "get": { + "tags": [ + "Backups" + ], + "summary": "List the schedules that target a specific external service. Useful for\nthe service detail page (\"which schedules back this DB up?\").", + "operationId": "list_service_schedules", + "parameters": [ + { + "name": "service_id", + "in": "path", + "description": "External service ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Schedules backing up this service", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BackupScheduleResponse" + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Service not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/backups/s3-sources": { + "get": { + "tags": [ + "Backups" + ], + "summary": "List all S3 sources", + "operationId": "list_s3_sources", + "responses": { + "200": { + "description": "List of S3 sources", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/S3SourceResponse" + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Backups" + ], + "summary": "Create a new S3 source", + "operationId": "create_s3_source", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateS3SourceRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "S3 source created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/S3SourceResponse" + } + } + } + }, + "400": { + "description": "Invalid request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/backups/s3-sources/test": { + "post": { + "tags": [ + "Backups" + ], + "summary": "Test S3 connectivity against a prospective source configuration (before creating it).\nThe credentials are NOT persisted. Useful for validating the form in the UI.", + "operationId": "test_s3_connection_preview", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateS3SourceRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Connection test result", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/S3ConnectionTestResponse" + } + } + } + }, + "400": { + "description": "Invalid request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/backups/s3-sources/{id}": { + "get": { + "tags": [ + "Backups" + ], + "summary": "Get an S3 source by ID", + "operationId": "get_s3_source", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "S3 source details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/S3SourceResponse" + } + } + } + }, + "404": { + "description": "S3 source not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "Backups" + ], + "summary": "Delete an S3 source", + "operationId": "delete_s3_source", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "S3 source deleted" + }, + "404": { + "description": "S3 source not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "patch": { + "tags": [ + "Backups" + ], + "summary": "Update an S3 source", + "operationId": "update_s3_source", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateS3SourceRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "S3 source updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/S3SourceResponse" + } + } + } + }, + "404": { + "description": "S3 source not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/backups/s3-sources/{id}/backups": { + "get": { + "tags": [ + "Backups" + ], + "summary": "List all backups in an S3 source", + "operationId": "list_source_backups", + "parameters": [ + { + "name": "include_s3_scan", + "in": "query", + "description": "When `true`, scan the S3 bucket for backups not tracked in the\nlocal database (useful after disaster-recovery from another Temps\ninstance). Defaults to `false` \u2014 the fast DB-only path.", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "List of all backups in the source", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SourceBackupIndexResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "S3 source not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/backups/s3-sources/{id}/run": { + "post": { + "tags": [ + "Backups" + ], + "summary": "Run a backup immediately for an S3 source.", + "description": "Enqueues the backup for asynchronous execution via the `BackupRunner`\n(ADR-014). Returns `202 Accepted` immediately: a `backups` row is inserted\nwith `state='pending'` and a `backup_jobs` row is enqueued for the\n`ControlPlaneEngine`. Poll `GET /backups/{id}` to observe\n`pending \u2192 running \u2192 completed`.", + "operationId": "run_backup_for_source", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RunBackupRequest" + } + } + }, + "required": true + }, + "responses": { + "202": { + "description": "Backup enqueued for async execution", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BackupResponse" + } + } + } + }, + "400": { + "description": "Invalid request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "S3 source not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/backups/s3-sources/{id}/set-default": { + "post": { + "tags": [ + "Backups" + ], + "summary": "Mark an S3 source as the default. All new backups/schedules/services that do not\nexplicitly reference a source will use the default. Returns the updated source.", + "operationId": "set_default_s3_source", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "S3 source marked as default", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/S3SourceResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "S3 source not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/backups/s3-sources/{id}/test": { + "post": { + "tags": [ + "Backups" + ], + "summary": "Test connectivity to an existing S3 source using its stored credentials.", + "operationId": "test_s3_source_connection", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Connection test result", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/S3ConnectionTestResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "S3 source not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/backups/schedule-runs/{id}/cancel": { + "post": { + "tags": [ + "Backups" + ], + "summary": "Cancel every non-terminal child backup belonging to a schedule run.", + "description": "Loops over `state IN ('pending','running')` children and flips each via\nthe same path as the per-backup cancel endpoint. The parent\n`schedule_runs.finished_at` is stamped automatically once no live\nchildren remain. Idempotent: cancelling a run with no live children is\na 200 with `cancelled = 0`.", + "operationId": "cancel_schedule_run", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "Cancel processed (idempotent)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CancelBackupResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Schedule run not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/backups/schedule-runs/{id}/jobs": { + "get": { + "tags": [ + "Backups" + ], + "summary": "List the individual backup jobs for a single scheduler run.", + "description": "Returns each child `backups` row joined with its external service name and\nthe most-recent `backup_jobs` engine key. Used by the schedule detail\naccordion to show per-job detail on row expand.\n\n`page_size` defaults to 50 and is capped at 200.", + "operationId": "list_schedule_run_jobs", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "Jobs for this scheduler run", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ScheduleRunJobEntry" + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/backups/schedules": { + "get": { + "tags": [ + "Backups" + ], + "summary": "List all backup schedules", + "operationId": "list_backup_schedules", + "responses": { + "200": { + "description": "List of backup schedules", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BackupScheduleResponse" + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Backups" + ], + "summary": "Create a new backup schedule", + "operationId": "create_backup_schedule", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateBackupScheduleRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Backup schedule created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BackupScheduleResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/backups/schedules/{id}": { + "get": { + "tags": [ + "Backups" + ], + "summary": "Get a backup schedule by ID", + "operationId": "get_backup_schedule", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Backup schedule details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BackupScheduleResponse" + } + } + } + }, + "404": { + "description": "Backup schedule not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "Backups" + ], + "summary": "Delete a backup schedule", + "operationId": "delete_backup_schedule", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Backup schedule deleted" + }, + "404": { + "description": "Backup schedule not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "patch": { + "tags": [ + "Backups" + ], + "summary": "Update a backup schedule (partial update).", + "description": "All request fields are optional; only fields that are present in the\nJSON body are updated. Absent fields leave the corresponding column\nunchanged. If `schedule_expression` is changed, `next_run` is\nrecomputed automatically.", + "operationId": "update_backup_schedule", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateBackupScheduleRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Schedule updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BackupScheduleResponse" + } + } + } + }, + "400": { + "description": "Validation error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Schedule not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/backups/schedules/{id}/backups": { + "get": { + "tags": [ + "Backups" + ], + "summary": "List backups for a schedule", + "operationId": "list_backups_for_schedule", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "List of backups for the schedule", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BackupResponse" + } + } + } + } + }, + "404": { + "description": "Backup schedule not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/backups/schedules/{id}/disable": { + "patch": { + "tags": [ + "Backups" + ], + "summary": "Disable a backup schedule", + "operationId": "disable_backup_schedule", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Backup schedule disabled", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BackupScheduleResponse" + } + } + } + }, + "404": { + "description": "Backup schedule not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/backups/schedules/{id}/enable": { + "patch": { + "tags": [ + "Backups" + ], + "summary": "Enable a backup schedule", + "operationId": "enable_backup_schedule", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Backup schedule enabled", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BackupScheduleResponse" + } + } + } + }, + "404": { + "description": "Backup schedule not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/backups/schedules/{id}/run": { + "post": { + "tags": [ + "Backups" + ], + "summary": "Immediately fan-out a run for the given schedule (Run Now).", + "description": "Creates one `schedule_runs` row, one control-plane backup job, and one\nbackup job per supported external service \u2014 all in a single transaction.\nReturns `202 Accepted` with a [`ScheduleRunResponse`] containing the new\n`schedule_run_id` and the list of enqueued jobs. Returns `409 Conflict` if\na run for this schedule is already in flight or if the schedule is disabled.", + "operationId": "run_schedule_now", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "202": { + "description": "Fan-out run enqueued for async execution", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScheduleRunResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Schedule not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "409": { + "description": "Run already in flight or schedule disabled", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/backups/schedules/{id}/runs": { + "get": { + "tags": [ + "Backups" + ], + "summary": "Paginated run history for a backup schedule (one row per scheduler tick).", + "description": "Returns one [`ScheduleRunSummary`] per scheduler tick, with child backup\ncounts aggregated in a single SQL round-trip. Legacy `backups` rows (pre-\nfan-out) are surfaced as synthetic single-job runs so history does not\ndisappear. Ordered by `started_at DESC` (newest first).\n\nUse `GET /backups/schedule-runs/{run_id}/jobs` to drill into a single run.", + "operationId": "list_schedule_runs", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "Page number (1-based, defaults to 1, clamped to 1 if < 1).", + "required": false, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "page_size", + "in": "query", + "description": "Items per page (defaults to 20, clamped to 100 if > 100).", + "required": false, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Paginated run history for the schedule", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScheduleRunSummaryList" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Schedule not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/backups/schedules/{id}/services": { + "get": { + "tags": [ + "Backups" + ], + "summary": "List the external services attached to a backup schedule.", + "operationId": "list_schedule_services", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Schedule ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Services attached to this schedule", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ExternalServiceSummary" + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Schedule not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Backups" + ], + "summary": "Attach one or more external services to a backup schedule. Idempotent \u2014\nservices that are already attached are silently skipped (`ON CONFLICT\nDO NOTHING`). Returns the count of newly inserted rows + the total\nmembership after the operation.", + "operationId": "attach_schedule_services", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Schedule ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AttachScheduleServicesRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Services attached", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AttachScheduleServicesResponse" + } + } + } + }, + "400": { + "description": "Validation error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Schedule not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/backups/schedules/{id}/services/{service_id}": { + "delete": { + "tags": [ + "Backups" + ], + "summary": "Detach a single external service from a backup schedule. Idempotent \u2014\nreturns `204` whether or not a row was actually removed.", + "operationId": "detach_schedule_service", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Schedule ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "service_id", + "in": "path", + "description": "External service ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Service detached (or was not attached)" + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/backups/{id}": { + "get": { + "tags": [ + "Backups" + ], + "summary": "Get a backup by ID", + "operationId": "get_backup", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Backup details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BackupResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Backup not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "Backups" + ], + "summary": "Permanently delete one terminal backup from object storage and the database.", + "operationId": "delete_backup", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Backup UUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Backup deleted" + }, + "400": { + "description": "Backup artifact cannot be safely attributed", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Backup not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "409": { + "description": "Backup is running, referenced, or lacks safe artifact identity", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Object storage or database error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/backups/{id}/cancel": { + "post": { + "tags": [ + "Backups" + ], + "summary": "Cancel a single in-flight backup.", + "description": "Flips the parent `backups` row + its latest `backup_jobs` row to\n`failed` with reason `\"cancelled by user \"`. The in-process\n`CancellationToken` is observed on the next heartbeat tick (\u22645s), so the\nengine exits cleanly and rollback reaps the sidecar. Idempotent: cancelling\nan already-terminal backup is a 200 with `cancelled = 0`.", + "operationId": "cancel_backup", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Cancel processed (idempotent)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CancelBackupResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Backup not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/backups/{id}/children": { + "get": { + "tags": [ + "Backups" + ], + "summary": "List the external-service child backups that belong to a parent backup.", + "description": "Each entry in `children` corresponds to one `external_service_backups` row,\njoined with `external_services` so the caller receives the service name and\ntype without a second request.\n\nReturns an empty `{ \"children\": [] }` \u2014 **not 404** \u2014 when the parent\nbackup exists but has no children (e.g. control-plane backups).\nReturns 404 when the parent backup itself does not exist.", + "operationId": "list_backup_children", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Integer row id of the parent backup", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Child backup list (may be empty)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChildBackupListResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Parent backup not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/blob": { + "get": { + "tags": [ + "Blob" + ], + "summary": "List blobs", + "operationId": "blob_list", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Maximum number of items to return", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "prefix", + "in": "query", + "description": "Prefix to filter by", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "cursor", + "in": "query", + "description": "Continuation token for pagination", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "List of blobs", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListBlobsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Blob" + ], + "summary": "Upload a blob", + "operationId": "blob_put", + "requestBody": { + "description": "Binary blob data", + "content": { + "application/octet-stream": { + "schema": { + "type": "string" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Blob uploaded successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BlobResponse" + } + } + } + }, + "400": { + "description": "Invalid request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "Blob" + ], + "summary": "Delete blobs", + "operationId": "blob_delete", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteBlobRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Blobs deleted successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteBlobResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/blob/copy": { + "post": { + "tags": [ + "Blob" + ], + "summary": "Copy a blob to a new location", + "operationId": "blob_copy", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CopyBlobRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Blob copied successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BlobResponse" + } + } + } + }, + "400": { + "description": "Invalid request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Source blob not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/blob/disable": { + "delete": { + "tags": [ + "Blob Management" + ], + "summary": "Disable Blob service", + "operationId": "blob_disable", + "responses": { + "200": { + "description": "Blob service disabled", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DisableBlobResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Blob service not enabled" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/blob/enable": { + "post": { + "tags": [ + "Blob Management" + ], + "summary": "Enable Blob service", + "operationId": "blob_enable", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnableBlobRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Blob service enabled", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnableBlobResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/blob/status": { + "get": { + "tags": [ + "Blob Management" + ], + "summary": "Get Blob service status", + "operationId": "blob_status", + "responses": { + "200": { + "description": "Blob service status", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BlobStatusResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/blob/update": { + "patch": { + "tags": [ + "Blob Management" + ], + "summary": "Update Blob service configuration", + "operationId": "blob_update", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateBlobRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Blob service updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateBlobResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Blob service not enabled" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/blob/{project_id}/{path}": { + "get": { + "tags": [ + "Blob" + ], + "summary": "Download a blob", + "operationId": "blob_download", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "path", + "in": "path", + "description": "Blob path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Blob content" + }, + "404": { + "description": "Blob not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "head": { + "tags": [ + "Blob" + ], + "summary": "Get blob metadata", + "operationId": "blob_head", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "path", + "in": "path", + "description": "Blob path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Blob metadata in headers" + }, + "404": { + "description": "Blob not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/dashboard/projects-analytics": { + "get": { + "tags": [ + "Events" + ], + "summary": "Get dashboard analytics for multiple projects in a single batch request", + "description": "Returns unique visitor counts and hourly sparkline data for all requested projects\nusing only 2 SQL queries instead of 2\u00d7N per-project queries.", + "operationId": "get_dashboard_projects_analytics", + "parameters": [ + { + "name": "project_ids", + "in": "query", + "description": "Comma-separated list of project IDs", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "start_date", + "in": "query", + "description": "Start date for filtering", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "end_date", + "in": "query", + "description": "End date for filtering", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved batch analytics", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardProjectsAnalyticsResponse" + } + } + } + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/deployments/activity-graph": { + "get": { + "tags": [ + "Deployments" + ], + "summary": "Get deployment activity graph showing daily deployment counts\nSimilar to GitHub's contribution graph", + "operationId": "get_activity_graph", + "parameters": [ + { + "name": "project_id", + "in": "query", + "description": "Filter by project ID (optional)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Filter by environment ID (optional)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "days", + "in": "query", + "description": "Number of days to include (default: 365)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved activity graph", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ActivityGraphResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/deployments/{deployment_id}/vulnerability-scan": { + "get": { + "tags": [ + "Vulnerability Scans" + ], + "operationId": "get_scan_by_deployment", + "parameters": [ + { + "name": "deployment_id", + "in": "path", + "description": "Deployment ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Scan for the specified deployment", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScanResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "No scan found for deployment", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/deployments/{id}/metrics": { + "get": { + "tags": [ + "Metrics" + ], + "summary": "Fetch a time-series range for a single metric on a deployment.", + "operationId": "DeploymentMetricsGetRange", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Deployment ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "metric", + "in": "query", + "description": "Metric name, e.g. `\"pg.connections_active\"`.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "range", + "in": "query", + "description": "Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`.", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "percentile", + "in": "query", + "description": "Optional histogram percentile (0\u2013100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile.", + "required": false, + "schema": { + "type": [ + "number", + "null" + ], + "format": "double" + } + } + ], + "responses": { + "200": { + "description": "Metric time series data points", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MetricDataPoint" + } + } + } + } + }, + "400": { + "description": "Invalid query parameters" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + }, + "503": { + "description": "Metrics store not available" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/deployments/{id}/metrics/enable": { + "patch": { + "tags": [ + "Metrics" + ], + "summary": "Enable or disable OTLP metric ingestion for a deployment.", + "description": "When `enabled=true`, seeds the default container alert rules for the\ndeployment via [`temps_monitoring::seed_default_container_rules`] (idempotent).", + "operationId": "DeploymentMetricsToggle", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Deployment ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ToggleDeploymentMetricsRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Metrics toggle applied" + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/deployments/{id}/metrics/latest": { + "get": { + "tags": [ + "Metrics" + ], + "summary": "Fetch the most-recent metric values for a deployment.", + "operationId": "DeploymentMetricsGetLatest", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Deployment ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Map of metric name to latest value", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": { + "type": "number", + "format": "double" + }, + "propertyNames": { + "type": "string" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + }, + "503": { + "description": "Metrics store not available" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/dns-providers": { + "get": { + "tags": [ + "DNS Providers" + ], + "summary": "List all DNS providers", + "operationId": "list_dns_providers", + "responses": { + "200": { + "description": "List of DNS providers", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DnsProviderResponse" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "DNS Providers" + ], + "summary": "Create a new DNS provider", + "description": "The provider's credentials will be tested before creation.\nIf the connection test fails, the provider will not be created.", + "operationId": "create_dns_provider", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateDnsProviderRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "DNS provider created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DnsProviderResponse" + } + } + } + }, + "400": { + "description": "Invalid request or connection test failed" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/dns-providers/{id}": { + "get": { + "tags": [ + "DNS Providers" + ], + "summary": "Get a DNS provider by ID", + "operationId": "get_dns_provider", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "DNS provider details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DnsProviderResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Provider not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "put": { + "tags": [ + "DNS Providers" + ], + "summary": "Update a DNS provider", + "description": "If new credentials are supplied, they are tested before the update is\npersisted (same as creation) -- otherwise a provider's credentials (and,\nfor Pebble, its target URL) could be swapped for something invalid or\nunsafe without ever going through validation.", + "operationId": "update_provider", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateDnsProviderRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "DNS provider updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DnsProviderResponse" + } + } + } + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Provider not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "DNS Providers" + ], + "summary": "Delete a DNS provider", + "operationId": "delete_dns_provider", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "DNS provider deleted" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Provider not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/dns-providers/{id}/domains": { + "get": { + "tags": [ + "DNS Providers" + ], + "summary": "List managed domains for a provider", + "operationId": "list_managed_domains", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "List of managed domains", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ManagedDomainResponse" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Provider not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "DNS Providers" + ], + "summary": "Add a managed domain to a provider", + "operationId": "add_managed_domain", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddManagedDomainApiRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Managed domain added", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ManagedDomainResponse" + } + } + } + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Provider not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/dns-providers/{id}/test": { + "post": { + "tags": [ + "DNS Providers" + ], + "summary": "Test provider connection", + "operationId": "test_provider_connection", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Connection test result", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConnectionTestResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Provider not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/dns-providers/{id}/zones": { + "get": { + "tags": [ + "DNS Providers" + ], + "summary": "List zones available in a provider", + "operationId": "list_provider_zones", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "List of zones", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ZoneListResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Provider not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/dns-providers/{provider_id}/domains/{domain}": { + "delete": { + "tags": [ + "DNS Providers" + ], + "summary": "Remove a managed domain", + "operationId": "remove_managed_domain", + "parameters": [ + { + "name": "provider_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "domain", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Managed domain removed" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Domain not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "patch": { + "tags": [ + "DNS Providers" + ], + "summary": "Update a managed domain's settings (hostname mode, sync opt-in, auto-manage).", + "operationId": "update_managed_domain", + "parameters": [ + { + "name": "provider_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "domain", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateManagedDomainApiRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Managed domain updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ManagedDomainResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Domain not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/dns-providers/{provider_id}/domains/{domain}/apply-hostname-mode": { + "post": { + "tags": [ + "DNS Providers" + ], + "summary": "Apply a hostname mode to a managed domain (persist + optional DNS sync +\nroute reload).", + "operationId": "apply_hostname_mode", + "parameters": [ + { + "name": "provider_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "domain", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApplyHostnameModeRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Hostname mode applied", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HostnamePreviewResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions or token lacks zone access" + }, + "404": { + "description": "Domain not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/dns-providers/{provider_id}/domains/{domain}/hostname-preview": { + "get": { + "tags": [ + "DNS Providers" + ], + "summary": "Preview the impact of switching a managed domain's hostname mode.", + "operationId": "preview_hostname_mode", + "parameters": [ + { + "name": "mode", + "in": "query", + "description": "Target mode: standard|flat", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "sync", + "in": "query", + "description": "Include DNS record changes", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "name": "provider_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "domain", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Hostname mode preview", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HostnamePreviewResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Domain not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/dns-providers/{provider_id}/domains/{domain}/verify": { + "post": { + "tags": [ + "DNS Providers" + ], + "summary": "Verify a managed domain", + "operationId": "verify_managed_domain", + "parameters": [ + { + "name": "provider_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "domain", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Domain verification result", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ManagedDomainResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Domain not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/dns/lookup": { + "get": { + "tags": [ + "DNS" + ], + "summary": "Lookup DNS A records for a domain", + "operationId": "lookup_dns_a_records", + "parameters": [ + { + "name": "domain", + "in": "query", + "description": "Domain name to lookup", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved DNS A records", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DnsLookupResponse" + } + } + } + }, + "400": { + "description": "Invalid domain name or lookup failed", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DnsLookupError" + } + } + } + } + } + } + }, + "/domains": { + "get": { + "tags": [ + "Domains" + ], + "summary": "List all domains", + "operationId": "list_domains", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "Page number (1-indexed)", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + }, + "example": 1 + }, + { + "name": "page_size", + "in": "query", + "description": "Number of items per page (max 100)", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + }, + "example": 20 + }, + { + "name": "search", + "in": "query", + "description": "Search domains by name (substring match)", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + }, + "example": "example.com" + } + ], + "responses": { + "200": { + "description": "Domains retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListDomainsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Domains" + ], + "summary": "Create a new domain", + "description": "Creates a new domain and automatically requests a Let's Encrypt challenge.\nYou can specify the challenge type (HTTP-01 or DNS-01) in the request.\n\n- **HTTP-01**: Validates domain ownership by placing a file on your web server at `/.well-known/acme-challenge/`\n- **DNS-01**: Validates domain ownership by adding a TXT record to your DNS (required for wildcard domains)", + "operationId": "create_domain", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateDomainRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Domain created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DomainResponse" + } + } + } + }, + "400": { + "description": "Invalid input" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/domains/by-host/{hostname}": { + "get": { + "tags": [ + "Domains" + ], + "summary": "Get domain details by hostname", + "operationId": "get_domain_by_host", + "parameters": [ + { + "name": "hostname", + "in": "path", + "description": "Domain hostname", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Domain details retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DomainResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Domain not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/domains/by-host/{hostname}/cert-status": { + "get": { + "tags": [ + "Domains" + ], + "summary": "Get on-demand TLS certificate status for a hostname", + "description": "Returns the current cert lifecycle state for a single hostname (from the\n`domains` row) plus the most recent on-demand issuance attempt (from the\n`on_demand_cert_attempts` audit log). This is the operator's first-line\ndiagnostic, surfaced by `temps domain cert-status` (ADR-018 \u00a75). Returns the\nhostname with `None` fields when no on-demand activity exists for it (never a\n404, so the CLI can render \"no attempts recorded\").", + "operationId": "get_on_demand_cert_status", + "parameters": [ + { + "name": "hostname", + "in": "path", + "description": "Domain hostname", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "On-demand cert status retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CertStatusResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/domains/on-demand-certs": { + "get": { + "tags": [ + "Domains" + ], + "summary": "List on-demand TLS certificate attempts", + "description": "Returns rows from the append-only `on_demand_cert_attempts` audit log\n(ADR-018 \u00a75), newest first, each joined with the current authoritative cert\nstate (`status`, `expiration_time`, `backoff_until`) from the `domains` row.\nThis backs the console \"Certificates\" surface. No certificate or private-key\nmaterial is returned \u2014 only audit metadata.", + "operationId": "list_on_demand_certs", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "Page number (1-indexed)", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + }, + "example": 1 + }, + { + "name": "page_size", + "in": "query", + "description": "Number of items per page (max 100)", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + }, + "example": 20 + } + ], + "responses": { + "200": { + "description": "On-demand cert attempts retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListOnDemandCertsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/domains/{domain_id}/order": { + "get": { + "tags": [ + "Domains" + ], + "summary": "Get ACME order for a domain", + "operationId": "get_domain_order", + "parameters": [ + { + "name": "domain_id", + "in": "path", + "description": "Domain ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Order retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AcmeOrderResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Order not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Domains" + ], + "summary": "Create or recreate ACME order for a domain", + "description": "Creates a new ACME order with Let's Encrypt for the specified domain.\nIf an order already exists, you should cancel it first using the cancel-order endpoint.\nReturns the challenge details that need to be fulfilled (DNS record or HTTP token).", + "operationId": "create_or_recreate_order", + "parameters": [ + { + "name": "domain_id", + "in": "path", + "description": "Domain ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Order created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DomainChallengeResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Domain not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "Domains" + ], + "summary": "Cancel ACME order for a domain", + "description": "Cancels the current ACME order for a domain and clears all challenge data.\nThis allows you to start over with a new order if the previous one failed or got stuck.", + "operationId": "cancel_domain_order", + "parameters": [ + { + "name": "domain_id", + "in": "path", + "description": "Domain ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Order cancelled successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DomainResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Domain not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/domains/{domain_id}/order/finalize": { + "post": { + "tags": [ + "Domains" + ], + "summary": "Finalize ACME order for a domain", + "description": "Finalizes the ACME order by completing the challenge validation and requesting the certificate.\nThis should be called after the challenge has been set up (DNS record added or HTTP token served).", + "operationId": "finalize_order", + "parameters": [ + { + "name": "domain_id", + "in": "path", + "description": "Domain ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Order finalized successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DomainResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Domain or order not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/domains/{domain_id}/setup-dns": { + "post": { + "tags": [ + "Domains" + ], + "summary": "Setup DNS challenge records automatically using a DNS provider", + "description": "This endpoint automatically creates the required DNS TXT records for ACME DNS-01 challenge\nvalidation using a configured DNS provider. The domain must have an active DNS challenge\npending (created via POST /domains/{id}/order with dns-01 challenge type).\n\nThis is similar to how email domain DNS records are auto-provisioned.", + "operationId": "setup_dns_challenge", + "parameters": [ + { + "name": "domain_id", + "in": "path", + "description": "Domain ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetupDnsChallengeRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "DNS records created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetupDnsChallengeResponse" + } + } + } + }, + "400": { + "description": "Bad request - DNS provider not configured or no challenge pending" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Domain or DNS provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/domains/{domain}": { + "get": { + "tags": [ + "Domains" + ], + "summary": "Get domain by ID", + "operationId": "get_domain_by_id", + "parameters": [ + { + "name": "domain", + "in": "path", + "description": "Domain ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Domain retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DomainResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Domain not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "Domains" + ], + "summary": "Delete a domain", + "operationId": "delete_domain", + "parameters": [ + { + "name": "domain", + "in": "path", + "description": "Domain name", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Domain deleted successfully" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Domain not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/domains/{domain}/challenge-token": { + "get": { + "tags": [ + "Domains" + ], + "summary": "Get challenge token for a domain (returns plain text token)", + "operationId": "get_challenge_token", + "parameters": [ + { + "name": "domain", + "in": "path", + "description": "Domain name", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Challenge token retrieved successfully", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Challenge not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/domains/{domain}/http-challenge-debug": { + "get": { + "tags": [ + "Domains" + ], + "summary": "Get HTTP challenge debug information", + "description": "Returns detailed debug information for HTTP-01 challenge including:\n- Whether a challenge exists for the domain\n- The challenge token and URL that Let's Encrypt will access\n- DNS resolution information showing where the domain currently points\n\nThis is useful for debugging why HTTP-01 challenges fail.", + "operationId": "get_http_challenge_debug", + "parameters": [ + { + "name": "domain", + "in": "path", + "description": "Domain name", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Debug information retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HttpChallengeDebugResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/domains/{domain}/provision": { + "post": { + "tags": [ + "Domains" + ], + "summary": "Provision a domain certificate", + "operationId": "provision_domain", + "parameters": [ + { + "name": "domain", + "in": "path", + "description": "Domain name", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Certificate provisioning initiated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProvisionResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Domain not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/domains/{domain}/renew": { + "post": { + "tags": [ + "Domains" + ], + "summary": "Renew domain certificate", + "description": "For HTTP-01 domains: Automatically renews the certificate\nFor DNS-01 domains (wildcards): Creates a new ACME order and returns challenge data", + "operationId": "renew_domain", + "parameters": [ + { + "name": "domain", + "in": "path", + "description": "Domain name", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Certificate renewal initiated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProvisionResponse" + } + } + } + }, + "202": { + "description": "DNS challenge created - manual action required", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DomainChallengeResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Domain not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/domains/{domain}/status": { + "get": { + "tags": [ + "Domains" + ], + "summary": "Check domain status", + "operationId": "check_domain_status", + "parameters": [ + { + "name": "domain", + "in": "path", + "description": "Domain ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Domain status retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DomainResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Domain not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/drop/inspect": { + "post": { + "tags": [ + "Projects" + ], + "summary": "Inspect a source ZIP without creating a project or retaining the upload.", + "operationId": "inspect_drop_archive", + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/DropArchiveUpload" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Detected deployable project roots", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DropInspectionResponse" + } + } + } + }, + "400": { + "description": "Invalid or unsupported archive" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/email-domains": { + "get": { + "tags": [ + "Email Domains" + ], + "summary": "List all email domains", + "operationId": "list_email_domains", + "parameters": [ + { + "name": "provider_id", + "in": "query", + "description": "Only return domains belonging to this provider", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "List of email domains", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EmailDomainResponse" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Email Domains" + ], + "summary": "Create a new email domain", + "operationId": "create_email_domain", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateEmailDomainRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Domain created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmailDomainWithDnsResponse" + } + } + } + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/email-domains/by-domain/{domain}": { + "get": { + "tags": [ + "Email Domains" + ], + "summary": "Get an email domain by domain name with DNS records", + "operationId": "get_domain_by_name", + "parameters": [ + { + "name": "domain", + "in": "path", + "description": "Domain name (e.g., 'mail.example.com')", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Email domain details with DNS records", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmailDomainWithDnsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Domain not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/email-domains/{id}": { + "get": { + "tags": [ + "Email Domains" + ], + "summary": "Get an email domain by ID with DNS records", + "operationId": "get_domain", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Domain ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Email domain details with DNS records", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmailDomainWithDnsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Domain not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "Email Domains" + ], + "summary": "Delete an email domain", + "operationId": "delete_email_domain", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Domain ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Domain deleted" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Domain not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/email-domains/{id}/dns-records": { + "get": { + "tags": [ + "Email Domains" + ], + "summary": "Get DNS records for an email domain", + "operationId": "get_domain_dns_records", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Domain ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "DNS records for the domain", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DnsRecordResponse" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Domain not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/email-domains/{id}/setup-dns": { + "post": { + "tags": [ + "Email Domains" + ], + "summary": "Setup DNS records for an email domain using a configured DNS provider", + "operationId": "setup_dns", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Email Domain ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetupDnsRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "DNS records setup result", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetupDnsResponse" + } + } + } + }, + "400": { + "description": "Invalid request or DNS provider not configured" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Domain not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/email-domains/{id}/verify": { + "post": { + "tags": [ + "Email Domains" + ], + "summary": "Verify an email domain's DNS configuration", + "operationId": "verify_domain", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Domain ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Domain verification result with DNS records", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmailDomainWithDnsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Domain not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/email-providers": { + "get": { + "tags": [ + "Email Providers" + ], + "summary": "List all email providers", + "operationId": "list_email_providers", + "responses": { + "200": { + "description": "List of email providers", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EmailProviderResponse" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Email Providers" + ], + "summary": "Create a new email provider", + "operationId": "create_email_provider", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateEmailProviderRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Provider created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmailProviderResponse" + } + } + } + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/email-providers/{id}": { + "get": { + "tags": [ + "Email Providers" + ], + "summary": "Get an email provider by ID", + "operationId": "get_email_provider", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Provider ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Email provider details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmailProviderResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "Email Providers" + ], + "summary": "Delete an email provider", + "operationId": "delete_email_provider", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Provider ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Provider deleted" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "patch": { + "tags": [ + "Email Providers" + ], + "summary": "Update an email provider", + "description": "Partial update \u2014 any field left out keeps its current value. Most importantly,\nomitting the credential block (`ses_credentials`/`scaleway_credentials`/`smtp_credentials`)\npreserves the stored secret, so operators can rename a provider without re-typing\npasswords. `provider_type` is immutable; to switch providers, delete and recreate.", + "operationId": "update_email_provider", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Provider ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateEmailProviderRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Provider updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmailProviderResponse" + } + } + } + }, + "400": { + "description": "Validation error" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Provider not found" + }, + "409": { + "description": "Provider type mismatch" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/email-providers/{id}/test": { + "post": { + "tags": [ + "Email Providers" + ], + "summary": "Test an email provider by sending a test email to the logged-in user", + "operationId": "test_provider", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Provider ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TestEmailRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Test email result", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TestEmailResponse" + } + } + } + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/email-providers/{id}/tracking/setup": { + "post": { + "tags": [ + "Email Providers" + ], + "summary": "One-click AWS-side setup of SES event tracking (SNS topic + webhook\nsubscription + SESv2 event destination), using the provider's stored\ncredentials.", + "operationId": "setup_email_tracking", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Provider ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Setup completed", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmailTrackingSetupResponse" + } + } + } + }, + "400": { + "description": "Provider does not support event tracking" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Provider not found" + }, + "502": { + "description": "An AWS call failed \u2014 the response detail names the failed step" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/email-providers/{id}/tracking/status": { + "get": { + "tags": [ + "Email Providers" + ], + "summary": "Live status of SES event tracking for a provider", + "operationId": "get_email_tracking_status", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Provider ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Event tracking status", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmailTrackingStatusResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Provider not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/emails": { + "get": { + "tags": [ + "Emails" + ], + "summary": "List emails with optional filtering", + "operationId": "list_emails", + "parameters": [ + { + "name": "domain_id", + "in": "query", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + }, + { + "name": "project_id", + "in": "query", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + }, + { + "name": "status", + "in": "query", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "from_address", + "in": "query", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + } + }, + { + "name": "page_size", + "in": "query", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "List of emails", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PaginatedEmailsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Emails" + ], + "summary": "Send an email", + "operationId": "send_email", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SendEmailRequestBody" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Email sent successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SendEmailResponseBody" + } + } + } + }, + "400": { + "description": "Invalid request or domain not verified" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/emails/events": { + "get": { + "tags": [ + "Email Tracking" + ], + "summary": "GET /emails/events", + "operationId": "get_global_events", + "parameters": [ + { + "name": "event_type", + "in": "query", + "description": "Filter by event type (open, click)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "page", + "in": "query", + "description": "Page number (default: 1)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "page_size", + "in": "query", + "description": "Page size (default: 20, max: 100)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "Paginated tracking events", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PaginatedEventsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/emails/events/stats": { + "get": { + "tags": [ + "Email Tracking" + ], + "summary": "GET /emails/events/stats", + "operationId": "get_global_event_stats", + "responses": { + "200": { + "description": "Global tracking statistics", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GlobalEventStatsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/emails/stats": { + "get": { + "tags": [ + "Emails" + ], + "summary": "Get email statistics", + "operationId": "get_email_stats", + "parameters": [ + { + "name": "domain_id", + "in": "query", + "description": "Optional domain ID to filter stats", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Email statistics", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmailStatsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/emails/validate": { + "post": { + "tags": [ + "Email Validation" + ], + "summary": "Validate an email address", + "operationId": "validate_email", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidateEmailRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Email validation result", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidateEmailResponse" + } + } + } + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/emails/{email_id}/track/click/{link_index}": { + "get": { + "tags": [ + "Email Tracking" + ], + "summary": "Track email link click - redirects to original URL", + "description": "This endpoint replaces original links in tracked emails.\nNo authentication required - it's called when the recipient clicks a link.", + "operationId": "track_click", + "parameters": [ + { + "name": "email_id", + "in": "path", + "description": "Email ID (UUID)", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "link_index", + "in": "path", + "description": "Link index", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "302": { + "description": "Redirect to original URL" + }, + "404": { + "description": "Link not found" + } + } + } + }, + "/emails/{email_id}/track/open": { + "get": { + "tags": [ + "Email Tracking" + ], + "summary": "Track email open - returns a 1x1 transparent GIF", + "description": "This endpoint is embedded as an tag in emails.\nNo authentication required - it's called by the email client.", + "operationId": "track_open", + "parameters": [ + { + "name": "email_id", + "in": "path", + "description": "Email ID (UUID)", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "1x1 transparent tracking pixel" + }, + "404": { + "description": "Email not found" + } + } + } + }, + "/emails/{id}": { + "get": { + "tags": [ + "Emails" + ], + "summary": "Get an email by ID", + "operationId": "get_email", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Email ID (UUID)", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Email details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmailResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Email not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/emails/{id}/tracking": { + "get": { + "tags": [ + "Email Tracking" + ], + "summary": "Get email tracking summary", + "operationId": "get_email_tracking", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Email ID (UUID)", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Tracking summary", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmailTrackingResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Email not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/emails/{id}/tracking/events": { + "get": { + "tags": [ + "Email Tracking" + ], + "summary": "Get email tracking events", + "operationId": "get_email_events", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Email ID (UUID)", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "event_type", + "in": "query", + "description": "Filter by event type (open, click)", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Tracking events", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TrackingEventResponse" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Email not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/emails/{id}/tracking/links": { + "get": { + "tags": [ + "Email Tracking" + ], + "summary": "Get tracked links for an email", + "operationId": "get_email_links", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Email ID (UUID)", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Tracked links", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TrackedLinkResponse" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Email not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/external-services": { + "get": { + "tags": [ + "External Services" + ], + "summary": "Get all external services", + "operationId": "list_services", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "Page number (1-indexed)", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + }, + "example": 1 + }, + { + "name": "page_size", + "in": "query", + "description": "Number of items per page (max 100)", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + }, + "example": 20 + }, + { + "name": "sort_by", + "in": "query", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "sort_order", + "in": "query", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + } + ], + "responses": { + "200": { + "description": "List of external services", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ExternalServiceInfo" + } + } + } + } + }, + "500": { + "description": "Internal server error" + } + } + }, + "post": { + "tags": [ + "External Services" + ], + "summary": "Create new external service", + "operationId": "create_service", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateExternalServiceRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Service created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExternalServiceInfo" + } + } + } + }, + "400": { + "description": "Invalid request" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/external-services/available-containers": { + "get": { + "tags": [ + "External Services" + ], + "summary": "List available Docker containers that can be imported as services", + "operationId": "list_available_containers", + "responses": { + "200": { + "description": "List of available containers", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AvailableContainerInfo" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/external-services/by-slug/{slug}": { + "get": { + "tags": [ + "External Services" + ], + "summary": "Get external service details by slug", + "operationId": "get_service_by_slug", + "parameters": [ + { + "name": "slug", + "in": "path", + "description": "External service slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "External service details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExternalServiceDetails" + } + } + } + }, + "404": { + "description": "Service not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/external-services/health-status-batch": { + "get": { + "tags": [ + "External Services" + ], + "summary": "Current health status for many services at once", + "description": "Powers the status dot on the Storage list page. Pass a comma-separated\nlist of service IDs via `?ids=1,2,3`. Omit to get every service.", + "operationId": "list_service_health_statuses", + "parameters": [ + { + "name": "ids", + "in": "query", + "description": "Comma-separated service IDs. Omit for all services.", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Batch of current health statuses", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceHealthStatusBatchResponse" + } + } + } + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/external-services/import": { + "post": { + "tags": [ + "External Services" + ], + "summary": "Import an existing Docker container as a managed external service", + "operationId": "import_external_service", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ImportExternalServiceRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Service imported successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExternalServiceInfo" + } + } + } + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/external-services/projects/{project_id}": { + "get": { + "tags": [ + "External Services" + ], + "summary": "List services linked to a project", + "operationId": "list_project_services", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "page", + "in": "query", + "description": "Page number (1-indexed)", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + }, + "example": 1 + }, + { + "name": "page_size", + "in": "query", + "description": "Number of items per page (max 100)", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + }, + "example": 20 + }, + { + "name": "sort_by", + "in": "query", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "sort_order", + "in": "query", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + } + ], + "responses": { + "200": { + "description": "List of services linked to project", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProjectServiceInfo" + } + } + } + } + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/external-services/projects/{project_id}/environment": { + "get": { + "tags": [ + "External Services" + ], + "summary": "Get all environment variables for all services linked to a project", + "operationId": "get_project_service_environment_variables", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Map of service IDs to their environment variables", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + } + }, + "propertyNames": { + "type": "integer", + "format": "int32" + } + } + } + } + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/external-services/providers/metadata": { + "get": { + "tags": [ + "External Services" + ], + "summary": "Get provider metadata (display names, icons, descriptions)", + "operationId": "get_providers_metadata", + "responses": { + "200": { + "description": "List of provider metadata", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProviderMetadata" + } + } + } + } + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/external-services/providers/metadata/{service_type}": { + "get": { + "tags": [ + "External Services" + ], + "summary": "Get metadata for a specific provider", + "operationId": "get_provider_metadata", + "parameters": [ + { + "name": "service_type", + "in": "path", + "description": "Service type (mongodb, postgres, redis, s3)", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Provider metadata", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProviderMetadata" + } + } + } + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/external-services/types": { + "get": { + "tags": [ + "External Services" + ], + "summary": "Get available service types", + "operationId": "get_service_types", + "responses": { + "200": { + "description": "List of available service types", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ServiceTypeRoute" + } + } + } + } + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/external-services/types/{service_type}/parameters": { + "get": { + "tags": [ + "External Services" + ], + "summary": "Get parameter schema for a specific service type", + "operationId": "get_service_type_parameters", + "parameters": [ + { + "name": "service_type", + "in": "path", + "description": "Service type", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Service type parameter schema" + }, + "404": { + "description": "Service type not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/external-services/{id}": { + "get": { + "tags": [ + "External Services" + ], + "summary": "Get external service details", + "operationId": "get_service", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "External service ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "External service details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExternalServiceDetails" + } + } + } + }, + "404": { + "description": "Service not found" + }, + "500": { + "description": "Internal server error" + } + } + }, + "put": { + "tags": [ + "External Services" + ], + "summary": "Update external service", + "operationId": "update_service", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "External service ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateExternalServiceRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Service updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExternalServiceInfo" + } + } + } + }, + "400": { + "description": "Invalid request" + }, + "404": { + "description": "Service not found" + }, + "409": { + "description": "A major upgrade is in progress for this service" + }, + "500": { + "description": "Internal server error" + } + } + }, + "delete": { + "tags": [ + "External Services" + ], + "summary": "Delete external service", + "operationId": "delete_service", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "External service ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Service deleted successfully" + }, + "400": { + "description": "Cannot delete: service is still linked to projects" + }, + "404": { + "description": "Service not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/external-services/{id}/cluster-health": { + "get": { + "tags": [ + "External Services" + ], + "summary": "Per-member health for a Postgres HA cluster.", + "description": "Reads pg_auto_failover's `pgautofailover.node` table from the cluster's\nmonitor (TLS, autoctl_node) and joins each member with its\n`pg_stat_replication` row from the current primary. Returns one row per\ndata member with role/state, sync state, and replay lag.\n\nReturns `200` with `monitor_error` set when the monitor is briefly\nunreachable (UI surfaces it as a banner above the table); the table\nitself is empty in that case. Returns `400` for non-cluster services.", + "operationId": "get_cluster_health", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "External service ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Per-member cluster health report", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ClusterHealthReportResponse" + } + } + } + }, + "400": { + "description": "Service is not a cluster" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Service not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/external-services/{id}/health-check": { + "post": { + "tags": [ + "External Services" + ], + "summary": "Run a health check for one service right now", + "description": "Triggers the same engine-specific probe as the background monitor, writes\na history row, updates the denormalized fields on `external_services`, and\nfires alerts on the Nth consecutive failure (so consecutive-failure state\nstays honest). Returns the fresh snapshot the UI can display immediately.", + "operationId": "trigger_service_health_check", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "External service ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Fresh health snapshot after probing", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceHealthResponse" + } + } + } + }, + "404": { + "description": "Service not found" + }, + "500": { + "description": "Internal server error" + }, + "503": { + "description": "Health monitor not running on this node" + } + } + } + }, + "/external-services/{id}/health-status": { + "get": { + "tags": [ + "External Services" + ], + "summary": "Persisted health status for an external service", + "description": "Returns the latest health probe result recorded by\n`ExternalServiceHealthMonitor`, plus recent check history for sparklines\nand a 24-hour uptime percentage. Safe to poll from the UI every 30s.", + "operationId": "get_service_health_status", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "External service ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "limit", + "in": "query", + "description": "Max number of recent checks (default 50, max 200)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "Current health + recent history", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceHealthResponse" + } + } + } + }, + "404": { + "description": "Service not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/external-services/{id}/members": { + "post": { + "tags": [ + "External Services" + ], + "summary": "Begin adding a single new member to a running cluster.", + "description": "Currently only `replica` members can be added at runtime. The\nresponse is **202 Accepted** as soon as the validation passes and\nthe placeholder `service_members` row is inserted. The actual\ncontainer provisioning + DNS registration runs in the background;\npoll `GET /external-services/{id}/members/{member_id}` to watch\n`provisioning_step` advance through the phases.", + "operationId": "add_cluster_member", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "External service ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddClusterMemberRequest" + } + } + }, + "required": true + }, + "responses": { + "202": { + "description": "Cluster member provisioning started", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceMemberInfo" + } + } + } + }, + "400": { + "description": "Validation failed (wrong topology, status, or role)" + }, + "404": { + "description": "Service not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/external-services/{id}/members/{member_id}": { + "get": { + "tags": [ + "External Services" + ], + "summary": "Get a single cluster member's current state.", + "description": "Used by the add-member page to poll the row every second while the\nbackground provisioning task walks through its phases. The\n`provisioning_step` field advances through `inserting_row` \u2192\n`provisioning_container` \u2192 `registering_dns` \u2192 `done` (or `failed`\nwith `provisioning_error` set).", + "operationId": "get_cluster_member", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "External service ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "member_id", + "in": "path", + "description": "Cluster member ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Cluster member details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceMemberInfo" + } + } + } + }, + "404": { + "description": "Service or member not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "External Services" + ], + "summary": "Remove a single member from a running cluster.", + "description": "Refuses to remove the monitor (singleton), the current primary\n(failover first), or any member if the cluster would drop below the\n2-data-member quorum required for HA. Stops + removes the container,\ndeletes the row, and drops the Tier-2 DNS record.", + "operationId": "remove_cluster_member", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "External service ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "member_id", + "in": "path", + "description": "Cluster member ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Cluster member removed" + }, + "400": { + "description": "Validation failed (monitor, primary, or quorum violation)" + }, + "404": { + "description": "Service or member not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/external-services/{id}/members/{member_id}/promote": { + "post": { + "tags": [ + "External Services" + ], + "summary": "Promote a replica to primary by triggering a pg_auto_failover\nfailover. The monitor demotes the current primary and the chosen\nreplica transitions to primary; the role reconciler then refreshes\nthe role-aliased VIPs (\u226430s).", + "operationId": "promote_cluster_member", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "External service ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "member_id", + "in": "path", + "description": "Cluster member ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "202": { + "description": "Promotion initiated" + }, + "400": { + "description": "Validation failed (monitor, already primary, not running, etc.)" + }, + "404": { + "description": "Service or member not found" + }, + "500": { + "description": "pg_autoctl perform promotion failed" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/external-services/{id}/metrics": { + "get": { + "tags": [ + "Metrics" + ], + "summary": "Fetch a time-series range for a single metric on an external service.", + "description": "Pass `percentile` to compute a histogram quantile instead of a plain\ngauge/counter average.", + "operationId": "ExternalServiceMetricsGetRange", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "External service ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "metric", + "in": "query", + "description": "Metric name, e.g. `\"pg.connections_active\"`.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "range", + "in": "query", + "description": "Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`.", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "percentile", + "in": "query", + "description": "Optional histogram percentile (0\u2013100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile.", + "required": false, + "schema": { + "type": [ + "number", + "null" + ], + "format": "double" + } + } + ], + "responses": { + "200": { + "description": "Metric time series data points", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MetricDataPoint" + } + } + } + } + }, + "400": { + "description": "Invalid query parameters" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + }, + "503": { + "description": "Metrics store not available" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/external-services/{id}/metrics/alert-rules": { + "get": { + "tags": [ + "Metrics" + ], + "summary": "List all monitoring alert rules for an external service.", + "operationId": "ExternalServiceMetricsGetAlertRules", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "External service ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "List of alert rules", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ServiceAlertRuleResponse" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Metrics" + ], + "summary": "Create a monitoring alert rule for an external service.", + "description": "If metric collection is enabled and the service engine has default rules,\nseeding is idempotent (ON CONFLICT DO NOTHING).", + "operationId": "ExternalServiceMetricsCreateAlertRule", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "External service ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceCreateAlertRuleRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Alert rule created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceAlertRuleResponse" + } + } + } + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/external-services/{id}/metrics/alert-rules/{rule_id}": { + "put": { + "tags": [ + "Metrics" + ], + "summary": "Update an existing monitoring alert rule for an external service.", + "operationId": "ExternalServiceMetricsUpdateAlertRule", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "External service ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "rule_id", + "in": "path", + "description": "Alert rule ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceUpdateAlertRuleRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Updated alert rule", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceAlertRuleResponse" + } + } + } + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Alert rule not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "Metrics" + ], + "summary": "Delete a monitoring alert rule for an external service.", + "operationId": "ExternalServiceMetricsDeleteAlertRule", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "External service ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "rule_id", + "in": "path", + "description": "Alert rule ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Alert rule deleted" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Alert rule not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/external-services/{id}/metrics/by-database": { + "get": { + "tags": [ + "Metrics" + ], + "summary": "Return the latest per-database metric values for a Postgres service.", + "description": "Groups `pg_stat_database` / size metrics by `datname` so the UI can show a\nbreakdown table (each database with its own size, cache-hit ratio, etc.)\nrather than collapsing every database into one value.", + "operationId": "ExternalServiceMetricsByDatabase", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "External service ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Per-database metric breakdown", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseMetricsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + }, + "503": { + "description": "Metrics not available" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/external-services/{id}/metrics/enable": { + "patch": { + "tags": [ + "Metrics" + ], + "summary": "Enable or disable metric collection for an external service.", + "description": "When `enabled=true`, seeds the default alert rules for the service's engine\nvia [`temps_monitoring::seed_default_rules`] (idempotent).", + "operationId": "ExternalServiceMetricsToggle", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "External service ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ToggleServiceMetricsRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Metrics toggle applied" + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Service not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/external-services/{id}/metrics/latest": { + "get": { + "tags": [ + "Metrics" + ], + "summary": "Fetch the most-recent value for every tracked metric on an external service.", + "operationId": "ExternalServiceMetricsGetLatest", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "External service ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Map of metric name to latest value", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": { + "type": "number", + "format": "double" + }, + "propertyNames": { + "type": "string" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + }, + "503": { + "description": "Metrics store not available" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/external-services/{id}/metrics/status": { + "get": { + "tags": [ + "Metrics" + ], + "summary": "Return the freshness status (last-received timestamp) for a service.", + "description": "Cheap O(1) lookup against `service_metrics_status` \u2014 used by the UI to show\n\"last received at \u2026\" without scanning the metrics hypertable.", + "operationId": "ExternalServiceMetricsStatus", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "External service ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Metrics freshness status", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MetricsStatusResponse" + } + } + } + }, + "503": { + "description": "Metrics not available" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/external-services/{id}/parameters/{param_name}": { + "get": { + "tags": [ + "External Services" + ], + "summary": "Reveal one sensitive service parameter. Service detail responses never\ncontain plaintext values; every successful reveal is recorded separately.", + "operationId": "reveal_service_parameter", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "External service ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "param_name", + "in": "path", + "description": "Sensitive parameter name", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Sensitive parameter value", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SensitiveValueResponse" + } + } + } + }, + "400": { + "description": "Parameter is not sensitive" + }, + "403": { + "description": "Caller cannot access a project linked to this service" + }, + "404": { + "description": "Service or parameter not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/external-services/{id}/preview-environment-masked": { + "get": { + "tags": [ + "External Services" + ], + "summary": "Get environment variables preview with masked sensitive values", + "operationId": "get_service_preview_environment_variables_masked", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "External service ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Preview of environment variables with sensitive values masked as ***", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + } + } + } + } + }, + "404": { + "description": "Service not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/external-services/{id}/preview-environment-names": { + "get": { + "tags": [ + "External Services" + ], + "summary": "Get environment variable names preview (safe - no sensitive values)", + "operationId": "get_service_preview_environment_variable_names", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "External service ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "List of environment variable names that would be provided", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "404": { + "description": "Service not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/external-services/{id}/projects": { + "get": { + "tags": [ + "External Services" + ], + "summary": "List projects linked to service", + "operationId": "list_service_projects", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "External service ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "page", + "in": "query", + "description": "Page number (1-indexed)", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + }, + "example": 1 + }, + { + "name": "page_size", + "in": "query", + "description": "Number of items per page (max 100)", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + }, + "example": 20 + }, + { + "name": "sort_by", + "in": "query", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "sort_order", + "in": "query", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + } + ], + "responses": { + "200": { + "description": "List of linked projects", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProjectServiceInfo" + } + } + } + } + }, + "404": { + "description": "Service not found" + }, + "500": { + "description": "Internal server error" + } + } + }, + "post": { + "tags": [ + "External Services" + ], + "summary": "Link service to project", + "operationId": "link_service_to_project", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "External service ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LinkServiceRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Service linked to project successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectServiceInfo" + } + } + } + }, + "404": { + "description": "Service or project not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/external-services/{id}/projects/{project_id}": { + "delete": { + "tags": [ + "External Services" + ], + "summary": "Unlink service from project", + "operationId": "unlink_service_from_project", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "External service ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Service unlinked from project successfully" + }, + "404": { + "description": "Service link not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/external-services/{id}/projects/{project_id}/environment": { + "get": { + "tags": [ + "External Services" + ], + "summary": "Get all environment variables for a service-project pair", + "operationId": "get_service_environment_variables", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "External service ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "List of environment variables", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EnvironmentVariableInfo" + } + } + } + } + }, + "404": { + "description": "Service or project not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/external-services/{id}/projects/{project_id}/environment/{var_name}": { + "get": { + "tags": [ + "External Services" + ], + "summary": "Get specific environment variable for a service-project pair", + "operationId": "get_service_environment_variable", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "External service ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "var_name", + "in": "path", + "description": "Environment variable name", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Environment variable value", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnvironmentVariableInfo" + } + } + } + }, + "403": { + "description": "Plaintext secret access is not permitted" + }, + "404": { + "description": "Service, project, or variable not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/external-services/{id}/resources": { + "patch": { + "tags": [ + "External Services" + ], + "summary": "Update a service's resource limits (memory, CPU caps).", + "description": "Persists the new caps to the encrypted config AND live-applies them\nvia Docker's update API. Memory and CPU can be hot-changed without a\nrestart on running containers; stopped containers also accept the\nupdate and pick up the new caps on next start.\n\nPass `null` (or omit) any field to leave it unlimited. A request where\nevery field is `null` removes any existing limits.\n\nThe response includes a per-container `applied[]` list so the caller\ncan tell which members got the update and which were skipped (e.g.,\ncontainer not yet created, or `docker update` rejected because the\nnew memory cap is below current usage).", + "operationId": "update_service_resources", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "External service ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceResourceLimits" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Updated resource limits", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceLimitsUpdateResponse" + } + } + } + }, + "400": { + "description": "Invalid resource limits" + }, + "404": { + "description": "Service not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/external-services/{id}/restore": { + "post": { + "tags": [ + "Restore" + ], + "operationId": "start_restore", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "External service id (source for the restore)", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StartRestoreRequest" + } + } + }, + "required": true + }, + "responses": { + "202": { + "description": "Restore run started", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RestoreRunView" + } + } + } + }, + "400": { + "description": "Validation error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Backup or service not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/external-services/{id}/restore-capabilities": { + "get": { + "tags": [ + "Restore" + ], + "operationId": "get_restore_capabilities", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "External service id", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Capabilities declared by the service", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RestoreCapabilitiesResponse" + } + } + } + }, + "404": { + "description": "Service not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/external-services/{id}/restore-plan": { + "post": { + "tags": [ + "Restore" + ], + "operationId": "plan_restore", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Target service id", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StartRestoreRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Preview of what the restore will do", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RestorePlan" + } + } + } + }, + "400": { + "description": "Validation error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Backup or service not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/external-services/{id}/restore-runs": { + "get": { + "tags": [ + "Restore" + ], + "operationId": "list_restore_runs_for_service", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "External service id", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Recent restore runs for the service", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RestoreRunView" + } + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/external-services/{id}/retry": { + "post": { + "tags": [ + "External Services" + ], + "summary": "Retry a failed cluster service initialization.", + "description": "Cleans up any leftover containers from the previous attempt and\nre-runs cluster initialization with the provided member specifications.", + "operationId": "retry_cluster", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RetryClusterRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Cluster retry initiated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExternalServiceInfo" + } + } + } + }, + "400": { + "description": "Service is not a failed cluster" + }, + "404": { + "description": "Service not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/external-services/{id}/runtime": { + "get": { + "tags": [ + "External Services" + ], + "summary": "Inspect a service's container(s): status, restart count, OOM-killed flag,\nexit code, and the cgroup limits actually applied.", + "operationId": "get_service_runtime", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "External service ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Container runtime snapshot", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceRuntimeReport" + } + } + } + }, + "404": { + "description": "Service not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/external-services/{id}/start": { + "post": { + "tags": [ + "External Services" + ], + "summary": "Start an external service", + "operationId": "start_service", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "External service ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Service started successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExternalServiceInfo" + } + } + } + }, + "404": { + "description": "Service not found" + }, + "409": { + "description": "A Postgres major upgrade is in progress for this service" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/external-services/{id}/stats": { + "get": { + "tags": [ + "External Services" + ], + "summary": "Sample current CPU/memory usage from each of a service's containers.\nOne-shot sample, no streaming. Cheap to call (single Docker round-trip\nper member) so the UI can poll on a 5\u201310s interval.", + "operationId": "get_service_stats", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "External service ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Container stats snapshot", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceStatsReport" + } + } + } + }, + "404": { + "description": "Service not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/external-services/{id}/stop": { + "post": { + "tags": [ + "External Services" + ], + "summary": "Stop an external service", + "operationId": "stop_service", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "External service ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Service stopped successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExternalServiceInfo" + } + } + } + }, + "404": { + "description": "Service not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/external-services/{id}/upgrade": { + "post": { + "tags": [ + "External Services" + ], + "summary": "Upgrade external service to new Docker image with data migration\nThis endpoint uses service-specific upgrade procedures (e.g., pg_upgrade for PostgreSQL)", + "operationId": "upgrade_service", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "External service ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpgradeExternalServiceRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Service upgraded successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExternalServiceInfo" + } + } + } + }, + "400": { + "description": "Invalid request or upgrade not supported" + }, + "404": { + "description": "Service not found" + }, + "409": { + "description": "A major upgrade is already in progress for this service" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/external-services/{id}/wal-health": { + "get": { + "tags": [ + "External Services" + ], + "summary": "Postgres WAL & archive health snapshot", + "description": "Returns the latest WAL/archive health snapshot recorded by the background\nhealth monitor for a Postgres external service. Powers the warning banner\non the service detail page when the disk is filling up due to stale\nreplication slots, archive backlog, or misconfigured `archive_command`.\n\nReturns 404 when no snapshot exists yet (probe hasn't run, or the service\nisn't Postgres).", + "operationId": "getPostgresWalHealth", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "External service ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Latest WAL health snapshot", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PostgresWalHealth" + } + } + } + }, + "404": { + "description": "Service not found, or no WAL snapshot available" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/external-services/{service_id}/pg-stat-statements/enable": { + "post": { + "tags": [ + "External Services" + ], + "summary": "Enable `pg_stat_statements` on a standalone Postgres service.", + "description": "Stops the container and restarts it so that the\n`shared_preload_libraries=pg_stat_statements` CMD flag (baked into every\nnew standalone Postgres container) takes effect. The named data volume is\nreused unchanged \u2014 no data is lost.\n\n**Clustered (HA) services are rejected** with 422 \u2014 a blind single-container\nrestart bypasses controlled failover. For clustered services the response\nbody describes the manual rolling-restart steps.\n\nConfirmation is the caller's responsibility (UI dialog / CLI `--yes` flag)\nbefore invoking this endpoint.", + "operationId": "ExternalServiceEnablePgStatStatements", + "parameters": [ + { + "name": "service_id", + "in": "path", + "description": "ID of the provisioned standalone Postgres service", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Container restarted; pg_stat_statements now active", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnablePgStatStatementsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions (requires external_services:write)" + }, + "404": { + "description": "Service not found" + }, + "422": { + "description": "Service is not standalone Postgres (cluster or wrong type)" + }, + "500": { + "description": "Restart failed" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/external-services/{service_id}/pg-stat-statements/reset": { + "post": { + "tags": [ + "External Services" + ], + "summary": "Reset all statistics accumulated by `pg_stat_statements` for a Postgres\nservice. This affects every user, database, and normalized query tracked by\nthe target Postgres instance and cannot be undone.", + "operationId": "ExternalServiceResetPgStatStatements", + "parameters": [ + { + "name": "service_id", + "in": "path", + "description": "ID of the provisioned Postgres service", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "description": "Explicit confirmation of the global, irreversible reset", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResetPgStatStatementsRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "All accumulated pg_stat_statements statistics cleared", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResetPgStatStatementsResponse" + } + } + } + }, + "400": { + "description": "Missing or invalid reset confirmation" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions (requires external_services:write)" + }, + "404": { + "description": "Service not found" + }, + "422": { + "description": "Service is not Postgres" + }, + "502": { + "description": "Target Postgres rejected or failed the reset operation" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/external-services/{service_id}/pg-stat-statements/slow-queries": { + "get": { + "tags": [ + "External Services" + ], + "operationId": "get_slow_queries", + "parameters": [ + { + "name": "service_id", + "in": "path", + "description": "ID of the provisioned Postgres service", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "page", + "in": "query", + "description": "Page number (1-based). Defaults to 1.", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "minimum": 0 + } + }, + { + "name": "page_size", + "in": "query", + "description": "Number of rows per page (1\u2013100). Defaults to 20.", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "minimum": 0 + } + }, + { + "name": "sort_by", + "in": "query", + "description": "Column to sort by: one of `calls`, `total_exec_time_ms`,\n`mean_exec_time_ms`, `rows`, `cache_hit_ratio`. Defaults to\n`mean_exec_time_ms`. Applied server-side so ordering stays\nconsistent across pages.", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "sort_order", + "in": "query", + "description": "Sort direction: `asc` or `desc`. Defaults to `desc`.", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + } + ], + "responses": { + "200": { + "description": "Paginated slow queries from pg_stat_statements", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SlowQueriesResponse" + } + } + } + }, + "400": { + "description": "Invalid pagination or sort parameters" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions (requires external_services:read)" + }, + "404": { + "description": "Service not found" + }, + "422": { + "description": "Service is not a Postgres service" + }, + "503": { + "description": "pg_stat_statements extension not available (container restart required)" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/external-services/{service_id}/query/ai-data-access": { + "get": { + "tags": [ + "External Services - Query" + ], + "summary": "Report whether the AI assistant may read row data from this service.", + "description": "Always answers (rather than 404-ing when disabled) so the console can render\nthe capability with an \"off \u2014 here's how to turn it on\" state instead of\nhiding it, and so the agent can tell \"not set up\" apart from \"not supported\".", + "operationId": "get_ai_data_access", + "parameters": [ + { + "name": "service_id", + "in": "path", + "description": "External service id", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Current AI data access setting", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiDataAccessResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Service not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "patch": { + "tags": [ + "External Services - Query" + ], + "summary": "Enable or disable AI assistant access to this service's row data.", + "description": "Off by default. Row contents can include password hashes, API tokens and\npersonal data, and enabling this sends them to the configured AI provider \u2014\nso it is a deliberate, audited, per-service decision by the operator.", + "operationId": "set_ai_data_access", + "parameters": [ + { + "name": "service_id", + "in": "path", + "description": "External service id", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ToggleAiDataAccessRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Setting applied", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiDataAccessResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Service not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/external-services/{service_id}/query/containers": { + "get": { + "tags": [ + "External Services - Query" + ], + "summary": "List containers at the root level (databases, keyspaces, etc.)", + "operationId": "list_root_containers", + "parameters": [ + { + "name": "service_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "List of root containers", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ContainerResponse" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Service not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/external-services/{service_id}/query/containers/{path}": { + "get": { + "tags": [ + "External Services - Query" + ], + "summary": "List containers at a specific path\nPath segments are separated by forward slashes\nExample: /external-services/1/query/containers/mydb lists schemas in database \"mydb\"", + "operationId": "list_containers_at_path", + "parameters": [ + { + "name": "service_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "path", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "List of containers", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ContainerResponse" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Service or container not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/external-services/{service_id}/query/containers/{path}/entities": { + "get": { + "tags": [ + "External Services - Query" + ], + "summary": "List entities (tables, collections, etc.) in a container\nExample: /external-services/1/query/containers/mydb/public/entities lists tables in the public schema", + "operationId": "list_entities", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Maximum number of entities to return (default: 100, max: 1000)", + "required": false, + "schema": { + "type": "integer", + "minimum": 0 + } + }, + { + "name": "token", + "in": "query", + "description": "Continuation token for pagination", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "service_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "path", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Paginated list of entities", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PaginatedEntitiesResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Service or container not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/external-services/{service_id}/query/containers/{path}/entities/{entity}": { + "get": { + "tags": [ + "External Services - Query" + ], + "summary": "Get detailed information about an entity (table schema)", + "operationId": "get_entity_info", + "parameters": [ + { + "name": "service_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "path", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "entity", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Entity details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EntityInfoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Service, container, or entity not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/external-services/{service_id}/query/containers/{path}/entities/{entity}/data": { + "get": { + "tags": [ + "External Services - Query" + ], + "summary": "Read rows from an entity (read-only `GET`; see [`query_data`] for the\n`POST` form used by the console).", + "description": "Gated for AI callers by the service's `ai_data_access` opt-in \u2014 see\n[`temps_core::ai_tool_call::AiToolCall`].", + "operationId": "read_entity_rows", + "parameters": [ + { + "name": "service_id", + "in": "path", + "description": "External service id", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "path", + "in": "path", + "description": "Container path, slash-separated (e.g. `mydb/public`)", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "entity", + "in": "path", + "description": "Table, collection, key or object name", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "filter", + "in": "query", + "description": "JSON-encoded backend-specific filter", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "description": "Maximum rows to return", + "required": false, + "schema": { + "type": "integer", + "minimum": 0 + } + }, + { + "name": "offset", + "in": "query", + "description": "Rows to skip", + "required": false, + "schema": { + "type": "integer", + "minimum": 0 + } + }, + { + "name": "sort_by", + "in": "query", + "description": "Field to sort by", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "sort_order", + "in": "query", + "description": "asc or desc", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Query results", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QueryDataResponse" + } + } + } + }, + "400": { + "description": "Invalid query or filter" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions, or AI data access not enabled for this service" + }, + "404": { + "description": "Service, container, or entity not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "External Services - Query" + ], + "summary": "Query data from an entity with optional filters, pagination, and sorting", + "operationId": "query_data", + "parameters": [ + { + "name": "service_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "path", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "entity", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QueryDataRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Query results", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QueryDataResponse" + } + } + } + }, + "400": { + "description": "Invalid query" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Service, container, or entity not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/external-services/{service_id}/query/containers/{path}/entities/{entity}/download": { + "get": { + "tags": [ + "External Services - Query" + ], + "summary": "Download an object (S3 only) as a streaming response", + "operationId": "download_object", + "parameters": [ + { + "name": "service_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "path", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "entity", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Object data stream", + "content": { + "application/octet-stream": {} + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Object not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/external-services/{service_id}/query/containers/{path}/info": { + "get": { + "tags": [ + "External Services - Query" + ], + "summary": "Get information about a specific container", + "operationId": "get_query_container_info", + "parameters": [ + { + "name": "service_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "path", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Container information", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContainerResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Service or container not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/external-services/{service_id}/query/explorer-support": { + "get": { + "tags": [ + "External Services - Query" + ], + "summary": "Check if a service supports query explorer functionality", + "operationId": "check_explorer_support", + "parameters": [ + { + "name": "service_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Explorer support information", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExplorerSupportResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Service not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/external-services/{service_id}/upgrades": { + "get": { + "tags": [ + "Postgres Upgrades" + ], + "summary": "List recent upgrades for a single service (newest first, page size 50).", + "operationId": "list_pg_upgrades", + "parameters": [ + { + "name": "service_id", + "in": "path", + "description": "External service id", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Recent upgrades", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PgUpgradeResponse" + } + } + } + } + }, + "500": { + "description": "Internal error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Postgres Upgrades" + ], + "summary": "Start a new PostgreSQL major-version upgrade for a service.", + "operationId": "start_pg_upgrade", + "parameters": [ + { + "name": "service_id", + "in": "path", + "description": "External service id", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StartPgUpgradeRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Upgrade started", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PgUpgradeResponse" + } + } + } + }, + "400": { + "description": "Invalid request" + }, + "409": { + "description": "An upgrade is already running for this service" + }, + "412": { + "description": "No default S3 source configured" + }, + "500": { + "description": "Internal error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/external-services/{service_id}/upgrades/{id}": { + "get": { + "tags": [ + "Postgres Upgrades" + ], + "summary": "Get a single upgrade by id, scoped to a service.", + "operationId": "get_pg_upgrade", + "parameters": [ + { + "name": "service_id", + "in": "path", + "description": "External service id", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "id", + "in": "path", + "description": "Upgrade id", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Upgrade", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PgUpgradeResponse" + } + } + } + }, + "404": { + "description": "Not found" + }, + "500": { + "description": "Internal error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/external-services/{service_id}/upgrades/{id}/cancel": { + "post": { + "tags": [ + "Postgres Upgrades" + ], + "summary": "Cancel an in-flight upgrade. The orchestrator stops at its next phase\nboundary; already-terminal upgrades return 409.", + "operationId": "cancel_pg_upgrade", + "parameters": [ + { + "name": "service_id", + "in": "path", + "description": "External service id", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "id", + "in": "path", + "description": "Upgrade id", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Cancellation requested", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PgUpgradeResponse" + } + } + } + }, + "404": { + "description": "Not found" + }, + "409": { + "description": "Upgrade already terminal" + }, + "500": { + "description": "Internal error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/external-services/{service_id}/upgrades/{id}/logs": { + "get": { + "tags": [ + "Postgres Upgrades" + ], + "summary": "Get the accumulated JSONL log content for an upgrade (for dashboard display).", + "operationId": "get_pg_upgrade_logs", + "parameters": [ + { + "name": "service_id", + "in": "path", + "description": "External service id", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "id", + "in": "path", + "description": "Upgrade id", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Log content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PgUpgradeLogResponse" + } + } + } + }, + "404": { + "description": "Not found" + }, + "500": { + "description": "Internal error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/external-services/{service_id}/upgrades/{id}/retry": { + "post": { + "tags": [ + "Postgres Upgrades" + ], + "summary": "Retry a failed upgrade. The phase is preserved, so the state machine\nresumes from where it failed.", + "operationId": "retry_pg_upgrade", + "parameters": [ + { + "name": "service_id", + "in": "path", + "description": "External service id", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "id", + "in": "path", + "description": "Upgrade id", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Retry scheduled", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PgUpgradeResponse" + } + } + } + }, + "400": { + "description": "Upgrade is not in a retriable state" + }, + "404": { + "description": "Not found" + }, + "500": { + "description": "Internal error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/external-services/{service_id}/upgrades/{id}/rollback": { + "post": { + "tags": [ + "Postgres Upgrades" + ], + "summary": "Roll a completed upgrade back to its pre-upgrade PGDATA volume and old image.\nOnly valid while the rollback retention window is still open (see\n`ROLLBACK_RETENTION_DAYS`) and the rollback volume has not been swept.", + "operationId": "rollback_pg_upgrade", + "parameters": [ + { + "name": "service_id", + "in": "path", + "description": "External service id", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "id", + "in": "path", + "description": "Upgrade id", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Rollback complete", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PgUpgradeResponse" + } + } + } + }, + "404": { + "description": "Not found" + }, + "409": { + "description": "Upgrade is not in a rollbackable state (not completed, volume swept, or retention expired)" + }, + "500": { + "description": "Internal error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/files/{file_path}": { + "get": { + "tags": [ + "Files" + ], + "operationId": "get_file", + "parameters": [ + { + "name": "file_path", + "in": "path", + "description": "Relative path to the file from static directory", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "File content retrieved successfully", + "content": { + "application/octet-stream": {} + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Access denied - path outside static directory or insufficient permissions" + }, + "404": { + "description": "File not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/flags/exposure": { + "post": { + "tags": [ + "Feature Flags" + ], + "summary": "Record which flags a running app actually evaluated.", + "description": "This is what makes `last_evaluated_at` mean something. The snapshot\nendpoint hands the SDK every flag in the environment and evaluation then\nhappens locally, so the control plane cannot otherwise tell a flag that is\nreferenced by live code from one nothing has called in a year. Stamping on\nsnapshot fetch would mark every flag as freshly used and defeat the point.\n\nScope comes from the deployment token, never the body. The endpoint writes\nonly `last_evaluated_at` \u2014 never a flag's value \u2014 so \"a deployment token\ncannot change what a flag serves\" still holds despite this being a write.", + "operationId": "record_flag_exposure", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RecordExposureRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Exposure recorded", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RecordExposureResponse" + } + } + } + }, + "400": { + "description": "Deployment token required" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/flags/snapshot": { + "get": { + "tags": [ + "Feature Flags" + ], + "summary": "Every flag for the caller's environment, collapsed to what the evaluator\nneeds.", + "description": "Scope comes from the deployment token, never from the URL: a container's\nbaked-in `TEMPS_API_TOKEN` identifies exactly one project (and usually one\nenvironment), so a compromised app cannot read another tenant's flags by\nchanging a path parameter.\n\nSupports `If-None-Match`, so the SDK's background poll is a 304 in the\ncommon case.", + "operationId": "get_flag_snapshot", + "parameters": [ + { + "name": "environment_id", + "in": "query", + "description": "Required only when the calling token is project-wide rather than scoped\nto a single environment.", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Snapshot for the environment", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FlagSnapshotResponse" + } + } + } + }, + "304": { + "description": "Snapshot unchanged" + }, + "400": { + "description": "Environment could not be determined" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/geo/{ip}": { + "get": { + "tags": [ + "geo" + ], + "summary": "Get geolocation information for an IP address", + "operationId": "get_ip_geolocation", + "parameters": [ + { + "name": "ip", + "in": "path", + "description": "IP address to geolocate (IPv4 or IPv6)", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Geolocation information retrieved", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GeoLocationResponse" + } + } + } + }, + "400": { + "description": "Invalid IP address", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Authentication required", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "IP address not found in database", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/git-connections": { + "get": { + "tags": [ + "Git Providers" + ], + "summary": "List user's git provider connections", + "operationId": "list_connections", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "Page number for pagination (default: 1)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "per_page", + "in": "query", + "description": "Number of items per page (default: 30, max: 100)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "sort", + "in": "query", + "description": "Sort field (created_at, updated_at, account_name)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "direction", + "in": "query", + "description": "Sort direction (asc, desc), default: desc", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "List of connections", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConnectionListResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/git-connections/{connection_id}": { + "delete": { + "tags": [ + "Git Providers" + ], + "summary": "Permanently delete a git provider connection", + "operationId": "delete_connection", + "parameters": [ + { + "name": "connection_id", + "in": "path", + "description": "Connection ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Connection deleted successfully" + }, + "400": { + "description": "Connection is in use by projects and cannot be deleted" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Connection not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/git-connections/{connection_id}/activate": { + "post": { + "tags": [ + "Git Providers" + ], + "summary": "Activate a git provider connection", + "operationId": "activate_connection", + "parameters": [ + { + "name": "connection_id", + "in": "path", + "description": "Connection ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Connection activated successfully" + }, + "400": { + "description": "Provider is deactivated and connection cannot be activated" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Connection not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/git-connections/{connection_id}/deactivate": { + "post": { + "tags": [ + "Git Providers" + ], + "summary": "Deactivate a git provider connection", + "operationId": "deactivate_connection", + "parameters": [ + { + "name": "connection_id", + "in": "path", + "description": "Connection ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Connection deactivated successfully" + }, + "400": { + "description": "Connection is in use by projects and cannot be deactivated" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Connection not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/git-connections/{connection_id}/health-check": { + "post": { + "tags": [ + "Git Provider Connections" + ], + "summary": "Run an on-demand health check for a git connection.", + "description": "Probes the upstream (GitHub App, PAT, or OAuth token), persists the result,\nand fires admin notifications on status transitions. Returns the updated\nconnection.", + "operationId": "run_connection_health_check", + "parameters": [ + { + "name": "connection_id", + "in": "path", + "description": "Connection ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Health check completed", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConnectionResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Connection not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/git-connections/{connection_id}/repositories": { + "get": { + "tags": [ + "Git Providers" + ], + "summary": "List repositories for a specific connection", + "description": "Fetches repositories from the connected git provider with support for pagination, search, and filtering.\nThis endpoint calls the provider's API directly to get the most up-to-date repository list.", + "operationId": "list_repositories_by_connection", + "parameters": [ + { + "name": "connection_id", + "in": "path", + "description": "Connection ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "page", + "in": "query", + "description": "Page number for pagination", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "per_page", + "in": "query", + "description": "Number of items per page (max 100)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "sort", + "in": "query", + "description": "Sort field (name, created_at, updated_at, stars, etc.)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "direction", + "in": "query", + "description": "Sort direction (asc, desc)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "search", + "in": "query", + "description": "Search term to filter repositories", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "owner", + "in": "query", + "description": "Filter by repository owner", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "language", + "in": "query", + "description": "Filter by programming language", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "private", + "in": "query", + "description": "Filter by private status (true/false)", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "List of repositories", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RepositoryListResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Connection not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/git-connections/{connection_id}/sync": { + "post": { + "tags": [ + "Git Providers" + ], + "summary": "Start a repository sync for a connection", + "description": "Kicks off a background sync of the connection's repositories from the\nprovider. Returns `202 Accepted` immediately \u2014 the caller should poll\nthe connection endpoint for `syncing` / `synced_repository_count`\nupdates rather than waiting on this response. The sync is guarded by\na hard deadline and always releases the `syncing` flag on exit, so a\nclient that disconnects mid-sync will not leave the connection stuck.", + "operationId": "sync_repositories", + "parameters": [ + { + "name": "connection_id", + "in": "path", + "description": "Connection ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "202": { + "description": "Repository sync started in background", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RepositorySyncStartedResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Connection not found" + }, + "409": { + "description": "Sync already in progress" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/git-connections/{connection_id}/update-token": { + "post": { + "tags": [ + "Git Provider Connections" + ], + "summary": "Update access token for a connection (when tokens expire or are rotated)", + "operationId": "update_connection_token", + "parameters": [ + { + "name": "connection_id", + "in": "path", + "description": "Connection ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateTokenRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Token updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateTokenResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Connection not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/git-connections/{connection_id}/validate": { + "get": { + "tags": [ + "Git Provider Connections" + ], + "summary": "Validate a connection by testing the access token", + "operationId": "validate_connection", + "parameters": [ + { + "name": "connection_id", + "in": "path", + "description": "Connection ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Connection validation result", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Connection not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/git-providers": { + "get": { + "tags": [ + "Git Providers" + ], + "summary": "List all git providers", + "operationId": "list_git_providers", + "responses": { + "200": { + "description": "List of providers", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProviderResponse" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Git Providers" + ], + "summary": "Create a new git provider configuration", + "operationId": "create_git_provider", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateProviderRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Provider created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProviderResponse" + } + } + } + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/git-providers/bitbucket": { + "post": { + "tags": [ + "Git Providers" + ], + "summary": "Create a Bitbucket Cloud provider with access token or app password authentication", + "operationId": "create_bitbucket_provider", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateBitbucketRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Bitbucket provider created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProviderResponse" + } + } + } + }, + "400": { + "description": "Bad request \u2014 missing or invalid auth fields" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/git-providers/generic": { + "post": { + "tags": [ + "Git Providers" + ], + "summary": "Create a Generic git provider for self-hosted or arbitrary HTTPS git hosts.\nSupports public repositories (no token) and private repositories (token-based).", + "operationId": "create_generic_provider", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateGenericRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Generic git provider created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProviderResponse" + } + } + } + }, + "400": { + "description": "Bad request \u2014 invalid clone URL or missing fields" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/git-providers/gitea/pat": { + "post": { + "tags": [ + "Git Providers" + ], + "summary": "Create a Gitea Personal Access Token provider", + "operationId": "create_gitea_pat_provider", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateGiteaPATRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Gitea PAT provider created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProviderResponse" + } + } + } + }, + "400": { + "description": "Bad request \u2014 invalid URL or missing fields" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/git-providers/github/pat": { + "post": { + "tags": [ + "Git Providers" + ], + "summary": "Create a GitHub Personal Access Token provider", + "operationId": "create_github_pat_provider", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateGitHubPATRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "GitHub PAT provider created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProviderResponse" + } + } + } + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/git-providers/gitlab/oauth": { + "post": { + "tags": [ + "Git Providers" + ], + "summary": "Create a GitLab OAuth provider", + "operationId": "create_gitlab_oauth_provider", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateGitLabOAuthRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "GitLab OAuth provider created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProviderResponse" + } + } + } + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/git-providers/gitlab/pat": { + "post": { + "tags": [ + "Git Providers" + ], + "summary": "Create a GitLab PAT provider", + "operationId": "create_gitlab_pat_provider", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateGitLabPATRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "GitLab PAT provider created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProviderResponse" + } + } + } + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/git-providers/{provider_id}": { + "get": { + "tags": [ + "Git Providers" + ], + "summary": "Get a specific git provider", + "operationId": "get_git_provider", + "parameters": [ + { + "name": "provider_id", + "in": "path", + "description": "Provider ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Provider details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProviderResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "Git Providers" + ], + "summary": "Permanently delete a git provider", + "operationId": "delete_git_provider", + "parameters": [ + { + "name": "provider_id", + "in": "path", + "description": "Provider ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Provider deleted successfully" + }, + "400": { + "description": "Provider has connections and cannot be deleted" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/git-providers/{provider_id}/activate": { + "post": { + "tags": [ + "Git Providers" + ], + "summary": "Activate a git provider", + "operationId": "activate_provider", + "parameters": [ + { + "name": "provider_id", + "in": "path", + "description": "Provider ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Provider activated successfully" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/git-providers/{provider_id}/callback": { + "get": { + "tags": [ + "Git Providers" + ], + "summary": "Handle OAuth callback for a git provider", + "operationId": "handle_git_provider_oauth_callback", + "parameters": [ + { + "name": "provider_id", + "in": "path", + "description": "Git provider ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "code", + "in": "query", + "description": "OAuth authorization code", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "state", + "in": "query", + "description": "CSRF state token", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "302": { + "description": "Redirect to success page" + }, + "400": { + "description": "Bad request" + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/git-providers/{provider_id}/connections": { + "get": { + "tags": [ + "Git Providers" + ], + "summary": "Get connections for a specific git provider", + "operationId": "get_provider_connections", + "parameters": [ + { + "name": "provider_id", + "in": "path", + "description": "Provider ID to get connections for", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "List of connections for the provider", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ConnectionResponse" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/git-providers/{provider_id}/credentials": { + "patch": { + "tags": [ + "Git Providers" + ], + "summary": "Partially update credentials for an existing git provider. Only the fields\nyou send are replaced; omitted fields keep their stored values. Fields that\ndon't apply to the provider's auth method are ignored on the service side.", + "operationId": "update_git_provider_credentials", + "parameters": [ + { + "name": "provider_id", + "in": "path", + "description": "Git provider ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateProviderCredentialsRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Credentials updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProviderResponse" + } + } + } + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/git-providers/{provider_id}/deactivate": { + "post": { + "tags": [ + "Git Providers" + ], + "summary": "Deactivate a git provider", + "operationId": "deactivate_provider", + "parameters": [ + { + "name": "provider_id", + "in": "path", + "description": "Provider ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Provider deactivated successfully" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/git-providers/{provider_id}/deletion-check": { + "get": { + "tags": [ + "Git Providers" + ], + "summary": "Check if a git provider can be safely deleted", + "operationId": "check_provider_deletion_safety", + "parameters": [ + { + "name": "provider_id", + "in": "path", + "description": "Git provider ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Deletion check result", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProviderDeletionCheckResponse" + } + } + } + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/git-providers/{provider_id}/oauth/authorize": { + "get": { + "tags": [ + "Git Providers" + ], + "summary": "Start OAuth flow for a git provider", + "operationId": "start_git_provider_oauth", + "parameters": [ + { + "name": "provider_id", + "in": "path", + "description": "Git provider ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "302": { + "description": "Redirect to OAuth provider" + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/git-providers/{provider_id}/repositories": { + "get": { + "tags": [ + "Git Providers" + ], + "summary": "List all repositories for a specific provider", + "description": "Lists repositories synced to the database across every connection under\nthis provider, with the same pagination/filtering as `/repositories`.", + "operationId": "list_repositories_by_provider", + "parameters": [ + { + "name": "provider_id", + "in": "path", + "description": "Provider ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "page", + "in": "query", + "description": "Page number for pagination", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "per_page", + "in": "query", + "description": "Number of items per page (max 100)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "sort", + "in": "query", + "description": "Sort field (name, created_at, updated_at, stars, watchers, size, issues)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "direction", + "in": "query", + "description": "Sort direction (asc, desc)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "search", + "in": "query", + "description": "Search term to filter repositories", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "owner", + "in": "query", + "description": "Filter by repository owner", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "language", + "in": "query", + "description": "Filter by programming language", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "private", + "in": "query", + "description": "Filter by private status (true/false)", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "List of repositories", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RepositoryListResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/git-providers/{provider_id}/safe-delete": { + "delete": { + "tags": [ + "Git Providers" + ], + "summary": "Safely delete a git provider (only if no projects are using it)", + "operationId": "delete_provider_safely", + "parameters": [ + { + "name": "provider_id", + "in": "path", + "description": "Git provider ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Provider successfully deleted" + }, + "400": { + "description": "Cannot delete provider because it's in use" + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/git/public/{provider}/{owner}/{repo}": { + "get": { + "tags": [ + "Public Repositories" + ], + "summary": "Get information about a public repository (supports GitHub and GitLab)", + "operationId": "get_public_repository", + "parameters": [ + { + "name": "provider", + "in": "path", + "description": "Git provider (github or gitlab)", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "owner", + "in": "path", + "description": "Repository owner", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "repo", + "in": "path", + "description": "Repository name", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Repository information", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicRepositoryInfo" + } + } + } + }, + "400": { + "description": "Provider not supported" + }, + "404": { + "description": "Repository not found" + }, + "429": { + "description": "API rate limit exceeded" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/git/public/{provider}/{owner}/{repo}/branches": { + "get": { + "tags": [ + "Public Repositories" + ], + "summary": "Get branches for a public repository (supports GitHub and GitLab)", + "operationId": "get_public_branches", + "parameters": [ + { + "name": "provider", + "in": "path", + "description": "Git provider (github or gitlab)", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "owner", + "in": "path", + "description": "Repository owner", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "repo", + "in": "path", + "description": "Repository name", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "fresh", + "in": "query", + "description": "Force fetch fresh data, bypassing cache (default: false)", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "List of branches", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BranchListResponse" + } + } + } + }, + "400": { + "description": "Provider not supported" + }, + "404": { + "description": "Repository not found" + }, + "429": { + "description": "API rate limit exceeded" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/git/public/{provider}/{owner}/{repo}/presets": { + "get": { + "tags": [ + "Public Repositories" + ], + "summary": "Detect presets for a public repository (supports GitHub and GitLab)", + "operationId": "detect_public_presets", + "parameters": [ + { + "name": "provider", + "in": "path", + "description": "Git provider (github or gitlab)", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "owner", + "in": "path", + "description": "Repository owner", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "repo", + "in": "path", + "description": "Repository name", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "branch", + "in": "query", + "description": "Branch name to detect presets for (default: repository's default branch)", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "fresh", + "in": "query", + "description": "Force fetch fresh data, bypassing cache (default: false)", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "Detected presets", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicPresetResponse" + } + } + } + }, + "400": { + "description": "Provider not supported" + }, + "404": { + "description": "Repository or branch not found" + }, + "429": { + "description": "API rate limit exceeded" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/imports/discover": { + "post": { + "tags": [ + "Imports" + ], + "summary": "Discover workloads from a source", + "operationId": "discover_workloads", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DiscoverRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "List of discovered workloads", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DiscoverResponse" + } + } + } + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/imports/execute": { + "post": { + "tags": [ + "Imports" + ], + "summary": "Execute an import", + "operationId": "execute_import", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExecuteImportRequest" + } + } + }, + "required": true + }, + "responses": { + "202": { + "description": "Import execution started", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExecuteImportResponse" + } + } + } + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/imports/plan": { + "post": { + "tags": [ + "Imports" + ], + "summary": "Create an import plan", + "operationId": "create_plan", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreatePlanRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Import plan created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreatePlanResponse" + } + } + } + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/imports/sources": { + "get": { + "tags": [ + "Imports" + ], + "summary": "List available import sources", + "operationId": "list_sources", + "responses": { + "200": { + "description": "List of available import sources", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImportSourceInfo" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/imports/{session_id}": { + "get": { + "tags": [ + "Imports" + ], + "summary": "Get import status", + "operationId": "get_import_status", + "parameters": [ + { + "name": "session_id", + "in": "path", + "description": "Import session ID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Import status", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ImportStatusResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Import session not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/incidents/{incident_id}": { + "get": { + "tags": [ + "Status Page" + ], + "summary": "Get an incident by ID", + "operationId": "get_incident", + "parameters": [ + { + "name": "incident_id", + "in": "path", + "description": "Incident ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved incident", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IncidentResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Incident not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/incidents/{incident_id}/status": { + "patch": { + "tags": [ + "Status Page" + ], + "summary": "Update incident status", + "operationId": "update_incident_status", + "parameters": [ + { + "name": "incident_id", + "in": "path", + "description": "Incident ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateIncidentStatusRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Incident status updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IncidentResponse" + } + } + } + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Incident not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/incidents/{incident_id}/updates": { + "get": { + "tags": [ + "Status Page" + ], + "summary": "Get incident updates", + "operationId": "get_incident_updates", + "parameters": [ + { + "name": "incident_id", + "in": "path", + "description": "Incident ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved incident updates", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IncidentUpdateResponse" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Incident not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/internal/nodes": { + "get": { + "tags": [ + "Nodes" + ], + "summary": "List all registered nodes (admin \u2014 session auth via RequireAuth)", + "operationId": "admin_list_nodes", + "responses": { + "200": { + "description": "List of nodes", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NodeListResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/internal/nodes/register": { + "post": { + "tags": [ + "Nodes" + ], + "summary": "Register a new worker node or reconnect an existing one", + "operationId": "register_node", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegisterNodeApiRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Node reconnected successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegisterNodeResponse" + } + } + } + }, + "201": { + "description": "Node registered successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegisterNodeResponse" + } + } + } + }, + "400": { + "description": "Validation error" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/internal/nodes/{node_id}": { + "get": { + "tags": [ + "Nodes" + ], + "summary": "Get a specific node by ID (admin \u2014 session auth via RequireAuth)", + "operationId": "admin_get_node", + "parameters": [ + { + "name": "node_id", + "in": "path", + "description": "Node ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Node details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NodeInfoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Node not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "Nodes" + ], + "summary": "Remove a node from the cluster entirely. The node should be drained first\nto ensure containers have been rescheduled. If the node still has active\ncontainers, it will be drained automatically before removal.", + "operationId": "admin_remove_node", + "parameters": [ + { + "name": "node_id", + "in": "path", + "description": "Node ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Node removed", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RemoveNodeResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Node not found" + }, + "409": { + "description": "Node still has active containers" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/internal/nodes/{node_id}/containers": { + "get": { + "tags": [ + "Nodes" + ], + "summary": "List all containers running on a specific node", + "operationId": "admin_list_node_containers", + "parameters": [ + { + "name": "node_id", + "in": "path", + "description": "Node ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Containers on this node", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NodeContainerListResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Node not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/internal/nodes/{node_id}/dns/ack": { + "post": { + "tags": [ + "Internal DNS" + ], + "summary": "`POST /internal/nodes/{node_id}/dns/ack`", + "operationId": "post_dns_ack", + "parameters": [ + { + "name": "node_id", + "in": "path", + "description": "Node id, must match the bearer token's node", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DnsAckRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "ACK accepted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DnsAckResponse" + } + } + } + }, + "400": { + "description": "ACK higher than server generation" + }, + "401": { + "description": "Missing or invalid bearer token" + }, + "404": { + "description": "Node not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/internal/nodes/{node_id}/dns/changes": { + "get": { + "tags": [ + "Internal DNS" + ], + "summary": "`GET /internal/nodes/{node_id}/dns/changes?since=N`", + "operationId": "get_dns_changes", + "parameters": [ + { + "name": "node_id", + "in": "path", + "description": "Node id, must match the bearer token's node", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "since", + "in": "query", + "description": "Highest generation the agent has already applied. Pass `0` to\nrequest a full zone snapshot. Defaults to `0` if omitted.", + "required": false, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "Diff or full snapshot", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DnsChangesResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid bearer token" + }, + "404": { + "description": "Node not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/internal/nodes/{node_id}/drain": { + "get": { + "tags": [ + "Nodes" + ], + "summary": "Get the drain status for a node, including migration progress.", + "description": "Returns container counts and whether the drain is complete.\nCan be polled to track drain progress.", + "operationId": "admin_drain_status", + "parameters": [ + { + "name": "node_id", + "in": "path", + "description": "Node ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Drain status", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DrainStatusResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Node not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Nodes" + ], + "summary": "Drain a node: mark it as \"draining\" so no new replicas are scheduled on it,\nand trigger redeployment of all affected environments so their containers\nare rescheduled to healthy nodes.", + "operationId": "admin_drain_node", + "parameters": [ + { + "name": "node_id", + "in": "path", + "description": "Node ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Node drain initiated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DrainNodeResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Node not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "Nodes" + ], + "summary": "Undrain (reactivate) a node so it can accept new deployments again.\nOnly works for nodes in \"draining\" or \"drained\" status.", + "operationId": "admin_undrain_node", + "parameters": [ + { + "name": "node_id", + "in": "path", + "description": "Node ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Node reactivated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UndrainNodeResponse" + } + } + } + }, + "400": { + "description": "Node not in drainable state" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Node not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/internal/nodes/{node_id}/heartbeat": { + "post": { + "tags": [ + "Nodes" + ], + "summary": "Receive a heartbeat from a worker node", + "operationId": "node_heartbeat", + "parameters": [ + { + "name": "node_id", + "in": "path", + "description": "Node ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HeartbeatApiRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Heartbeat received", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HeartbeatResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Node not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/internal/nodes/{node_id}/network/peers": { + "get": { + "tags": [ + "Nodes" + ], + "summary": "`GET /internal/nodes/{node_id}/network/peers`", + "operationId": "list_peers", + "parameters": [ + { + "name": "node_id", + "in": "path", + "description": "Node id, must match the bearer token's node", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Peer list and self-allocation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PeerListResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid bearer token" + }, + "404": { + "description": "Node not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/internal/nodes/{node_id}/s3-credentials/{s3_source_id}": { + "get": { + "tags": [ + "Nodes" + ], + "summary": "Get decrypted S3 credentials for a backup/restore operation.", + "description": "Agents call this endpoint to receive the S3 credentials they need to upload\nor download backups. The credentials are decrypted from the stored S3 source\nand returned over the authenticated TLS/WireGuard channel.", + "operationId": "get_s3_credentials", + "parameters": [ + { + "name": "node_id", + "in": "path", + "description": "Node ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "s3_source_id", + "in": "path", + "description": "S3 source ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "S3 credentials", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/S3CredentialsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "S3 source not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/ip-access-control": { + "get": { + "tags": [ + "IP Access Control" + ], + "summary": "List all IP access control rules", + "operationId": "list_ip_access_control", + "parameters": [ + { + "name": "action", + "in": "query", + "description": "Filter by action (\"block\" or \"allow\")", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + } + ], + "responses": { + "200": { + "description": "List of IP access control rules", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IpAccessControlResponse" + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "IP Access Control" + ], + "summary": "Create a new IP access control rule", + "operationId": "create_ip_access_control", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateIpAccessControlRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "IP access control rule created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IpAccessControlResponse" + } + } + } + }, + "400": { + "description": "Invalid request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "409": { + "description": "Duplicate IP address", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/ip-access-control/check/{ip}": { + "get": { + "tags": [ + "IP Access Control" + ], + "summary": "Check if an IP address is blocked", + "operationId": "check_ip_blocked", + "parameters": [ + { + "name": "ip", + "in": "path", + "description": "IP address to check", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "IP block status" + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/ip-access-control/{id}": { + "get": { + "tags": [ + "IP Access Control" + ], + "summary": "Get a single IP access control rule by ID", + "operationId": "get_ip_access_control", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "IP access control rule ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "IP access control rule details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IpAccessControlResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "IP access control rule not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "IP Access Control" + ], + "summary": "Delete an IP access control rule", + "operationId": "delete_ip_access_control", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "IP access control rule ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "IP access control rule deleted" + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "IP access control rule not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "patch": { + "tags": [ + "IP Access Control" + ], + "summary": "Update an IP access control rule", + "operationId": "update_ip_access_control", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "IP access control rule ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateIpAccessControlRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "IP access control rule updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IpAccessControlResponse" + } + } + } + }, + "400": { + "description": "Invalid request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "IP access control rule not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/kv/del": { + "post": { + "tags": [ + "KV Store" + ], + "summary": "Delete one or more keys", + "operationId": "kv_del", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DelRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Keys deleted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DelResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/kv/disable": { + "delete": { + "tags": [ + "KV Management" + ], + "summary": "Disable KV service", + "operationId": "kv_disable", + "responses": { + "200": { + "description": "KV service disabled", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DisableKvResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "KV service not enabled" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/kv/enable": { + "post": { + "tags": [ + "KV Management" + ], + "summary": "Enable KV service", + "operationId": "kv_enable", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnableKvRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "KV service enabled", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnableKvResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/kv/expire": { + "post": { + "tags": [ + "KV Store" + ], + "summary": "Set expiration on a key", + "operationId": "kv_expire", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExpireRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Expiration set", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExpireResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/kv/get": { + "post": { + "tags": [ + "KV Store" + ], + "summary": "Get a value by key", + "operationId": "kv_get", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Value retrieved", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/kv/incr": { + "post": { + "tags": [ + "KV Store" + ], + "summary": "Increment a numeric value", + "operationId": "kv_incr", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IncrRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Value incremented", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IncrResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/kv/keys": { + "post": { + "tags": [ + "KV Store" + ], + "summary": "Get keys matching a pattern", + "operationId": "kv_keys", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeysRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Keys retrieved", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeysResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/kv/set": { + "post": { + "tags": [ + "KV Store" + ], + "summary": "Set a value with optional expiration", + "operationId": "kv_set", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Value set", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/kv/status": { + "get": { + "tags": [ + "KV Management" + ], + "summary": "Get KV service status", + "operationId": "kv_status", + "responses": { + "200": { + "description": "KV service status", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KvStatusResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/kv/ttl": { + "post": { + "tags": [ + "KV Store" + ], + "summary": "Get time-to-live for a key", + "operationId": "kv_ttl", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TtlRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "TTL retrieved", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TtlResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/kv/update": { + "patch": { + "tags": [ + "KV Management" + ], + "summary": "Update KV service configuration", + "operationId": "kv_update", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateKvRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "KV service updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateKvResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "KV service not enabled" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/lb/routes": { + "get": { + "tags": [ + "Load Balancer" + ], + "operationId": "list_routes", + "responses": { + "200": { + "description": "List of routes", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RouteResponse" + } + } + } + } + }, + "500": { + "description": "Internal server error" + } + } + }, + "post": { + "tags": [ + "Load Balancer" + ], + "operationId": "create_route", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateRouteRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Route created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RouteResponse" + } + } + } + }, + "400": { + "description": "Invalid request" + } + } + } + }, + "/lb/routes/{domain}": { + "get": { + "tags": [ + "Load Balancer" + ], + "operationId": "get_route", + "parameters": [ + { + "name": "domain", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Route found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RouteResponse" + } + } + } + }, + "404": { + "description": "Route not found" + } + } + }, + "put": { + "tags": [ + "Load Balancer" + ], + "operationId": "update_route", + "parameters": [ + { + "name": "domain", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateRouteRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Route updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RouteResponse" + } + } + } + }, + "404": { + "description": "Route not found" + } + } + }, + "delete": { + "tags": [ + "Load Balancer" + ], + "operationId": "delete_route", + "parameters": [ + { + "name": "domain", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Route deleted successfully" + }, + "404": { + "description": "Route not found" + } + } + } + }, + "/logout": { + "post": { + "tags": [ + "Authentication" + ], + "operationId": "logout", + "responses": { + "200": { + "description": "Successfully logged out" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "session_token": [] + } + ] + } + }, + "/logs/context": { + "get": { + "tags": [ + "Logs" + ], + "summary": "Get context lines surrounding a specific log line", + "operationId": "get_log_context", + "parameters": [ + { + "name": "chunk_id", + "in": "query", + "description": "Chunk ID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "line_offset", + "in": "query", + "description": "Line offset within the chunk", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "lines", + "in": "query", + "description": "Context lines before and after (default: 25)", + "required": false, + "schema": { + "type": "integer", + "format": "int32", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "Context lines", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContextLogsResponse" + } + } + } + }, + "400": { + "description": "Invalid parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Chunk not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/logs/search": { + "post": { + "tags": [ + "Logs" + ], + "summary": "Search logs with structured filters and full text search", + "operationId": "search_logs", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SearchLogsRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Search results", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SearchLogsResponse" + } + } + } + }, + "400": { + "description": "Invalid search parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/logs/tail": { + "get": { + "tags": [ + "Logs" + ], + "summary": "Live tail logs via Server-Sent Events", + "operationId": "tail_logs", + "parameters": [ + { + "name": "project_id", + "in": "query", + "description": "Project ID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "service", + "in": "query", + "description": "Service name", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "env", + "in": "query", + "description": "Environment", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "levels", + "in": "query", + "description": "Optional level filters", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "text", + "in": "query", + "description": "Optional text filter", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "SSE stream of log lines" + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/monitors-health/projects": { + "get": { + "tags": [ + "Status Page" + ], + "summary": "Get monitor-based health summaries for multiple projects in a single query", + "operationId": "get_projects_monitor_health", + "parameters": [ + { + "name": "project_ids", + "in": "query", + "description": "Comma-separated list of project IDs", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Health summaries per project", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectsMonitorHealthResponse" + } + } + } + }, + "400": { + "description": "Invalid parameters" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/monitors/{monitor_id}": { + "get": { + "tags": [ + "Status Page" + ], + "summary": "Get a monitor by ID", + "operationId": "get_monitor", + "parameters": [ + { + "name": "monitor_id", + "in": "path", + "description": "Monitor ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved monitor", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MonitorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Monitor not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "Status Page" + ], + "summary": "Delete a monitor", + "operationId": "delete_monitor", + "parameters": [ + { + "name": "monitor_id", + "in": "path", + "description": "Monitor ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Monitor deleted successfully" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Monitor not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/monitors/{monitor_id}/bucketed": { + "get": { + "tags": [ + "Status Page" + ], + "summary": "Get bucketed status data for a monitor using TimescaleDB", + "operationId": "get_bucketed_status", + "parameters": [ + { + "name": "monitor_id", + "in": "path", + "description": "Monitor ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "interval", + "in": "query", + "description": "Bucket interval: '5min', 'hourly', or 'daily' (default: hourly)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "start_time", + "in": "query", + "description": "Start time (ISO 8601) (default: 24 hours ago)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "end_time", + "in": "query", + "description": "End time (ISO 8601) (default: now)", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved bucketed status data", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StatusBucketedResponse" + } + } + } + }, + "400": { + "description": "Invalid parameters" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Monitor not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/monitors/{monitor_id}/current-status": { + "get": { + "tags": [ + "Status Page" + ], + "summary": "Get current status and uptime metrics for a monitor", + "operationId": "get_current_monitor_status", + "parameters": [ + { + "name": "monitor_id", + "in": "path", + "description": "Monitor ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "start_time", + "in": "query", + "description": "Custom start time (ISO 8601) - overrides timeframe", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "end_time", + "in": "query", + "description": "Custom end time (ISO 8601)", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved current status", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CurrentStatusResponse" + } + } + } + }, + "400": { + "description": "Invalid time parameters" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Monitor not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/monitors/{monitor_id}/uptime": { + "get": { + "tags": [ + "Status Page" + ], + "summary": "Get uptime history for a monitor", + "operationId": "get_uptime_history", + "parameters": [ + { + "name": "monitor_id", + "in": "path", + "description": "Monitor ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "days", + "in": "query", + "description": "Number of days of history (default: 60) - ignored if start_time/end_time provided", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "start_time", + "in": "query", + "description": "Start time (ISO 8601) - overrides days parameter", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "end_time", + "in": "query", + "description": "End time (ISO 8601) - defaults to now", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved uptime history", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UptimeHistoryResponse" + } + } + } + }, + "400": { + "description": "Invalid time parameters" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Monitor not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/nodes/{id}/metrics": { + "get": { + "tags": [ + "Metrics" + ], + "summary": "Fetch a time-series range for a single metric on a node.", + "operationId": "NodeMetricsGetRange", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Node ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "metric", + "in": "query", + "description": "Metric name, e.g. `\"pg.connections_active\"`.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "range", + "in": "query", + "description": "Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`.", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "percentile", + "in": "query", + "description": "Optional histogram percentile (0\u2013100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile.", + "required": false, + "schema": { + "type": [ + "number", + "null" + ], + "format": "double" + } + } + ], + "responses": { + "200": { + "description": "Metric time series data points", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MetricDataPoint" + } + } + } + } + }, + "400": { + "description": "Invalid query parameters" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + }, + "503": { + "description": "Metrics store not available" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/notification-preferences": { + "get": { + "tags": [ + "Notification Preferences" + ], + "summary": "Get notification preferences", + "operationId": "get_preferences", + "responses": { + "200": { + "description": "Successfully retrieved preferences", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationPreferencesResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "put": { + "tags": [ + "Notification Preferences" + ], + "summary": "Update notification preferences", + "operationId": "update_preferences", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdatePreferencesRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successfully updated preferences", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationPreferencesResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "Notification Preferences" + ], + "summary": "Delete notification preferences", + "operationId": "delete_preferences", + "responses": { + "204": { + "description": "Successfully deleted preferences" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/notification-providers": { + "get": { + "tags": [ + "Notification Providers" + ], + "summary": "List all notification providers", + "operationId": "list_notification_providers", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "Page number (1-indexed)", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + }, + "example": 1 + }, + { + "name": "page_size", + "in": "query", + "description": "Number of items per page (max 100)", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + }, + "example": 20 + }, + { + "name": "sort_by", + "in": "query", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "sort_order", + "in": "query", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved providers", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NotificationProviderResponse" + } + } + } + } + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Notification Providers" + ], + "summary": "Create a new notification provider", + "operationId": "create_notification_provider", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateProviderRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Successfully created provider", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationProviderResponse" + } + } + } + }, + "400": { + "description": "Invalid request" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/notification-providers/cloudflare": { + "post": { + "tags": [ + "Notification Providers" + ], + "summary": "Create a new Cloudflare Email Sending notification provider", + "operationId": "create_cloudflare_provider", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateCloudflareProviderRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Successfully created Cloudflare provider", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationProviderResponse" + } + } + } + }, + "400": { + "description": "Invalid request" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/notification-providers/cloudflare/{id}": { + "put": { + "tags": [ + "Notification Providers" + ], + "summary": "Update a Cloudflare Email Sending notification provider", + "operationId": "update_cloudflare_provider", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Provider ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateCloudflareProviderRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successfully updated Cloudflare provider", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationProviderResponse" + } + } + } + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/notification-providers/email": { + "post": { + "tags": [ + "Notification Providers" + ], + "summary": "Create a new Email notification provider", + "operationId": "create_notification_email_provider", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateNotificationEmailProviderRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Successfully created Email provider", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationProviderResponse" + } + } + } + }, + "400": { + "description": "Invalid request" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/notification-providers/email/{id}": { + "put": { + "tags": [ + "Notification Providers" + ], + "summary": "Update an Email notification provider", + "operationId": "update_notification_email_provider", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Provider ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateNotificationEmailProviderRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successfully updated Email provider", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationProviderResponse" + } + } + } + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/notification-providers/slack": { + "post": { + "tags": [ + "Notification Providers" + ], + "summary": "Create a new Slack notification provider", + "operationId": "create_slack_provider", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateSlackProviderRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Successfully created Slack provider", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationProviderResponse" + } + } + } + }, + "400": { + "description": "Invalid request" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/notification-providers/slack/{id}": { + "put": { + "tags": [ + "Notification Providers" + ], + "summary": "Update a Slack notification provider", + "operationId": "update_slack_provider", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Provider ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateSlackProviderRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successfully updated Slack provider", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationProviderResponse" + } + } + } + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/notification-providers/webhook": { + "post": { + "tags": [ + "Notification Providers" + ], + "summary": "Create a new Webhook notification provider", + "description": "Webhook providers send notifications as JSON payloads to any HTTP endpoint.\nYou can configure custom headers for authentication (Bearer tokens, API keys, etc.).\nThe webhook will receive a JSON payload with notification details including:\nid, title, message, type, priority, severity, timestamp, and metadata.", + "operationId": "create_webhook_provider", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateWebhookProviderRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Successfully created Webhook provider", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationProviderResponse" + } + } + } + }, + "400": { + "description": "Invalid request" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/notification-providers/webhook/{id}": { + "put": { + "tags": [ + "Notification Providers" + ], + "summary": "Update a Webhook notification provider", + "operationId": "update_webhook_provider", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Provider ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateWebhookProviderRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successfully updated Webhook provider", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationProviderResponse" + } + } + } + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/notification-providers/{id}": { + "get": { + "tags": [ + "Notification Providers" + ], + "summary": "Get a single notification provider", + "operationId": "get_notification_provider", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Provider ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved provider", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationProviderResponse" + } + } + } + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "put": { + "tags": [ + "Notification Providers" + ], + "summary": "Update a notification provider", + "operationId": "update_notification_provider", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Provider ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateProviderRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successfully updated provider", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationProviderResponse" + } + } + } + }, + "400": { + "description": "Invalid masked provider configuration" + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "Notification Providers" + ], + "summary": "Delete a notification provider", + "operationId": "delete_notification_provider", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Provider ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Successfully deleted provider" + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/notification-providers/{id}/config/{field}": { + "get": { + "tags": [ + "Notification Providers" + ], + "operationId": "reveal_notification_provider_config", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Provider ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "field", + "in": "path", + "description": "Sensitive field, such as password or headers.Authorization", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Sensitive provider configuration value", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SensitiveConfigValueResponse" + } + } + } + }, + "400": { + "description": "Field is not revealable" + }, + "403": { + "description": "Missing secrets:read permission" + }, + "404": { + "description": "Provider or field not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/notification-providers/{id}/test": { + "post": { + "tags": [ + "Notification Providers" + ], + "summary": "Test a notification provider", + "operationId": "test_notification_provider", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Provider ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Test result", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TestProviderResponse" + } + } + } + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/orders": { + "get": { + "tags": [ + "Domains" + ], + "summary": "List all ACME orders", + "operationId": "list_orders", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "Page number (1-indexed)", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + }, + "example": 1 + }, + { + "name": "page_size", + "in": "query", + "description": "Number of items per page (max 100)", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + }, + "example": 20 + }, + { + "name": "sort_by", + "in": "query", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "sort_order", + "in": "query", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + } + ], + "responses": { + "200": { + "description": "Orders retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListOrdersResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/otel/alerts": { + "get": { + "tags": [ + "Alerts" + ], + "summary": "List alert rules for a project (newest first, paginated).", + "operationId": "list_alerts", + "parameters": [ + { + "name": "project_id", + "in": "query", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "page", + "in": "query", + "description": "Page number (default: 1)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "page_size", + "in": "query", + "description": "Page size (default: 20, max: 100)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "Alert rules for the project", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OtelMetricAlertsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Alerts" + ], + "summary": "Create a new alert rule for a project.", + "operationId": "create_alert", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateMetricAlertRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Alert rule created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OtelMetricAlertRuleResponse" + } + } + } + }, + "400": { + "description": "Validation error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/otel/alerts/preview": { + "post": { + "tags": [ + "Alerts" + ], + "summary": "Backtest an anomaly detector over a time range without saving a rule.", + "description": "Replays the metric against the same band the evaluator would use, returning\nthe per-bucket band + which points would have fired. Powers the form's\n\"would this have fired?\" preview and the explorer band overlay. Read-only.", + "operationId": "preview_alert", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AnomalyPreviewRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Per-bucket band + breach points", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AnomalyPreviewResponse" + } + } + } + }, + "400": { + "description": "Not an anomaly detector / bad input", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/otel/alerts/{id}": { + "get": { + "tags": [ + "Alerts" + ], + "summary": "Fetch a single alert rule by id.", + "operationId": "get_alert", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Alert rule ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "project_id", + "in": "query", + "description": "Owning project ID (scopes the lookup)", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Alert rule", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OtelMetricAlertRuleResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Alert rule not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "Alerts" + ], + "summary": "Delete an alert rule.", + "operationId": "delete_alert", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Alert rule ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "project_id", + "in": "query", + "description": "Owning project ID (scopes the delete)", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Alert rule deleted" + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Alert rule not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "patch": { + "tags": [ + "Alerts" + ], + "summary": "Update an alert rule's fields.", + "operationId": "update_alert", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Alert rule ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "project_id", + "in": "query", + "description": "Owning project ID (scopes the update)", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateMetricAlertRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Alert rule updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OtelMetricAlertRuleResponse" + } + } + } + }, + "400": { + "description": "Validation error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Alert rule not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/otel/dashboards": { + "get": { + "tags": [ + "Dashboards" + ], + "summary": "List dashboards for a project (newest first, paginated).", + "operationId": "list_dashboards", + "parameters": [ + { + "name": "project_id", + "in": "query", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "page", + "in": "query", + "description": "Page number (default: 1)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "page_size", + "in": "query", + "description": "Page size (default: 20, max: 100)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "Dashboards for the project", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OtelDashboardsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Dashboards" + ], + "summary": "Create a new dashboard for a project.", + "operationId": "create_dashboard", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateDashboardRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Dashboard created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OtelDashboardResponse" + } + } + } + }, + "400": { + "description": "Validation error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/otel/dashboards/{id}": { + "get": { + "tags": [ + "Dashboards" + ], + "summary": "Fetch a single dashboard by id.", + "operationId": "get_dashboard", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Dashboard ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "project_id", + "in": "query", + "description": "Owning project ID (scopes the lookup)", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Dashboard", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OtelDashboardResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Dashboard not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "Dashboards" + ], + "summary": "Delete a dashboard.", + "operationId": "delete_dashboard", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Dashboard ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "project_id", + "in": "query", + "description": "Owning project ID (scopes the delete)", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Dashboard deleted" + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Dashboard not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "patch": { + "tags": [ + "Dashboards" + ], + "summary": "Update a dashboard's name and/or layout.", + "operationId": "update_dashboard", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Dashboard ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "project_id", + "in": "query", + "description": "Owning project ID (scopes the update)", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateDashboardRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Dashboard updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OtelDashboardResponse" + } + } + } + }, + "400": { + "description": "Validation error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Dashboard not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/otel/genai/traces": { + "get": { + "tags": [ + "GenAI" + ], + "summary": "Query GenAI trace summaries \u2014 traces containing spans with `gen_ai.*` attributes.", + "description": "`duration_ms` is the only field guaranteed to be milliseconds. `gen_ai.*`\nspan attributes (e.g. time-to-first-token, token latency) often follow the\nOTel GenAI semantic conventions, which use **seconds** (a fractional\ndouble), not milliseconds \u2014 do not read them as ms without converting.", + "operationId": "query_genai_traces", + "parameters": [ + { + "name": "project_id", + "in": "query", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "service_name", + "in": "query", + "description": "Filter by service name", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "gen_ai_system", + "in": "query", + "description": "Filter by AI system (openai, anthropic, etc.)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "gen_ai_model", + "in": "query", + "description": "Filter by model (gpt-4, claude-sonnet-4-20250514, etc.)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "start_time", + "in": "query", + "description": "Start time (RFC 3339)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "end_time", + "in": "query", + "description": "End time (RFC 3339)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "description": "Max traces to return (default: 50, max: 100)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "offset", + "in": "query", + "description": "Offset for pagination", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "GenAI trace summaries", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GenAiTraceSummariesResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/otel/genai/traces/{project_id}/{trace_id}": { + "get": { + "tags": [ + "GenAI" + ], + "summary": "Get GenAI span details for a specific trace.", + "description": "`duration_ms` is the only field guaranteed to be milliseconds. `gen_ai.*`\nspan attributes (e.g. time-to-first-token, token latency) often follow the\nOTel GenAI semantic conventions, which use **seconds** (a fractional\ndouble), not milliseconds \u2014 do not read them as ms without converting.", + "operationId": "get_genai_trace", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "trace_id", + "in": "path", + "description": "Trace ID (hex)", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "GenAI trace span details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GenAiTraceDetailResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/otel/global/traces/{trace_id}": { + "get": { + "tags": [ + "Traces" + ], + "summary": "Assemble a unified cross-project span waterfall (Phase 2).", + "description": "Fans out to every project that holds spans for `trace_id` (up to 20\nprojects, 10,000 total spans). Spans are annotated with\n`project_id`/`project_name` and sorted by `start_time ASC`.\n`truncated: true` signals a hit on either cap; `truncated_projects`\nlists the dropped project IDs. See ADR-027 \u00a74 for the full design.", + "operationId": "getUnifiedTrace", + "parameters": [ + { + "name": "trace_id", + "in": "path", + "description": "Trace ID (32 lowercase hex characters)", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Unified cross-project trace waterfall", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnifiedTrace" + } + } + } + }, + "400": { + "description": "trace_id is not 32 lowercase hex characters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions or deployment token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/otel/health/{project_id}": { + "get": { + "tags": [ + "OTel" + ], + "summary": "Get health summaries for a project.", + "operationId": "get_health", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Filter by environment ID", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Health summaries", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HealthResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/otel/insights/{project_id}": { + "get": { + "tags": [ + "Insights" + ], + "summary": "List anomaly insights for a project.", + "operationId": "list_insights", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "status", + "in": "query", + "description": "Filter by status (active, resolved)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "description": "Max insights to return (default: 20, max: 100)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "offset", + "in": "query", + "description": "Offset for pagination", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "Insights list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InsightsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/otel/logs": { + "get": { + "tags": [ + "Telemetry Logs" + ], + "summary": "Query log records with optional filters.", + "operationId": "query_logs", + "parameters": [ + { + "name": "project_id", + "in": "query", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "severity", + "in": "query", + "description": "Filter by severity (TRACE, DEBUG, INFO, WARN, ERROR, FATAL)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "service_name", + "in": "query", + "description": "Filter by service name", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "search", + "in": "query", + "description": "Full-text search in log body (ILIKE)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "trace_id", + "in": "query", + "description": "Filter by correlated trace ID", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "start_time", + "in": "query", + "description": "Start time (RFC 3339)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "end_time", + "in": "query", + "description": "End time (RFC 3339)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "description": "Max logs to return (default: 100, max: 1000)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "offset", + "in": "query", + "description": "Offset for pagination", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "Log records", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LogsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/otel/metric-label-keys": { + "get": { + "tags": [ + "Telemetry Metrics" + ], + "summary": "List the attribute (label) keys observed on a metric \u2014 powers the\nlabel-filter key autocomplete.", + "operationId": "list_metric_label_keys", + "parameters": [ + { + "name": "project_id", + "in": "query", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "metric_name", + "in": "query", + "description": "Metric to inspect", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "start_time", + "in": "query", + "description": "Window start (RFC 3339); defaults to 24h before end", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "end_time", + "in": "query", + "description": "Window end (RFC 3339); defaults to now", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Distinct label keys", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OtelMetricLabelKeysResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/otel/metric-label-values": { + "get": { + "tags": [ + "Telemetry Metrics" + ], + "summary": "List the distinct values seen for a label key on a metric \u2014 powers value\nautocomplete once a key is chosen.", + "operationId": "list_metric_label_values", + "parameters": [ + { + "name": "project_id", + "in": "query", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "metric_name", + "in": "query", + "description": "Metric to inspect", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "label_key", + "in": "query", + "description": "Label key whose values to list (must match [a-zA-Z0-9_.:-])", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "start_time", + "in": "query", + "description": "Window start (RFC 3339); defaults to 24h before end", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "end_time", + "in": "query", + "description": "Window end (RFC 3339); defaults to now", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Distinct label values", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OtelMetricLabelValuesResponse" + } + } + } + }, + "400": { + "description": "Invalid label key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/otel/metric-names/{project_id}": { + "get": { + "tags": [ + "Telemetry Metrics" + ], + "summary": "List distinct metric names for a project.", + "operationId": "list_metric_names", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "List of metric names", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OtelMetricNamesResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/otel/metrics": { + "get": { + "tags": [ + "Telemetry Metrics" + ], + "summary": "Query metrics with time bucketing.", + "operationId": "query_metrics", + "parameters": [ + { + "name": "project_id", + "in": "query", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "metric_name", + "in": "query", + "description": "Filter by metric name", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "service_name", + "in": "query", + "description": "Filter by service name", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "environment", + "in": "query", + "description": "Filter by deployment environment", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "start_time", + "in": "query", + "description": "Start time (RFC 3339)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "end_time", + "in": "query", + "description": "End time (RFC 3339)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "bucket_interval", + "in": "query", + "description": "Bucket interval (e.g. '1 hour', '5 minutes')", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "description": "Max buckets to return (default: 1000)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "metric_type", + "in": "query", + "description": "Filter by metric type (gauge, sum, histogram, exponential_histogram, summary)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "aggregation", + "in": "query", + "description": "Per-bucket aggregation: avg (default), sum, min, max, count, rate, p50/p95/p99, quantile:0.95", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "label_filters", + "in": "query", + "description": "Comma-separated key=value data-point label filters (keys must match [a-zA-Z0-9_.:-])", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "group_by", + "in": "query", + "description": "Comma-separated label keys to group series by", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Metrics data", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OtelMetricsResponse" + } + } + } + }, + "400": { + "description": "Invalid label key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/otel/pipeline-stats": { + "get": { + "tags": [ + "OTel" + ], + "summary": "Get OTel pipeline statistics (admin/system view).", + "operationId": "get_pipeline_stats", + "responses": { + "200": { + "description": "Pipeline statistics", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PipelineStatsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/otel/quota/{project_id}": { + "get": { + "tags": [ + "OTel" + ], + "summary": "Get storage quota for a project.", + "operationId": "get_quota", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Storage quota", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QuotaResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/otel/trace-summaries": { + "get": { + "tags": [ + "Traces" + ], + "summary": "Query trace summaries \u2014 one row per trace with span count, error count,\nroot span info, and proper trace-level pagination.", + "operationId": "query_trace_summaries", + "parameters": [ + { + "name": "project_id", + "in": "query", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "trace_id", + "in": "query", + "description": "Filter by trace ID", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "service_name", + "in": "query", + "description": "Filter by service name", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "status", + "in": "query", + "description": "Filter by status (OK, ERROR)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "min_duration_ms", + "in": "query", + "description": "Minimum trace duration in ms", + "required": false, + "schema": { + "type": "number", + "format": "double" + } + }, + { + "name": "start_time", + "in": "query", + "description": "Start time (RFC 3339)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "end_time", + "in": "query", + "description": "End time (RFC 3339)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Filter by environment ID", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "deployment_id", + "in": "query", + "description": "Filter by deployment ID", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "name_pattern", + "in": "query", + "description": "Filter by span name pattern (ILIKE)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "sort_by", + "in": "query", + "description": "Sort field: 'start_time' (default) or 'duration'", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "sort_order", + "in": "query", + "description": "Sort direction: 'asc' or 'desc' (default)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "include_total", + "in": "query", + "description": "Compute the `total` count (default: true). Set false to skip the second aggregation when only the page is needed", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "name": "limit", + "in": "query", + "description": "Max traces to return (default: 50, max: 100)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "offset", + "in": "query", + "description": "Offset for pagination", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "Trace summaries", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TraceSummariesResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/otel/traces": { + "get": { + "tags": [ + "Traces" + ], + "summary": "Query trace spans with optional filters.", + "description": "Each returned span has a `duration_ms` field (float, milliseconds) \u2014 this is\nthe ONLY field guaranteed to be in milliseconds. Spans also carry an\n`attributes` map of raw key/value pairs exactly as reported by the\ninstrumenting library: numeric attribute values may be seconds, milliseconds,\nmicroseconds, or nanoseconds depending on that library's convention, and\nnothing in this response labels the unit. Never assume an attribute's\nnumeric value shares `duration_ms`'s unit, and never state a duration in\nmilliseconds unless it came from a `duration_ms` field.", + "operationId": "query_traces", + "parameters": [ + { + "name": "project_id", + "in": "query", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "trace_id", + "in": "query", + "description": "Filter by trace ID", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "service_name", + "in": "query", + "description": "Filter by service name", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "status", + "in": "query", + "description": "Filter by status (OK, ERROR, UNSET)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "min_duration_ms", + "in": "query", + "description": "Minimum span duration in ms", + "required": false, + "schema": { + "type": "number", + "format": "double" + } + }, + { + "name": "start_time", + "in": "query", + "description": "Start time (RFC 3339)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "end_time", + "in": "query", + "description": "End time (RFC 3339)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Filter by environment ID", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "deployment_id", + "in": "query", + "description": "Filter by deployment ID", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "limit", + "in": "query", + "description": "Max spans to return (default: 100, max: 1000)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "offset", + "in": "query", + "description": "Offset for pagination", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "Trace spans", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TracesResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/otel/traces/cross-project/{trace_id}": { + "get": { + "tags": [ + "Traces" + ], + "summary": "Discover sibling projects that share the same `trace_id` (Phase 1 banner).", + "description": "Returns an empty `siblings` list when the trace is single-project \u2014 never\n404. Project names are included so the UI can render navigation links\nwithout a second round-trip. See ADR-027 \u00a73 for the full auth model and\ntopology-disclosure trade-offs.", + "operationId": "getCrossProjectTraceSiblings", + "parameters": [ + { + "name": "trace_id", + "in": "path", + "description": "Trace ID (32 lowercase hex characters)", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "exclude_project_id", + "in": "query", + "description": "Project ID to exclude (the caller's own project) so the UI does not render a self-link", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Sibling projects sharing this trace", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CrossProjectTraceResponse" + } + } + } + }, + "400": { + "description": "trace_id is not 32 lowercase hex characters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions or deployment token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/otel/traces/{project_id}/{trace_id}": { + "get": { + "tags": [ + "Traces" + ], + "summary": "Get all spans for a specific trace.", + "description": "Each span has a `duration_ms` field (float, milliseconds) \u2014 the ONLY field\nguaranteed to be in milliseconds \u2014 plus an `attributes` map of raw\nkey/value pairs exactly as the instrumenting library reported them.\nNumeric attribute values (e.g. connection-pool wait times, queue delays)\nmay be in seconds, milliseconds, microseconds, or nanoseconds depending on\nthat library's own convention; this response never labels the unit. When\nexplaining what a span spent time on, only quote milliseconds from\n`duration_ms` (or from `start_time`/`end_time` deltas) \u2014 never assume a raw\nattribute number is already in milliseconds.", + "operationId": "get_trace", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "trace_id", + "in": "path", + "description": "Trace ID (hex)", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Trace spans tree", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TracesResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/otel/v1/logs": { + "post": { + "tags": [ + "OTel Ingest" + ], + "summary": "Ingest log records via OTLP/HTTP protobuf.", + "description": "Authenticates via API key in header, decompresses, decodes protobuf,\nchecks rate limit and storage quota, routes high-severity logs\nto DB and all logs to S3.", + "operationId": "ingest_logs", + "requestBody": { + "description": "OTLP ExportLogsServiceRequest (protobuf, optionally gzip/zstd compressed)", + "content": { + "application/x-protobuf": { + "schema": { + "type": "string" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Logs accepted (OTLP protobuf response)" + }, + "400": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Missing or invalid API key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "413": { + "description": "Storage quota exceeded", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "429": { + "description": "Rate limit exceeded", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ] + } + }, + "/otel/v1/metrics": { + "post": { + "tags": [ + "OTel Ingest" + ], + "summary": "Ingest metrics via OTLP/HTTP protobuf.", + "description": "Authenticates via API key in header, decompresses, decodes protobuf,\nchecks rate limit and storage quota, then stores.", + "operationId": "ingest_metrics", + "requestBody": { + "description": "OTLP ExportMetricsServiceRequest (protobuf, optionally gzip/zstd compressed)", + "content": { + "application/x-protobuf": { + "schema": { + "type": "string" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Metrics accepted (OTLP protobuf response)" + }, + "400": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Missing or invalid API key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "413": { + "description": "Storage quota exceeded", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "429": { + "description": "Rate limit exceeded", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ] + } + }, + "/otel/v1/traces": { + "post": { + "tags": [ + "OTel Ingest" + ], + "summary": "Ingest trace spans via OTLP/HTTP protobuf.", + "description": "Authenticates via API key in header, decompresses, decodes protobuf,\nchecks rate limit and storage quota, then stores spans.", + "operationId": "ingest_traces", + "requestBody": { + "description": "OTLP ExportTraceServiceRequest (protobuf, optionally gzip/zstd compressed)", + "content": { + "application/x-protobuf": { + "schema": { + "type": "string" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Traces accepted (OTLP protobuf response)" + }, + "400": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Missing or invalid API key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "413": { + "description": "Storage quota exceeded", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "429": { + "description": "Rate limit exceeded", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ] + } + }, + "/otel/v1/{project_id}/{environment_id}/{deployment_id}/logs": { + "post": { + "tags": [ + "OTel Ingest" + ], + "summary": "Ingest log records with project/environment/deployment in the URL path.", + "operationId": "ingest_logs_by_path", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "path", + "description": "Environment ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "deployment_id", + "in": "path", + "description": "Deployment ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "description": "OTLP ExportLogsServiceRequest (protobuf, optionally gzip/zstd compressed)", + "content": { + "application/x-protobuf": { + "schema": { + "type": "string" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Logs accepted (OTLP protobuf response)" + }, + "400": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Missing or invalid API key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "413": { + "description": "Storage quota exceeded", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "429": { + "description": "Rate limit exceeded", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ] + } + }, + "/otel/v1/{project_id}/{environment_id}/{deployment_id}/metrics": { + "post": { + "tags": [ + "OTel Ingest" + ], + "summary": "Ingest metrics with project/environment/deployment in the URL path.", + "operationId": "ingest_metrics_by_path", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "path", + "description": "Environment ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "deployment_id", + "in": "path", + "description": "Deployment ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "description": "OTLP ExportMetricsServiceRequest (protobuf, optionally gzip/zstd compressed)", + "content": { + "application/x-protobuf": { + "schema": { + "type": "string" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Metrics accepted (OTLP protobuf response)" + }, + "400": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Missing or invalid API key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "413": { + "description": "Storage quota exceeded", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "429": { + "description": "Rate limit exceeded", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ] + } + }, + "/otel/v1/{project_id}/{environment_id}/{deployment_id}/traces": { + "post": { + "tags": [ + "OTel Ingest" + ], + "summary": "Ingest trace spans with project/environment/deployment in the URL path.", + "operationId": "ingest_traces_by_path", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "path", + "description": "Environment ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "deployment_id", + "in": "path", + "description": "Deployment ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "description": "OTLP ExportTraceServiceRequest (protobuf, optionally gzip/zstd compressed)", + "content": { + "application/x-protobuf": { + "schema": { + "type": "string" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Traces accepted (OTLP protobuf response)" + }, + "400": { + "description": "Invalid payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Missing or invalid API key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "413": { + "description": "Storage quota exceeded", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "429": { + "description": "Rate limit exceeded", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ] + } + }, + "/performance/has-metrics": { + "get": { + "tags": [ + "Performance" + ], + "summary": "Check if performance metrics exist for a project", + "operationId": "has_performance_metrics", + "parameters": [ + { + "name": "project_id", + "in": "query", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Successfully checked performance metrics availability", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HasMetricsResponse" + } + } + } + }, + "401": { + "description": "Authentication required", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/performance/metrics": { + "get": { + "tags": [ + "Performance" + ], + "summary": "Get performance metrics", + "operationId": "get_performance_metrics", + "parameters": [ + { + "name": "start_date", + "in": "query", + "description": "Start date in format YYYY-MM-DD HH:MM:SS", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "end_date", + "in": "query", + "description": "End date in format YYYY-MM-DD HH:MM:SS", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "project_id", + "in": "query", + "description": "Project ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Environment ID (optional)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "deployment_id", + "in": "query", + "description": "Deployment ID (optional)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "device_type", + "in": "query", + "description": "Device type filter: desktop or mobile (optional)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "include_bots", + "in": "query", + "description": "Include crawler/datacenter bot samples (default false)", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "name": "filter_path", + "in": "query", + "description": "Filter to one page pathname (optional)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "filter_country", + "in": "query", + "description": "Filter to one country (optional)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "filter_region", + "in": "query", + "description": "Filter to one region (optional)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "filter_city", + "in": "query", + "description": "Filter to one city (optional)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "filter_browser", + "in": "query", + "description": "Filter to one browser (optional)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "filter_operating_system", + "in": "query", + "description": "Filter to one operating system (optional)", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved performance metrics", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PerformanceMetricsResponse" + } + } + } + }, + "400": { + "description": "Invalid date format or missing parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Authentication required", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/performance/metrics-over-time": { + "get": { + "tags": [ + "Performance" + ], + "summary": "Get metrics over time", + "operationId": "get_metrics_over_time", + "parameters": [ + { + "name": "start_date", + "in": "query", + "description": "Start date in format YYYY-MM-DDTHH:MM:SSZ", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "end_date", + "in": "query", + "description": "End date in format YYYY-MM-DDTHH:MM:SSZ", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "project_id", + "in": "query", + "description": "Project ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Environment ID (optional)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "deployment_id", + "in": "query", + "description": "Deployment ID (optional)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "device_type", + "in": "query", + "description": "Device type filter: desktop or mobile (optional)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "include_bots", + "in": "query", + "description": "Include crawler/datacenter bot samples (default false)", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "name": "filter_path", + "in": "query", + "description": "Filter to one page pathname (optional)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "filter_country", + "in": "query", + "description": "Filter to one country (optional)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "filter_region", + "in": "query", + "description": "Filter to one region (optional)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "filter_city", + "in": "query", + "description": "Filter to one city (optional)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "filter_browser", + "in": "query", + "description": "Filter to one browser (optional)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "filter_operating_system", + "in": "query", + "description": "Filter to one operating system (optional)", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved metrics over time", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MetricsOverTimeResponse" + } + } + } + }, + "400": { + "description": "Invalid date format or missing parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Authentication required", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/performance/page-metrics": { + "get": { + "tags": [ + "Performance" + ], + "summary": "Get grouped page metrics", + "operationId": "get_grouped_page_metrics", + "parameters": [ + { + "name": "start_date", + "in": "query", + "description": "Start date in format YYYY-MM-DDTHH:MM:SSZ", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "end_date", + "in": "query", + "description": "End date in format YYYY-MM-DDTHH:MM:SSZ", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "project_id", + "in": "query", + "description": "Project ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Environment ID (optional)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "deployment_id", + "in": "query", + "description": "Deployment ID (optional)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "group_by", + "in": "query", + "description": "Group by: path, country, region, city, device_type, browser, operating_system", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "device_type", + "in": "query", + "description": "Device type filter: desktop or mobile (optional)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "include_bots", + "in": "query", + "description": "Include crawler/datacenter bot samples (default false)", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "name": "filter_path", + "in": "query", + "description": "Filter to one page pathname (optional)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "filter_country", + "in": "query", + "description": "Filter to one country (optional)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "filter_region", + "in": "query", + "description": "Filter to one region (optional)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "filter_city", + "in": "query", + "description": "Filter to one city (optional)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "filter_browser", + "in": "query", + "description": "Filter to one browser (optional)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "filter_operating_system", + "in": "query", + "description": "Filter to one operating system (optional)", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved grouped page metrics", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GroupedPageMetricsResponse" + } + } + } + }, + "400": { + "description": "Invalid date format, missing parameters, or invalid group_by value", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Authentication required", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/platform/access-info": { + "get": { + "tags": [ + "Platform" + ], + "summary": "Get information about how the service is being accessed", + "description": "Returns details about the server's access mode, public IP address, private IP address,\nand domain creation capabilities. Both IP addresses are always included when available.", + "operationId": "get_access_info", + "responses": { + "200": { + "description": "Service access information", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceAccessInfo" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/platform/private-ip": { + "get": { + "tags": [ + "Platform" + ], + "summary": "Get private/local IP address of the server", + "operationId": "get_private_ip", + "responses": { + "200": { + "description": "Successfully retrieved private IP address" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/platform/public-ip": { + "get": { + "tags": [ + "Platform" + ], + "summary": "Get public IP address of the server", + "operationId": "get_public_ip", + "responses": { + "200": { + "description": "Successfully retrieved public IP address" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/presets": { + "get": { + "tags": [ + "Presets" + ], + "summary": "List all available presets", + "operationId": "list_presets", + "responses": { + "200": { + "description": "List of available presets", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListPresetsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/presets/{slug}/dockerfile": { + "post": { + "tags": [ + "Presets" + ], + "summary": "Generate a Dockerfile from a preset", + "description": "Returns the Dockerfile content and build arguments for a given preset slug.\nThe CLI can use this to build Docker images locally without needing a Dockerfile\nin the project directory, enabling zero-config deployments.", + "operationId": "generate_preset_dockerfile", + "parameters": [ + { + "name": "slug", + "in": "path", + "description": "Preset slug (e.g., nextjs, vite, python)", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GenerateDockerfileRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Generated Dockerfile", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GenerateDockerfileResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Preset not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/preview-gateway/logs": { + "get": { + "tags": [ + "Preview Gateway" + ], + "operationId": "get_preview_gateway_logs", + "parameters": [ + { + "name": "tail", + "in": "query", + "description": "Lines to tail (default 200, max 2000)", + "required": false, + "schema": { + "type": "integer", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LogsResponse" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/preview-gateway/restart": { + "post": { + "tags": [ + "Preview Gateway" + ], + "operationId": "restart_preview_gateway", + "responses": { + "204": { + "description": "Gateway restarted" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/preview-gateway/settings": { + "get": { + "tags": [ + "Preview Gateway" + ], + "operationId": "get_preview_gateway_settings", + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PreviewGatewaySettingsResponse" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "patch": { + "tags": [ + "Preview Gateway" + ], + "operationId": "patch_preview_gateway_settings", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PatchSettingsRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PreviewGatewaySettingsResponse" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/preview-gateway/status": { + "get": { + "tags": [ + "Preview Gateway" + ], + "operationId": "get_preview_gateway_status", + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GatewayStatus" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/preview-gateway/upgrade": { + "post": { + "tags": [ + "Preview Gateway" + ], + "operationId": "upgrade_preview_gateway", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpgradeRequest" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Gateway upgraded" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects": { + "get": { + "tags": [ + "Projects" + ], + "summary": "Get a list of all projects", + "operationId": "get_projects", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "Page number (1-based)", + "required": false, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "per_page", + "in": "query", + "description": "Number of items per page", + "required": false, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "List of projects", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PaginatedProjectList" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Projects" + ], + "summary": "Create a new project", + "operationId": "create_project", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateProjectRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Project created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectResponse" + } + } + } + }, + "400": { + "description": "Invalid input" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/by-slug/{slug}": { + "get": { + "tags": [ + "Projects" + ], + "summary": "Get details of a specific project by slug", + "operationId": "get_project_by_slug", + "parameters": [ + { + "name": "slug", + "in": "path", + "description": "Project slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Project details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectResponse" + } + } + } + }, + "404": { + "description": "Project not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/from-template": { + "post": { + "tags": [ + "Projects" + ], + "summary": "Create a new project from a template", + "description": "Creates a new repository from a template and sets up the project with the\nspecified configuration. The template is cloned to a new repository under\nthe authenticated user's account or specified organization.", + "operationId": "create_project_from_template", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateProjectFromTemplateRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Project created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateProjectFromTemplateResponse" + } + } + } + }, + "400": { + "description": "Invalid input" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Template not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/statistics": { + "get": { + "tags": [ + "Projects" + ], + "summary": "Get project statistics", + "operationId": "get_project_statistics", + "responses": { + "200": { + "description": "Project statistics", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectStatisticsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{id}": { + "get": { + "tags": [ + "Projects" + ], + "summary": "Get details of a specific project", + "operationId": "get_project", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Project details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectResponse" + } + } + } + }, + "404": { + "description": "Project not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "put": { + "tags": [ + "Projects" + ], + "operationId": "update_project", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateProjectRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Project updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "Projects" + ], + "operationId": "delete_project", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Project deleted successfully" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{id}/deployments": { + "get": { + "tags": [ + "Projects" + ], + "operationId": "get_project_deployments", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "page", + "in": "query", + "description": "Page number", + "required": false, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "per_page", + "in": "query", + "description": "Items per page", + "required": false, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Environment ID filter", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "List of deployments", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeploymentListResponse" + } + } + } + }, + "404": { + "description": "Project not found" + } + } + } + }, + "/projects/{id}/last-deployment": { + "get": { + "tags": [ + "Deployments" + ], + "summary": "Get the last deployment for a specific project", + "operationId": "get_last_deployment", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Last deployment details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeploymentResponse" + } + } + } + }, + "404": { + "description": "Project not found or no deployments" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{id}/source": { + "patch": { + "tags": [ + "Projects" + ], + "summary": "Change a project's source type to a Git-less type (docker_image /\nstatic_files / manual). Switching TO Git is done via the Git settings\nendpoint (`POST /projects/{id}/git`), which also supplies the repository and\nprovider connection.", + "operationId": "change_project_source", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChangeProjectSourceRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Source type changed", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectResponse" + } + } + } + }, + "400": { + "description": "Invalid source type change (e.g. switching to Git here)" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{id}/trigger-pipeline": { + "post": { + "tags": [ + "Projects" + ], + "summary": "Trigger pipeline for a specific project", + "operationId": "trigger_project_pipeline", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TriggerPipelinePayload" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Pipeline triggered successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TriggerPipelineResponse" + } + } + } + }, + "400": { + "description": "Invalid request" + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/access": { + "get": { + "tags": [ + "Teams" + ], + "operationId": "list_project_access", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Access grants", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProjectAccessResponse" + } + } + } + } + }, + "403": { + "description": "Insufficient permissions or no access to this project" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Teams" + ], + "operationId": "grant_project_access", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateProjectAccessRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Access granted (idempotent upsert)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectAccessResponse" + } + } + } + }, + "403": { + "description": "Insufficient permissions or no access to this project" + }, + "404": { + "description": "Team not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/access/{team_id}": { + "delete": { + "tags": [ + "Teams" + ], + "operationId": "revoke_project_access", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "team_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Access revoked" + }, + "403": { + "description": "Insufficient permissions or no access to this project" + }, + "404": { + "description": "Grant not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/active-visitors": { + "get": { + "tags": [ + "Events" + ], + "summary": "Get active visitors count", + "operationId": "get_active_visitors", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Filter by environment ID", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "deployment_id", + "in": "query", + "description": "Filter by deployment ID", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved active visitors count", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ActiveVisitorsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/agents": { + "get": { + "tags": [ + "Agents" + ], + "operationId": "list_agents", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "List of agents for project", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListAgentsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Agents" + ], + "operationId": "create_agent", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpsertAgentRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Agent created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentConfigResponse" + } + } + } + }, + "400": { + "description": "Validation error" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/agents/cli-status": { + "get": { + "tags": [ + "Agents" + ], + "operationId": "get_cli_status", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "provider", + "in": "query", + "description": "AI provider: claude_cli or codex_cli", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "CLI status" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/agents/runs": { + "get": { + "tags": [ + "Agents" + ], + "operationId": "list_all_runs", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "page", + "in": "query", + "description": "Page number (1-based)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "page_size", + "in": "query", + "description": "Page size (max 100)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "List of all agent runs for a project", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListRunsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/agents/runs/latest-for-source": { + "get": { + "tags": [ + "Agents" + ], + "operationId": "latest_run_for_source", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "trigger_source_type", + "in": "query", + "description": "Trigger source type, e.g. 'error_group'", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "trigger_source_id", + "in": "query", + "description": "Trigger source ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Latest matching run, or null if none", + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/AgentRunResponse" + } + ] + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/agents/runs/{run_id}": { + "get": { + "tags": [ + "Agents" + ], + "operationId": "get_run_with_logs", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "run_id", + "in": "path", + "description": "Run ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Run with logs", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentRunWithLogsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Run not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/agents/runs/{run_id}/cancel": { + "post": { + "tags": [ + "Agents" + ], + "operationId": "cancel_run", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "run_id", + "in": "path", + "description": "Agent run ID to cancel", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Run cancelled", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentRunResponse" + } + } + } + }, + "400": { + "description": "Run is already in a terminal state" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Run not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/agents/runs/{run_id}/retry": { + "post": { + "tags": [ + "Agents" + ], + "summary": "Retry a completed, failed, cancelled, or no_fix run with the same trigger context.\nCreates a new run record and spawns the executor.", + "operationId": "retry_run", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "run_id", + "in": "path", + "description": "Run ID to retry", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "202": { + "description": "New run created from retry", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentRunResponse" + } + } + } + }, + "400": { + "description": "Run is still active" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Run not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/agents/runs/{run_id}/stream": { + "get": { + "tags": [ + "Agents" + ], + "summary": "SSE endpoint for real-time streaming of run events.\nPolls the agent_run_logs table every 500ms for new entries and streams them.\nCloses when the run reaches a terminal status.", + "operationId": "stream_run_events", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "run_id", + "in": "path", + "description": "Agent run ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Server-Sent Events stream of run log events and terminal status", + "content": { + "text/event-stream": {} + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Run not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/agents/sandbox-status": { + "get": { + "tags": [ + "Agents" + ], + "operationId": "get_sandbox_status", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Project-scoped sandbox readiness (Docker + agent image)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxStatusResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/agents/smoke-test": { + "post": { + "tags": [ + "Agents" + ], + "summary": "Run a smoke test to verify the selected AI CLI works in the environment\nwhere agents will actually execute (host or sandbox container). If no\n`provider_id` is supplied the globally active provider is tested.", + "operationId": "smoke_test_agent", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "provider_id", + "in": "query", + "description": "Provider id to test; defaults to the globally active provider", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Smoke test result for the AI CLI in the agent's execution environment", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SmokeTestResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/agents/{slug}": { + "get": { + "tags": [ + "Agents" + ], + "operationId": "get_agent", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "slug", + "in": "path", + "description": "Agent slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Agent config", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentConfigResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Agent not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "put": { + "tags": [ + "Agents" + ], + "operationId": "update_agent", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "slug", + "in": "path", + "description": "Agent slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpsertAgentRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Agent updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentConfigResponse" + } + } + } + }, + "400": { + "description": "Validation error" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Agent not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "Agents" + ], + "operationId": "delete_agent", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "slug", + "in": "path", + "description": "Agent slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Agent deleted" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Agent not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/agents/{slug}/runs": { + "get": { + "tags": [ + "Agents" + ], + "operationId": "list_agent_runs", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "slug", + "in": "path", + "description": "Agent slug", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "page", + "in": "query", + "description": "Page number (1-based)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "page_size", + "in": "query", + "description": "Page size (max 100)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "List of runs for a specific agent", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListRunsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Agent not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/agents/{slug}/trigger": { + "post": { + "tags": [ + "Agents" + ], + "operationId": "trigger_agent", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "slug", + "in": "path", + "description": "Agent slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TriggerAgentRequest" + } + } + }, + "required": true + }, + "responses": { + "202": { + "description": "Agent run created and queued", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentRunResponse" + } + } + } + }, + "400": { + "description": "Validation error" + }, + "401": { + "description": "Unauthorized" + }, + "402": { + "description": "Daily budget exceeded" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Agent not found" + }, + "422": { + "description": "AI CLI not installed" + }, + "429": { + "description": "Cooldown active" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/aggregated-buckets": { + "get": { + "tags": [ + "Events" + ], + "summary": "Get aggregated metrics by time bucket", + "operationId": "get_aggregated_buckets", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "start_date", + "in": "query", + "description": "Start date for the query range", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "end_date", + "in": "query", + "description": "End date for the query range", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Optional environment filter", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "deployment_id", + "in": "query", + "description": "Optional deployment filter", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "aggregation_level", + "in": "query", + "description": "Aggregation level: events, sessions, or visitors (default: events)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "bucket_size", + "in": "query", + "description": "Time bucket size: '1 hour', '1 day', '1 week', etc. (default: '1 hour')", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved aggregated buckets", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AggregatedBucketsResponse" + } + } + } + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/ai/conversations": { + "get": { + "tags": [ + "AI Chat" + ], + "summary": "Find the existing chat for a context (returns `null` if none yet). Requires\nthe per-project `ai_debug_chat_enabled` toggle to be on; returns 403 when the\nfeature is disabled so revoking it consistently hides existing chat content.", + "operationId": "find_conversation", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "context_type", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "context_id", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/ConversationResponse" + } + ] + } + } + } + }, + "401": { + "description": "" + }, + "403": { + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "AI Chat" + ], + "summary": "Get-or-create the chat for a context (seeds it on first open).", + "operationId": "create_conversation", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateConversationRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConversationResponse" + } + } + } + }, + "401": { + "description": "" + }, + "403": { + "description": "" + }, + "404": { + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/ai/conversations/list": { + "get": { + "tags": [ + "AI Chat" + ], + "summary": "List all active conversations for a project, most-recently-active first.\nPowers the conversation switcher in the AI assistant sidebar.", + "operationId": "list_conversations", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ConversationResponse" + } + } + } + } + }, + "401": { + "description": "" + }, + "403": { + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/ai/conversations/{public_id}": { + "get": { + "tags": [ + "AI Chat" + ], + "summary": "Full conversation history (excluding the internal system seed).", + "operationId": "get_conversation", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "public_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConversationDetailResponse" + } + } + } + }, + "401": { + "description": "" + }, + "403": { + "description": "" + }, + "404": { + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "patch": { + "tags": [ + "AI Chat" + ], + "summary": "Rename a conversation (set its human-facing title).", + "operationId": "rename_conversation", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "public_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RenameConversationRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConversationResponse" + } + } + } + }, + "400": { + "description": "" + }, + "401": { + "description": "" + }, + "403": { + "description": "" + }, + "404": { + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/ai/conversations/{public_id}/archive": { + "post": { + "tags": [ + "AI Chat" + ], + "summary": "Archive (soft-delete) a conversation.", + "operationId": "archive_conversation", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "public_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "" + }, + "401": { + "description": "" + }, + "403": { + "description": "" + }, + "404": { + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/ai/conversations/{public_id}/messages": { + "post": { + "tags": [ + "AI Chat" + ], + "summary": "Send a user message; stream the assistant reply as Server-Sent Events.", + "operationId": "send_message", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "public_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SendMessageRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "SSE stream of assistant text deltas", + "content": { + "text/event-stream": {} + } + }, + "401": { + "description": "" + }, + "403": { + "description": "" + }, + "404": { + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/ai/conversations/{public_id}/pending-actions": { + "get": { + "tags": [ + "AI Chat" + ], + "summary": "List all pending actions for a conversation (most-recently-proposed first).", + "operationId": "list_pending_actions", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "public_id", + "in": "path", + "description": "Conversation public id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PendingActionResponse" + } + } + } + } + }, + "401": { + "description": "" + }, + "403": { + "description": "" + }, + "404": { + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/ai/pending-actions/{action_public_id}": { + "get": { + "tags": [ + "AI Chat" + ], + "summary": "Get a single pending action by its public id (scoped to the project).", + "operationId": "get_pending_action", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "action_public_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PendingActionResponse" + } + } + } + }, + "401": { + "description": "" + }, + "403": { + "description": "" + }, + "404": { + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/ai/pending-actions/{action_public_id}/confirm": { + "post": { + "tags": [ + "AI Chat" + ], + "summary": "Confirm a proposed AI action: validate permission, atomically claim, execute,\npersist outcome. The execution uses the CONFIRMING user's auth \u2014 never the model's.", + "operationId": "confirm_pending_action", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "action_public_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PendingActionResponse" + } + } + } + }, + "401": { + "description": "" + }, + "403": { + "description": "" + }, + "404": { + "description": "" + }, + "409": { + "description": "" + }, + "503": { + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/ai/pending-actions/{action_public_id}/reject": { + "post": { + "tags": [ + "AI Chat" + ], + "summary": "Reject a proposed AI action (no execution). Status transitions to \"rejected\".", + "operationId": "reject_pending_action", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "action_public_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PendingActionResponse" + } + } + } + }, + "401": { + "description": "" + }, + "403": { + "description": "" + }, + "404": { + "description": "" + }, + "409": { + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/ai/readiness": { + "get": { + "tags": [ + "AI Chat" + ], + "summary": "Report which AI prerequisites this project satisfies.", + "description": "Read-only and cheap, so the UI can decide up front whether to show a working\nentry point, an onboarding path, or nothing \u2014 instead of letting the user\nclick something that fails with a 409 they can't act on.", + "operationId": "get_chat_readiness", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Which AI prerequisites are met", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChatReadinessResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Project not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/alarms": { + "get": { + "tags": [ + "Alarms" + ], + "summary": "List alarms for a project with optional filters.", + "operationId": "listProjectAlarms", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "alarm_type", + "in": "query", + "description": "Filter by alarm type (e.g. `container_restart`, `outage`).", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "status", + "in": "query", + "description": "Filter by status: `firing`, `acknowledged`, or `resolved`.", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "severity", + "in": "query", + "description": "Filter by severity: `info`, `warning`, or `critical`.", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Filter by environment ID.", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + }, + { + "name": "deployment_id", + "in": "query", + "description": "Filter by deployment ID.", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + }, + { + "name": "service_id", + "in": "query", + "description": "Filter by external service ID.", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + }, + { + "name": "page", + "in": "query", + "description": "Page number (1-based, default 1).", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + } + }, + { + "name": "page_size", + "in": "query", + "description": "Items per page (default 20, max 100).", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "Paginated list of alarms", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AlarmListResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/alarms/summary": { + "get": { + "tags": [ + "Alarms" + ], + "summary": "Get alarm counts by status/severity/type for a project (dashboard summary widget).", + "operationId": "getProjectAlarmsSummary", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Alarm summary counts", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AlarmSummaryResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/alarms/{alarm_id}/acknowledge": { + "post": { + "tags": [ + "Alarms" + ], + "summary": "Acknowledge a firing alarm (marks it as seen but not resolved).", + "operationId": "acknowledgeAlarm", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "alarm_id", + "in": "path", + "description": "Alarm ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Alarm acknowledged" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Alarm not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/alarms/{alarm_id}/resolve": { + "post": { + "tags": [ + "Alarms" + ], + "summary": "Resolve an alarm.", + "operationId": "resolveAlarm", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "alarm_id", + "in": "path", + "description": "Alarm ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Alarm resolved" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Alarm not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/autofixer/analyze": { + "post": { + "tags": [ + "Autofixer" + ], + "summary": "Start an autofixer analysis run for the given error group.\nCreates the run record immediately and spawns analysis in the background.", + "operationId": "start_analysis", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StartAnalysisRequest" + } + } + }, + "required": true + }, + "responses": { + "202": { + "description": "Analysis started; returns run_id for streaming", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AutofixerRunResponse" + } + } + } + }, + "400": { + "description": "Validation error" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/autofixer/runs/{run_id}": { + "get": { + "tags": [ + "Autofixer" + ], + "summary": "Get a single autofixer run with its logs.", + "operationId": "get_run", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "run_id", + "in": "path", + "description": "Run ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Run with logs", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AutofixerRunWithLogsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Run not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/autofixer/runs/{run_id}/add-context": { + "post": { + "tags": [ + "Autofixer" + ], + "summary": "Append a user message to the run's context field.", + "operationId": "add_context", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "run_id", + "in": "path", + "description": "Run ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddContextRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Context appended" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Run not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/autofixer/runs/{run_id}/cancel": { + "post": { + "tags": [ + "Autofixer" + ], + "summary": "Cancel an autofixer run and clean up the work directory.", + "operationId": "cancel", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "run_id", + "in": "path", + "description": "Run ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Run cancelled" + }, + "400": { + "description": "Run is already in a terminal state" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Run not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/autofixer/runs/{run_id}/create-pr": { + "post": { + "tags": [ + "Autofixer" + ], + "summary": "Push the fix branch and create a pull request.\nRequires phase == \"fix_ready\".", + "operationId": "create_pr", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "run_id", + "in": "path", + "description": "Run ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "201": { + "description": "PR created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreatePrResponse" + } + } + } + }, + "400": { + "description": "Run not in fix_ready phase" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Run not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/autofixer/runs/{run_id}/fix": { + "post": { + "tags": [ + "Autofixer" + ], + "summary": "Transition from analysis to fix phase.\nRequires phase == \"analyzed\".", + "operationId": "start_fix", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "run_id", + "in": "path", + "description": "Run ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "202": { + "description": "Fix generation started" + }, + "400": { + "description": "Run not in analyzed phase" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Run not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/autofixer/runs/{run_id}/re-analyze": { + "post": { + "tags": [ + "Autofixer" + ], + "summary": "Continue the conversation with user feedback.\nUses the same Claude session (--continue) in the existing work directory.\nRequires phase == \"analyzed\".", + "operationId": "re_analyze", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "run_id", + "in": "path", + "description": "Run ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "202": { + "description": "Conversation continued with feedback" + }, + "400": { + "description": "Run not in analyzed phase" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Run not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/autofixer/runs/{run_id}/stream": { + "get": { + "tags": [ + "Agents" + ], + "summary": "SSE endpoint: streams run log events in real-time.\nPolls every 500 ms. Keeps the connection open through \"analyzed\" and \"fix_ready\"\nwaiting states; closes only on terminal statuses.", + "operationId": "stream_events", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "run_id", + "in": "path", + "description": "Autofixer run ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Server-Sent Events stream of autofixer run logs and status updates", + "content": { + "text/event-stream": {} + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Run not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/automatic-deploy": { + "post": { + "tags": [ + "Projects" + ], + "summary": "Update automatic deployment setting for a project", + "operationId": "update_automatic_deploy", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateAutomaticDeployRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Automatic deployment setting updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/custom-domains": { + "get": { + "tags": [ + "Custom Domains" + ], + "summary": "List all custom domains for a project", + "operationId": "list_custom_domains_for_project", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Custom domains retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListCustomDomainsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Custom Domains" + ], + "summary": "Create a custom domain for a project", + "operationId": "create_custom_domain", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomDomainRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Custom domain created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomDomainResponse" + } + } + } + }, + "400": { + "description": "Invalid input" + }, + "401": { + "description": "Unauthorized" + }, + "409": { + "description": "Domain already exists" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/custom-domains/{domain_id}": { + "get": { + "tags": [ + "Custom Domains" + ], + "summary": "Get a custom domain by ID", + "operationId": "get_custom_domain", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "domain_id", + "in": "path", + "description": "Custom domain ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Custom domain retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomDomainResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Custom domain not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "put": { + "tags": [ + "Custom Domains" + ], + "summary": "Update a custom domain", + "operationId": "update_custom_domain", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "domain_id", + "in": "path", + "description": "Custom domain ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateCustomDomainRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Custom domain updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomDomainResponse" + } + } + } + }, + "400": { + "description": "Invalid input" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Custom domain not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "Custom Domains" + ], + "summary": "Delete a custom domain", + "operationId": "delete_custom_domain", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "domain_id", + "in": "path", + "description": "Custom domain ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Custom domain deleted successfully" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Custom domain not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/custom-domains/{domain_id}/link-certificate/{certificate_id}": { + "post": { + "tags": [ + "Custom Domains" + ], + "summary": "Link a custom domain to a certificate", + "operationId": "link_custom_domain_to_certificate", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "domain_id", + "in": "path", + "description": "Custom domain ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "certificate_id", + "in": "path", + "description": "Certificate ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Custom domain linked to certificate successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomDomainResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Custom domain or certificate not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/deployment-config": { + "patch": { + "tags": [ + "Projects" + ], + "summary": "Update deployment configuration for a project", + "operationId": "update_project_deployment_config", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateDeploymentConfigRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Deployment configuration updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectResponse" + } + } + } + }, + "400": { + "description": "Invalid deployment configuration" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/deployment-tokens": { + "get": { + "tags": [ + "Deployment Tokens" + ], + "summary": "List all deployment tokens for a project", + "operationId": "list_deployment_tokens", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "page", + "in": "query", + "description": "Page number (default: 1)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "page_size", + "in": "query", + "description": "Page size (default: 20, max: 100)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "List of deployment tokens", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeploymentTokenListResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Deployment Tokens" + ], + "summary": "Create a new deployment token for a project", + "operationId": "create_deployment_token", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateDeploymentTokenRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Deployment token created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateDeploymentTokenResponse" + } + } + } + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "409": { + "description": "Token with this name already exists" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/deployment-tokens/{token_id}": { + "get": { + "tags": [ + "Deployment Tokens" + ], + "summary": "Get a specific deployment token", + "operationId": "get_deployment_token", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "token_id", + "in": "path", + "description": "Deployment token ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Deployment token details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeploymentTokenResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Deployment token not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "Deployment Tokens" + ], + "summary": "Delete a deployment token", + "operationId": "delete_deployment_token", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "token_id", + "in": "path", + "description": "Deployment token ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Deployment token deleted successfully" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Deployment token not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "patch": { + "tags": [ + "Deployment Tokens" + ], + "summary": "Update a deployment token", + "operationId": "update_deployment_token", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "token_id", + "in": "path", + "description": "Deployment token ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateDeploymentTokenRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Deployment token updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeploymentTokenResponse" + } + } + } + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Deployment token not found" + }, + "409": { + "description": "Token with this name already exists" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/deployment-tokens/{token_id}/rotate": { + "post": { + "tags": [ + "Deployment Tokens" + ], + "summary": "Rotate a deployment token, invalidating its old secret and issuing a new one", + "operationId": "rotate_deployment_token", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "token_id", + "in": "path", + "description": "Deployment token ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Deployment token rotated successfully; the response contains the new plaintext token, shown only once", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateDeploymentTokenResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Deployment token not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/deployments/{deployment_id}": { + "get": { + "tags": [ + "Deployments" + ], + "summary": "Get a specific deployment by ID for a project (identified by ID or slug)", + "operationId": "get_deployment", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "deployment_id", + "in": "path", + "description": "Deployment ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Deployment details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeploymentResponse" + } + } + } + }, + "404": { + "description": "Project or deployment not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/deployments/{deployment_id}/cancel": { + "post": { + "tags": [ + "Projects" + ], + "summary": "Cancel a deployment", + "operationId": "cancel_deployment", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "deployment_id", + "in": "path", + "description": "Deployment ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Deployment cancelled successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeploymentStateResponse" + } + } + } + }, + "400": { + "description": "Deployment cannot be cancelled (already completed, failed, or cancelled)" + }, + "404": { + "description": "Project or deployment not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/deployments/{deployment_id}/container-logs": { + "get": { + "tags": [ + "Deployments" + ], + "summary": "List the captured (historical) container-log dumps for a deployment.", + "description": "Container runtime logs are normally only available live from the running\ncontainer. When a deployment is superseded its containers are torn down and\nthose logs would be lost \u2014 so just before teardown we capture each\ncontainer's logs to durable storage. This endpoint lists what was captured\nfor a given (often older) deployment, so a user can read the logs of a\ncontainer that no longer exists.", + "operationId": "list_deployment_container_logs", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "deployment_id", + "in": "path", + "description": "Deployment ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Captured container logs for the deployment", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeploymentContainerLogsListResponse" + } + } + } + }, + "404": { + "description": "Deployment not found in this project" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_token": [] + } + ] + } + }, + "/projects/{project_id}/deployments/{deployment_id}/container-logs/{log_id}": { + "get": { + "tags": [ + "Deployments" + ], + "summary": "Get the captured text content of a single historical container-log dump.", + "operationId": "get_deployment_container_log_content", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "deployment_id", + "in": "path", + "description": "Deployment ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "log_id", + "in": "path", + "description": "Captured log ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Captured container log content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeploymentContainerLogContentResponse" + } + } + } + }, + "404": { + "description": "Captured log not found in this project" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_token": [] + } + ] + } + }, + "/projects/{project_id}/deployments/{deployment_id}/jobs": { + "get": { + "tags": [ + "Deployments" + ], + "summary": "Get jobs for a specific deployment", + "description": "Returns all jobs (workflow tasks) for a deployment, ordered by execution order.\nThis replaces the old deployment stages endpoint.", + "operationId": "get_deployment_jobs", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "deployment_id", + "in": "path", + "description": "Deployment ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Jobs retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeploymentJobsResponse" + } + } + } + }, + "404": { + "description": "Deployment not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/deployments/{deployment_id}/jobs/{job_id}/logs": { + "get": { + "tags": [ + "Deployments" + ], + "summary": "Get logs for a specific deployment job", + "operationId": "get_deployment_job_logs", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "deployment_id", + "in": "path", + "description": "Deployment ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "job_id", + "in": "path", + "description": "Job ID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Job logs retrieved successfully", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "404": { + "description": "Job or logs not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_token": [] + } + ] + } + }, + "/projects/{project_id}/deployments/{deployment_id}/jobs/{job_id}/logs/tail": { + "get": { + "tags": [ + "Deployments" + ], + "summary": "Tail logs for a specific deployment job in real-time via WebSocket", + "description": "**WebSocket Streaming**: Logs are sent as raw text, one line per WebSocket message.\n\n**Authentication**: Requires authentication via session cookie (browser clients)\nor API key (API clients). For browser-based WebSocket connections, ensure the user\nis logged in - the browser automatically includes session cookies in the WebSocket\nupgrade request.\n\n**API Client Authentication**: Include API key in Authorization header:\n```text\nAuthorization: Bearer tk_your_api_key_here\n```", + "operationId": "tail_deployment_job_logs", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "deployment_id", + "in": "path", + "description": "Deployment ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "job_id", + "in": "path", + "description": "Job ID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "101": { + "description": "WebSocket connection established for streaming deployment job logs" + }, + "404": { + "description": "Job or logs not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_token": [] + } + ] + } + }, + "/projects/{project_id}/deployments/{deployment_id}/operations": { + "get": { + "tags": [ + "Deployments" + ], + "summary": "Get all operations for a deployment", + "operationId": "get_deployment_operations", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "deployment_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "List of operations", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OperationResultsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Deployment not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Deployments" + ], + "summary": "Execute a deployment operation (deploy, mark_complete, take_screenshot)", + "operationId": "execute_deployment_operation", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "deployment_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExecuteOperationRequest" + } + } + }, + "required": true + }, + "responses": { + "202": { + "description": "Operation executed", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OperationResultResponse" + } + } + } + }, + "400": { + "description": "Invalid operation" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Deployment not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/deployments/{deployment_id}/operations/{operation_type}": { + "get": { + "tags": [ + "Deployments" + ], + "summary": "Get the status of a specific operation type", + "operationId": "get_deployment_operation_status", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "deployment_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "operation_type", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Operation status", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OperationResultResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Operation not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/deployments/{deployment_id}/pause": { + "post": { + "tags": [ + "Projects" + ], + "summary": "Pause a deployment", + "operationId": "pause_deployment", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "deployment_id", + "in": "path", + "description": "Deployment ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Deployment paused successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeploymentStateResponse" + } + } + } + }, + "404": { + "description": "Project or deployment not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/deployments/{deployment_id}/promote": { + "post": { + "tags": [ + "Deployments" + ], + "summary": "Promote a deployment to another environment", + "description": "Creates a new deployment in the target environment using the source deployment's\nDocker image. Useful for promoting a validated preview/staging deployment to production.", + "operationId": "promote_deployment", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "deployment_id", + "in": "path", + "description": "Source deployment ID to promote", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PromoteDeploymentRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Promotion initiated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeploymentResponse" + } + } + } + }, + "400": { + "description": "Invalid deployment state for promotion" + }, + "404": { + "description": "Project, deployment, or target environment not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/deployments/{deployment_id}/resume": { + "post": { + "tags": [ + "Projects" + ], + "summary": "Resume a deployment", + "operationId": "resume_deployment", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "deployment_id", + "in": "path", + "description": "Deployment ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Deployment resumed successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeploymentStateResponse" + } + } + } + }, + "404": { + "description": "Project or deployment not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/deployments/{deployment_id}/rollback": { + "post": { + "tags": [ + "Projects" + ], + "operationId": "rollback_to_deployment", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "deployment_id", + "in": "path", + "description": "Deployment ID to rollback to", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Rollback initiated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeploymentResponse" + } + } + } + }, + "404": { + "description": "Project or deployment not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/deployments/{deployment_id}/teardown": { + "delete": { + "tags": [ + "Projects" + ], + "summary": "Teardown a specific deployment", + "operationId": "teardown_deployment", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "deployment_id", + "in": "path", + "description": "Deployment ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Deployment torn down successfully" + }, + "404": { + "description": "Project or deployment not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/dsns": { + "get": { + "tags": [], + "summary": "List all DSNs for a project", + "operationId": "list_dsns", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "List of DSNs", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProjectDSNResponse" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [], + "summary": "Create a new DSN for a project", + "operationId": "create_dsn", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateDSNRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "DSN created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectDSNResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Project not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/dsns/get-or-create": { + "post": { + "tags": [], + "summary": "Get or create DSN for a project/environment/deployment combination", + "operationId": "get_or_create_dsn", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetOrCreateDSNRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "DSN retrieved or created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectDSNResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Project not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/dsns/{dsn_id}/regenerate": { + "post": { + "tags": [], + "summary": "Regenerate DSN keys (rotate keys)", + "operationId": "regenerate_dsn", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "dsn_id", + "in": "path", + "description": "DSN ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegenerateDSNRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "DSN keys regenerated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectDSNResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "DSN not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/dsns/{dsn_id}/revoke": { + "post": { + "tags": [], + "summary": "Revoke (deactivate) a DSN", + "operationId": "revoke_dsn", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "dsn_id", + "in": "path", + "description": "DSN ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "DSN revoked" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "DSN not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/env-vars": { + "get": { + "tags": [ + "Projects" + ], + "summary": "Get environment variables for a project, optionally filtered by environment", + "operationId": "get_environment_variables", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Optional environment ID to filter by", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "List of environment variables", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EnvironmentVariableResponse" + } + } + } + } + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + } + }, + "post": { + "tags": [ + "Projects" + ], + "summary": "Create a new environment variable", + "operationId": "create_environment_variable", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateEnvironmentVariableRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Environment variables created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnvironmentVariableResponse" + } + } + } + }, + "400": { + "description": "Invalid input" + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/env-vars/resolved": { + "get": { + "tags": [ + "Projects" + ], + "summary": "Resolved env vars for a project (manual + integration-sourced, merged).", + "description": "Returns the effective set of environment variables a deployment would see,\ncombining manually-defined vars with those contributed by linked external\nservices (Postgres, Redis, S3, etc.). Each entry is tagged with its source\nso the UI can render an integration icon, and manual entries that shadow an\nintegration key carry a reference to the integration they override.\n\nValues are always returned as a masked preview. Use the per-key reveal\nendpoint for plaintext (audit-logged).", + "operationId": "get_resolved_environment_variables", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Optional environment ID to filter manual vars by", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Resolved environment variables", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ResolvedEnvVarResponse" + } + } + } + } + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/env-vars/resolved/{key}/value": { + "get": { + "tags": [ + "Projects" + ], + "summary": "Reveal the plaintext value of a resolved environment variable.", + "description": "Mirrors `GET /projects/{id}/env-vars/{key}/value` but handles keys sourced\nfrom linked integrations (which are not stored in the `env_vars` table).\nResolution order mirrors the merged view:\n\n1. Manual env var with this key \u2014 this endpoint reads the manual store when\n the key exists there, then writes its own reveal audit event so callers\n can safely use one endpoint regardless of source.\n2. Integration env var supplied by a linked external service.\n\nReturns 404 when neither a manual var nor an integration produces the key.", + "operationId": "get_resolved_environment_variable_value", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "key", + "in": "path", + "description": "Environment variable key", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Optional environment ID", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "var_id", + "in": "query", + "description": "Exact manual environment-variable row ID", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "service_id", + "in": "query", + "description": "Integration service ID shown by the resolved list", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Resolved environment variable value", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnvironmentVariableValueResponse" + } + } + } + }, + "403": { + "description": "Plaintext secret access is not permitted" + }, + "404": { + "description": "Project, key, or integration not found" + }, + "409": { + "description": "Environment variable key is ambiguous" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/env-vars/{key}/value": { + "get": { + "tags": [ + "Projects" + ], + "summary": "Get environment variable value by key", + "operationId": "get_environment_variable_value", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "key", + "in": "path", + "description": "Environment variable key", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Optional environment ID", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "var_id", + "in": "query", + "description": "Exact environment-variable row ID", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Environment variable value", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnvironmentVariableValueResponse" + } + } + } + }, + "403": { + "description": "Plaintext secret access is not permitted" + }, + "404": { + "description": "Project or variable not found" + }, + "409": { + "description": "Environment variable key is ambiguous" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/env-vars/{var_id}": { + "put": { + "tags": [ + "Projects" + ], + "summary": "Update an environment variable", + "operationId": "update_environment_variable", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "var_id", + "in": "path", + "description": "Environment variable ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateEnvironmentVariableRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Environment variables updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnvironmentVariableResponse" + } + } + } + }, + "400": { + "description": "Invalid input" + }, + "404": { + "description": "Project or variable not found" + }, + "500": { + "description": "Internal server error" + } + } + }, + "delete": { + "tags": [ + "Projects" + ], + "summary": "Delete an environment variable", + "operationId": "delete_environment_variable", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "var_id", + "in": "path", + "description": "Environment variable ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Environment variable deleted successfully" + }, + "404": { + "description": "Project or variable not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/environments": { + "get": { + "tags": [ + "Projects" + ], + "summary": "Get all environments for a project", + "operationId": "get_environments", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "List of environments", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EnvironmentResponse" + } + } + } + } + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + } + }, + "post": { + "tags": [ + "Projects" + ], + "summary": "Create a new environment for a project", + "operationId": "create_environment", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateEnvironmentRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Environment created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnvironmentResponse" + } + } + } + }, + "400": { + "description": "Invalid input" + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/environments/{env_id}": { + "get": { + "tags": [ + "Projects" + ], + "summary": "Get a specific environment by ID or slug", + "operationId": "get_environment", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "env_id", + "in": "path", + "description": "Environment ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Environment details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnvironmentResponse" + } + } + } + }, + "404": { + "description": "Project or environment not found" + }, + "500": { + "description": "Internal server error" + } + } + }, + "delete": { + "tags": [ + "Projects" + ], + "summary": "Delete an environment permanently", + "description": "Permanently deletes an environment and all related data. Cannot delete:\n- Production environments (name = \"Production\")\n\nWarning: This action is permanent and cannot be undone.\nActive deployments are automatically cancelled before deletion.", + "operationId": "delete_environment", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "env_id", + "in": "path", + "description": "Environment ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Environment permanently deleted" + }, + "400": { + "description": "Cannot delete production environment" + }, + "404": { + "description": "Project or environment not found" + }, + "428": { + "description": "Recent MFA verification required" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/environments/{env_id}/crons": { + "get": { + "tags": [ + "Crons" + ], + "operationId": "get_environment_crons", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "env_id", + "in": "path", + "description": "Environment ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "List of cron jobs", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CronInfo" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/environments/{env_id}/crons/{cron_id}": { + "get": { + "tags": [ + "Crons" + ], + "operationId": "get_cron_by_id", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "env_id", + "in": "path", + "description": "Environment ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "cron_id", + "in": "path", + "description": "Cron Job ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Cron job details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CronInfo" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Cron job not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/environments/{env_id}/crons/{cron_id}/executions": { + "get": { + "tags": [ + "Crons" + ], + "operationId": "get_cron_executions", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "env_id", + "in": "path", + "description": "Environment ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "cron_id", + "in": "path", + "description": "Cron Job ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "page", + "in": "query", + "description": "Page number (default: 1)", + "required": false, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "per_page", + "in": "query", + "description": "Items per page (default: 20)", + "required": false, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "List of cron job executions", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CronExecutionInfo" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Cron job not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/environments/{env_id}/domains": { + "get": { + "tags": [ + "Projects" + ], + "summary": "Get all environment domains for a specific environment", + "operationId": "get_environment_domains", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "env_id", + "in": "path", + "description": "Environment ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "List of environment domains", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EnvironmentDomainResponse" + } + } + } + } + }, + "404": { + "description": "Project or environment not found" + }, + "500": { + "description": "Internal server error" + } + } + }, + "post": { + "tags": [ + "Projects" + ], + "summary": "Add a new environment domain", + "operationId": "add_environment_domain", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "env_id", + "in": "path", + "description": "Environment ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddEnvironmentDomainRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Domain added successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnvironmentDomainResponse" + } + } + } + }, + "400": { + "description": "Invalid input" + }, + "404": { + "description": "Project or environment not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/environments/{env_id}/domains/{domain_id}": { + "delete": { + "tags": [ + "Projects" + ], + "summary": "Delete an environment domain", + "operationId": "delete_environment_domain", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "env_id", + "in": "path", + "description": "Environment ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "domain_id", + "in": "path", + "description": "Domain ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Domain deleted successfully" + }, + "404": { + "description": "Project, environment, or domain not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/environments/{env_id}/settings": { + "put": { + "tags": [ + "Projects" + ], + "summary": "Update environment settings", + "operationId": "update_environment_settings", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "env_id", + "in": "path", + "description": "Environment ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateEnvironmentSettingsRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Environment settings updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnvironmentResponse" + } + } + } + }, + "404": { + "description": "Project or environment not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/environments/{env_id}/sleep": { + "post": { + "tags": [ + "Environments" + ], + "summary": "Sleep an on-demand environment", + "description": "Manually put an on-demand environment to sleep. Stops containers and sets\n`sleeping = true`. If no OnDemandWaker is available, falls back to DB flag only.", + "operationId": "sleep_environment", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "env_id", + "in": "path", + "description": "Environment ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Environment put to sleep", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnvironmentResponse" + } + } + } + }, + "400": { + "description": "On-demand not enabled for this environment" + }, + "404": { + "description": "Environment not found" + }, + "429": { + "description": "Too many state transitions, retry after cooldown" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/environments/{env_id}/subdomain": { + "patch": { + "tags": [ + "Projects" + ], + "summary": "Rename the auto-managed subdomain for an environment.", + "description": "Replaces the environment's previous subdomain entirely \u2014 the old\nhostname stops resolving once the proxy reloads its route table.\nCustom domains attached to the environment are unaffected.", + "operationId": "update_environment_subdomain", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "env_id", + "in": "path", + "description": "Environment ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateEnvironmentSubdomainRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Subdomain updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnvironmentResponse" + } + } + } + }, + "400": { + "description": "Invalid subdomain or conflict with another environment" + }, + "404": { + "description": "Project or environment not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/environments/{env_id}/teardown": { + "delete": { + "tags": [ + "Projects" + ], + "summary": "Teardown an environment and all its active deployments", + "operationId": "teardown_environment", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "env_id", + "in": "path", + "description": "Environment ID or slug", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Environment torn down successfully" + }, + "404": { + "description": "Project or environment not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/environments/{env_id}/wake": { + "post": { + "tags": [ + "Environments" + ], + "summary": "Wake a sleeping on-demand environment", + "description": "Manually wake an environment that has been put to sleep by the on-demand\nidle timeout. Starts containers, waits for health checks, then sets\n`sleeping = false`. If no OnDemandWaker is available (proxy not running\nin same process), falls back to setting the DB flag only.", + "operationId": "wake_environment", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "env_id", + "in": "path", + "description": "Environment ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Environment woken up", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnvironmentResponse" + } + } + } + }, + "400": { + "description": "On-demand not enabled for this environment" + }, + "404": { + "description": "Environment not found" + }, + "429": { + "description": "Too many state transitions, retry after cooldown" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/environments/{environment_id}/container-logs": { + "get": { + "tags": [ + "Deployments" + ], + "summary": "Get logs for a container in an environment via WebSocket", + "operationId": "get_container_logs", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "path", + "description": "Environment ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "start_date", + "in": "query", + "description": "Start date for logs", + "required": false, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "end_date", + "in": "query", + "description": "End date for logs", + "required": false, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "tail", + "in": "query", + "description": "Number of lines to tail (or 'all')", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "container_name", + "in": "query", + "description": "Optional container name (defaults to first/primary container)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "timestamps", + "in": "query", + "description": "Include timestamps in log output (default: false)", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "name": "follow", + "in": "query", + "description": "Follow log output in real-time (default: true)", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "101": { + "description": "WebSocket connection established for streaming container logs" + }, + "400": { + "description": "Not a server-type project" + }, + "404": { + "description": "Project, deployment, or container not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/environments/{environment_id}/containers": { + "get": { + "tags": [ + "Deployments" + ], + "summary": "List all containers for an environment", + "operationId": "list_containers", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "path", + "description": "Environment ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "List of containers", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContainerListResponse" + } + } + } + }, + "400": { + "description": "Not a server-type project" + }, + "404": { + "description": "Project or environment not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/environments/{environment_id}/containers/{container_id}": { + "get": { + "tags": [ + "Containers" + ], + "summary": "Get detailed information about a specific container", + "operationId": "get_container_detail", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "path", + "description": "Environment ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "container_id", + "in": "path", + "description": "Container ID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Container details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContainerDetailResponse" + } + } + } + }, + "404": { + "description": "Container not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/environments/{environment_id}/containers/{container_id}/environment/{variable_name}": { + "get": { + "tags": [ + "Containers" + ], + "operationId": "get_container_environment_variable", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "path", + "description": "Environment ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "container_id", + "in": "path", + "description": "Container ID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "variable_name", + "in": "path", + "description": "Environment variable name", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Environment variable value", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContainerEnvironmentVariableValueResponse" + } + } + } + }, + "403": { + "description": "Plaintext secret access is not permitted" + }, + "404": { + "description": "Container or environment variable not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/environments/{environment_id}/containers/{container_id}/logs": { + "get": { + "tags": [ + "Deployments" + ], + "summary": "Get logs for a specific container by container ID via WebSocket", + "operationId": "get_container_logs_by_id", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "path", + "description": "Environment ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "container_id", + "in": "path", + "description": "Container ID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "start_date", + "in": "query", + "description": "Start date for logs", + "required": false, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "end_date", + "in": "query", + "description": "End date for logs", + "required": false, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "tail", + "in": "query", + "description": "Number of lines to tail (or 'all')", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "timestamps", + "in": "query", + "description": "Include timestamps in log output (default: false)", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "name": "follow", + "in": "query", + "description": "Follow log output in real-time (default: true)", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "101": { + "description": "WebSocket connection established for streaming container logs" + }, + "400": { + "description": "Not a server-type project" + }, + "404": { + "description": "Project, environment, or container not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/environments/{environment_id}/containers/{container_id}/metrics": { + "get": { + "tags": [ + "Containers" + ], + "summary": "Get metrics/stats for a specific container", + "operationId": "get_container_metrics", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "path", + "description": "Environment ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "container_id", + "in": "path", + "description": "Container ID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Container metrics retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContainerMetricsResponse" + } + } + } + }, + "404": { + "description": "Container not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/environments/{environment_id}/containers/{container_id}/metrics/history": { + "get": { + "tags": [ + "Containers" + ], + "summary": "Fetch a time-series range for a single container resource metric\n(recorded by the container health monitor every ~30s).", + "description": "Useful metric names: `container.cpu_percent`,\n`container.cpu_utilization_percent`, `container.memory_used_bytes`,\n`container.memory_percent`, `container.network_rx_bytes_delta`,\n`container.network_tx_bytes_delta`.", + "operationId": "ContainerMetricsGetHistory", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "path", + "description": "Environment ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "container_id", + "in": "path", + "description": "Container ID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "metric", + "in": "query", + "description": "Dotted metric name, e.g. `container.cpu_percent` or\n`container.memory_used_bytes`.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "range", + "in": "query", + "description": "Time window: `1h`, `6h`, `24h`, or `7d` (defaults to `1h`).", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Metric time series data points", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ContainerMetricHistoryPoint" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Container not found" + }, + "500": { + "description": "Internal server error" + }, + "503": { + "description": "Metrics store not available" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/environments/{environment_id}/containers/{container_id}/metrics/stream": { + "get": { + "tags": [ + "Containers" + ], + "summary": "Stream container metrics via Server-Sent Events (SSE)", + "operationId": "stream_container_metrics", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "path", + "description": "Environment ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "container_id", + "in": "path", + "description": "Container ID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "interval", + "in": "query", + "description": "Update interval in milliseconds (default: 1000)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "Metrics stream established (Server-Sent Events)" + }, + "404": { + "description": "Container not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/environments/{environment_id}/containers/{container_id}/restart": { + "post": { + "tags": [ + "Containers" + ], + "summary": "Restart a container", + "operationId": "restart_container", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "path", + "description": "Environment ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "container_id", + "in": "path", + "description": "Container ID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Container restarted successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContainerActionResponse" + } + } + } + }, + "404": { + "description": "Container not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/environments/{environment_id}/containers/{container_id}/start": { + "post": { + "tags": [ + "Containers" + ], + "summary": "Start a container", + "operationId": "start_container", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "path", + "description": "Environment ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "container_id", + "in": "path", + "description": "Container ID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Container started successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContainerActionResponse" + } + } + } + }, + "404": { + "description": "Container not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/environments/{environment_id}/containers/{container_id}/stop": { + "post": { + "tags": [ + "Containers" + ], + "summary": "Stop a specific container", + "operationId": "stop_container", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "path", + "description": "Environment ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "container_id", + "in": "path", + "description": "Container ID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Container stopped successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContainerActionResponse" + } + } + } + }, + "404": { + "description": "Container not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/environments/{environment_id}/deploy/image": { + "post": { + "tags": [ + "Deployments" + ], + "summary": "Deploy from an external Docker image", + "description": "Triggers a deployment using a pre-built Docker image from an external registry.\nThe image will be pulled and deployed to the specified environment.", + "operationId": "deploy_from_image", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeployFromImageRequest" + } + } + }, + "required": true + }, + "responses": { + "202": { + "description": "Deployment started", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RemoteDeploymentResponse" + } + } + } + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Project or environment not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/environments/{environment_id}/deploy/image-upload": { + "post": { + "tags": [ + "Deployments" + ], + "summary": "Deploy from an uploaded Docker image tarball", + "description": "Uploads a Docker image tarball (from `docker save`) and deploys it directly.\nThe image is imported using `docker load` and then deployed to the specified environment.\nThis is useful when you want to deploy an image without pushing to a registry first.\n\nThe uploaded file should be a tarball created by `docker save myimage:tag > image.tar`\nor `docker save myimage:tag | gzip > image.tar.gz` (gzip compressed tarballs are also supported).", + "operationId": "deploy_from_image_upload", + "parameters": [ + { + "name": "tag", + "in": "query", + "description": "Tag to apply to the imported image (e.g., \"myapp:v1.0\")\nIf not provided, a unique tag will be generated", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "health_check_path", + "in": "query", + "description": "Optional HTTP health-check path override (e.g. \"/api/healthz\").\nMust start with '/'. When omitted, defaults to \"/\".", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "202": { + "description": "Image imported and deployment started", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RemoteDeploymentResponse" + } + } + } + }, + "400": { + "description": "Invalid request or unsupported format" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Project or environment not found" + }, + "413": { + "description": "Image tarball too large" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/environments/{environment_id}/deploy/source": { + "post": { + "tags": [ + "Deployments" + ], + "summary": "Upload source code and immediately start a preset-based deployment.", + "operationId": "deploy_from_uploaded_source", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/SourceArchiveUpload" + } + } + }, + "required": true + }, + "responses": { + "202": { + "description": "Source deployment started", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RemoteDeploymentResponse" + } + } + } + }, + "400": { + "description": "Invalid source archive" + }, + "404": { + "description": "Project or environment not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/environments/{environment_id}/deploy/static": { + "post": { + "tags": [ + "Deployments" + ], + "summary": "Deploy from an uploaded static bundle", + "description": "Triggers a deployment using a previously uploaded static file bundle.", + "operationId": "deploy_from_static", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeployFromStaticRequest" + } + } + }, + "required": true + }, + "responses": { + "202": { + "description": "Deployment started", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RemoteDeploymentResponse" + } + } + } + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Project, environment, or bundle not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/error-alert-rules": { + "get": { + "tags": [ + "error-alert-rules" + ], + "summary": "List all alert rules for a project", + "operationId": "list_alert_rules", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "List of alert rules", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AlertRuleResponse" + } + } + } + } + }, + "500": { + "description": "Internal server error" + } + } + }, + "post": { + "tags": [ + "error-alert-rules" + ], + "summary": "Create a new alert rule", + "operationId": "create_alert_rule", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateAlertRuleRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Alert rule created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AlertRuleResponse" + } + } + } + }, + "400": { + "description": "Validation error" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/error-alert-rules/{rule_id}": { + "get": { + "tags": [ + "error-alert-rules" + ], + "summary": "Get a specific alert rule", + "operationId": "get_alert_rule", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "rule_id", + "in": "path", + "description": "Alert rule ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Alert rule details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AlertRuleResponse" + } + } + } + }, + "404": { + "description": "Alert rule not found" + }, + "500": { + "description": "Internal server error" + } + } + }, + "put": { + "tags": [ + "error-alert-rules" + ], + "summary": "Update an existing alert rule", + "operationId": "update_alert_rule", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "rule_id", + "in": "path", + "description": "Alert rule ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateAlertRuleRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Alert rule updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AlertRuleResponse" + } + } + } + }, + "400": { + "description": "Validation error" + }, + "404": { + "description": "Alert rule not found" + }, + "500": { + "description": "Internal server error" + } + } + }, + "delete": { + "tags": [ + "error-alert-rules" + ], + "summary": "Delete an alert rule", + "operationId": "delete_alert_rule", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "rule_id", + "in": "path", + "description": "Alert rule ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Alert rule deleted" + }, + "404": { + "description": "Alert rule not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/error-dashboard-stats": { + "get": { + "tags": [ + "error-tracking" + ], + "summary": "Get error dashboard statistics", + "operationId": "get_error_dashboard_stats", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "start_time", + "in": "query", + "required": true, + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "end_time", + "in": "query", + "required": true, + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "environment_id", + "in": "query", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + }, + { + "name": "compare_to_previous", + "in": "query", + "required": false, + "schema": { + "type": [ + "boolean", + "null" + ] + } + } + ], + "responses": { + "200": { + "description": "Error dashboard statistics", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDashboardStatsResponse" + } + } + } + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/error-groups": { + "get": { + "tags": [ + "error-tracking" + ], + "summary": "List error groups for a project", + "operationId": "list_error_groups", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "page_size", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "status", + "in": "query", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "environment_id", + "in": "query", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + }, + { + "name": "start_date", + "in": "query", + "required": false, + "schema": { + "type": [ + "string", + "null" + ], + "format": "date-time" + } + }, + { + "name": "end_date", + "in": "query", + "required": false, + "schema": { + "type": [ + "string", + "null" + ], + "format": "date-time" + } + }, + { + "name": "sort_by", + "in": "query", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "sort_order", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Paginated list of error groups", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PaginatedErrorGroupsResponse" + } + } + } + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/error-groups/{group_id}": { + "get": { + "tags": [ + "error-tracking" + ], + "summary": "Get a specific error group", + "operationId": "get_error_group", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "group_id", + "in": "path", + "description": "Error group ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Error group details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorGroupResponse" + } + } + } + }, + "404": { + "description": "Error group not found" + }, + "500": { + "description": "Internal server error" + } + } + }, + "put": { + "tags": [ + "error-tracking" + ], + "summary": "Update error group status", + "operationId": "update_error_group", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "group_id", + "in": "path", + "description": "Error group ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateErrorGroupRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Error group updated successfully" + }, + "404": { + "description": "Error group not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/error-groups/{group_id}/events": { + "get": { + "tags": [ + "error-tracking" + ], + "summary": "List error events for a specific group", + "operationId": "list_error_events", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "group_id", + "in": "path", + "description": "Error group ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "page_size", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "Paginated list of error events", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PaginatedErrorEventsResponse" + } + } + } + }, + "404": { + "description": "Error group not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/error-groups/{group_id}/events/{event_id}": { + "get": { + "tags": [ + "error-tracking" + ], + "summary": "Get a specific error event", + "operationId": "get_error_event", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "group_id", + "in": "path", + "description": "Error group ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "event_id", + "in": "path", + "description": "Error event ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "Error event details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorEventResponse" + } + } + } + }, + "404": { + "description": "Event not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/error-stats": { + "get": { + "tags": [ + "error-tracking" + ], + "summary": "Get error statistics for a project", + "operationId": "get_error_stats", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Error statistics", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorGroupStatsResponse" + } + } + } + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/error-time-series": { + "get": { + "tags": [ + "error-tracking" + ], + "summary": "Get error time series data for charts", + "operationId": "get_error_time_series", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "start_time", + "in": "query", + "required": true, + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "end_time", + "in": "query", + "required": true, + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "bucket", + "in": "query", + "description": "Time bucket size (e.g., \"1h\", \"15m\", \"1d\", \"1 hour\", \"30 minutes\")", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Error time series data", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ErrorTimeSeriesDataResponse" + } + } + } + } + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/events": { + "get": { + "tags": [ + "Events" + ], + "summary": "Get event counts with filtering", + "operationId": "get_events_count", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "start_date", + "in": "query", + "description": "Start date for filtering events", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "end_date", + "in": "query", + "description": "End date for filtering events", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Filter by environment ID", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "limit", + "in": "query", + "description": "Maximum number of events to return (default: 20, max: 100)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "custom_events_only", + "in": "query", + "description": "Only return custom events, excluding system events like page_view, page_leave, heartbeat (default: true)", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "name": "aggregation_level", + "in": "query", + "description": "Aggregation level: events, sessions, or visitors (default: events)", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved event counts", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EventCount" + } + } + } + } + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/events/breakdown": { + "get": { + "tags": [ + "Events" + ], + "summary": "Get event type breakdown", + "operationId": "get_event_type_breakdown", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "start_date", + "in": "query", + "description": "Start date for filtering events", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "end_date", + "in": "query", + "description": "End date for filtering events", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Filter by environment ID", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "aggregation_level", + "in": "query", + "description": "Aggregation level: events, sessions, or visitors (default: events)", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved event type breakdown", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EventTypeBreakdown" + } + } + } + } + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/events/ingest": { + "post": { + "tags": [ + "Events" + ], + "summary": "Record an analytics event via the console API with explicit project ID.", + "description": "The app backend forwards the user's encrypted Temps cookies, so visitor/session\nidentity is resolved automatically by middleware. No geolocation or user-agent\nenrichment is performed \u2014 this is a lightweight server-side ingestion path.", + "operationId": "record_console_event", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConsoleEventPayload" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Event recorded successfully" + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/events/properties/breakdown": { + "get": { + "tags": [ + "Events" + ], + "summary": "Get property breakdown by grouping events by a column", + "operationId": "get_property_breakdown", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "start_date", + "in": "query", + "description": "Start date in '%Y-%m-%d %H:%M:%S' format", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "end_date", + "in": "query", + "description": "End date in '%Y-%m-%d %H:%M:%S' format", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "group_by", + "in": "query", + "description": "Column to group by (channel, device_type, browser, etc.)", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Filter by environment ID", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "deployment_id", + "in": "query", + "description": "Filter by deployment ID", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "event_name", + "in": "query", + "description": "Filter by event name", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "aggregation_level", + "in": "query", + "description": "Aggregation level: events, sessions, or visitors - default: events", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "description": "Maximum number of results (default: 20, max: 100)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "filter_country", + "in": "query", + "description": "Filter by country (for region/city drill-downs)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "filter_region", + "in": "query", + "description": "Filter by region (for city drill-downs)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "filter_browser", + "in": "query", + "description": "Filter by browser name (for version drill-downs)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "filter_os", + "in": "query", + "description": "Filter by OS name (for version drill-downs)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "filter_channel", + "in": "query", + "description": "Filter by channel name (for channel drill-downs)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "filter_referrer", + "in": "query", + "description": "Filter by referrer hostname (for referrer drill-downs)", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved property breakdown", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PropertyBreakdownResponse" + } + } + } + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/events/properties/timeline": { + "get": { + "tags": [ + "Events" + ], + "summary": "Get property timeline by grouping events by a column over time", + "operationId": "get_property_timeline", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "start_date", + "in": "query", + "description": "Start date in '%Y-%m-%d %H:%M:%S' format", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "end_date", + "in": "query", + "description": "End date in '%Y-%m-%d %H:%M:%S' format", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "group_by", + "in": "query", + "description": "Column to group by (channel, device_type, browser, etc.)", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Filter by environment ID", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "deployment_id", + "in": "query", + "description": "Filter by deployment ID", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "event_name", + "in": "query", + "description": "Filter by event name", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "aggregation_level", + "in": "query", + "description": "Aggregation level: events, sessions, or visitors - default: events", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "bucket_size", + "in": "query", + "description": "Time bucket: hour, day, week, month (default: auto-detect)", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved property timeline", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PropertyTimelineResponse" + } + } + } + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/events/timeline": { + "get": { + "tags": [ + "Events" + ], + "summary": "Get events timeline", + "operationId": "get_events_timeline", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "start_date", + "in": "query", + "description": "Start date for filtering events", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "end_date", + "in": "query", + "description": "End date for filtering events", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Filter by environment ID", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "event_name", + "in": "query", + "description": "Filter by specific event name", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "bucket_size", + "in": "query", + "description": "Bucket size: hour, day, or week (auto-detected if not specified)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "aggregation_level", + "in": "query", + "description": "Aggregation level: events, sessions, or visitors (default: events)", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved events timeline", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EventTimeline" + } + } + } + } + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/events/unique": { + "get": { + "tags": [ + "Funnels" + ], + "summary": "Get all unique/distinct event types for a project (paginated)", + "operationId": "get_unique_events", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "page", + "in": "query", + "description": "Page number (default: 1)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "page_size", + "in": "query", + "description": "Items per page (default: 50, max: 100)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "Unique event types retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventTypesResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/external-images": { + "get": { + "tags": [ + "External Images" + ], + "summary": "List external images for a project", + "operationId": "list_remote_external_images", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "page", + "in": "query", + "description": "Page number (default: 1)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "page_size", + "in": "query", + "description": "Items per page (default: 20)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "List of external images", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PaginatedExternalImagesResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "External Images" + ], + "summary": "Register an external Docker image", + "description": "Registers an external Docker image reference without triggering a deployment.\nThe image can be deployed later using the deploy/image endpoint.", + "operationId": "register_external_image", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegisterImageRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Image registered successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExternalImageResponse" + } + } + } + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/external-images/{image_id}": { + "get": { + "tags": [ + "External Images" + ], + "summary": "Get details of a specific external image", + "operationId": "get_remote_external_image", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "image_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Image details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExternalImageResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Image not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "External Images" + ], + "summary": "Delete an external image", + "operationId": "delete_external_image", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "image_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Image deleted" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Image not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/flags": { + "get": { + "tags": [ + "Feature Flags" + ], + "operationId": "list_flags", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "include_archived", + "in": "query", + "description": "Include archived flags. Defaults to false.", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "name": "page", + "in": "query", + "description": "1-indexed page number. Defaults to 1.", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + } + }, + { + "name": "page_size", + "in": "query", + "description": "Items per page. Defaults to 20, capped at 100.", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "Flags listed", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FlagListResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Feature Flags" + ], + "operationId": "create_flag", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateFlagRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Flag created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FlagResponse" + } + } + } + }, + "400": { + "description": "Validation error" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "409": { + "description": "Flag key already exists" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/flags/{key}": { + "get": { + "tags": [ + "Feature Flags" + ], + "operationId": "get_flag", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "key", + "in": "path", + "description": "Flag key", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Flag retrieved", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FlagResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Flag not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "Feature Flags" + ], + "operationId": "archive_flag", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "key", + "in": "path", + "description": "Flag key", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Flag archived", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ArchiveFlagResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Flag not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "patch": { + "tags": [ + "Feature Flags" + ], + "operationId": "update_flag", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "key", + "in": "path", + "description": "Flag key", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateFlagRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Flag updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FlagResponse" + } + } + } + }, + "400": { + "description": "Validation error" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Flag not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/flags/{key}/environments/{environment_id}": { + "put": { + "tags": [ + "Feature Flags" + ], + "summary": "Set a flag's value in one environment, and/or flip its kill switch.", + "operationId": "set_flag_environment", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "key", + "in": "path", + "description": "Flag key", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "environment_id", + "in": "path", + "description": "Environment ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetFlagEnvironmentRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Environment value set", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FlagEnvironmentResponse" + } + } + } + }, + "400": { + "description": "Validation error" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Flag or environment not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/flags/{key}/restore": { + "post": { + "tags": [ + "Feature Flags" + ], + "summary": "Bring an archived flag back.", + "description": "Archiving is otherwise one-way: the key stays reserved so the flag cannot\neven be re-created under the same name, which makes an accidental archive\nunrecoverable through the API.", + "operationId": "restore_flag", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "key", + "in": "path", + "description": "Flag key", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Flag restored", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FlagResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Flag not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/funnels": { + "get": { + "tags": [ + "Funnels" + ], + "summary": "List all funnels for a project", + "operationId": "list_funnels", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Funnels retrieved successfully", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FunnelResponse" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Funnels" + ], + "summary": "Create a new funnel", + "operationId": "create_funnel", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateFunnelRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Funnel created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateFunnelResponse" + } + } + } + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/funnels/preview": { + "post": { + "tags": [ + "Funnels" + ], + "summary": "Preview funnel metrics without creating the funnel", + "operationId": "preview_funnel_metrics", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateFunnelRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Funnel metrics preview", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FunnelMetricsResponse" + } + } + } + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/funnels/{funnel_id}": { + "put": { + "tags": [ + "Funnels" + ], + "summary": "Update a funnel", + "operationId": "update_funnel", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "funnel_id", + "in": "path", + "description": "Funnel ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateFunnelRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Funnel updated successfully" + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Funnel not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "Funnels" + ], + "summary": "Delete a funnel", + "operationId": "delete_funnel", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "funnel_id", + "in": "path", + "description": "Funnel ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Funnel deleted successfully" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Funnel not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/funnels/{funnel_id}/metrics": { + "get": { + "tags": [ + "Funnels" + ], + "summary": "Get funnel metrics", + "operationId": "get_funnel_metrics", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "funnel_id", + "in": "path", + "description": "Funnel ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Environment ID filter", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "country_code", + "in": "query", + "description": "Country code filter", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "start_date", + "in": "query", + "description": "Start date filter (ISO 8601)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "end_date", + "in": "query", + "description": "End date filter (ISO 8601)", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Funnel metrics retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FunnelMetricsResponse" + } + } + } + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Funnel not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/git": { + "post": { + "tags": [ + "Projects" + ], + "summary": "Update git settings for a project", + "operationId": "update_git_settings", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateGitSettingsRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Git settings updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectResponse" + } + } + } + }, + "400": { + "description": "Invalid git configuration or branch does not exist" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/gitlab/reinstall-webhook": { + "post": { + "tags": [ + "Projects" + ], + "summary": "Reinstall the GitLab webhook for a project", + "description": "Removes the existing webhook (if any) and installs a fresh one.\nUse this when a webhook has been manually deleted on the GitLab side\nand automatic deployments have stopped working.", + "operationId": "reinstall_gitlab_webhook", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Webhook reinstalled", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReinstallWebhookResponse" + } + } + } + }, + "400": { + "description": "Project is not connected to a GitLab repository" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/has-error-groups": { + "get": { + "tags": [ + "error-tracking" + ], + "summary": "Check if project has any error groups", + "operationId": "has_error_groups", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Error groups existence check", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HasErrorGroupsResponse" + } + } + } + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/has-events": { + "get": { + "tags": [ + "Events" + ], + "summary": "Check if project has any analytics events", + "operationId": "has_analytics_events", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Successfully checked for events", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HasEventsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/hourly-visits": { + "get": { + "tags": [ + "Events" + ], + "summary": "Get hourly visits", + "operationId": "get_hourly_visits", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "start_date", + "in": "query", + "description": "Start date for filtering visits", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "end_date", + "in": "query", + "description": "End date for filtering visits", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Filter by environment ID", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "aggregation_level", + "in": "query", + "description": "Aggregation level: events (page views), sessions (unique sessions), or visitors (unique visitors) - default: events", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved hourly visits", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EventTimeline" + } + } + } + } + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/images": { + "get": { + "tags": [ + "External Images" + ], + "summary": "List all external images for a project", + "operationId": "list_external_images", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "List of external images", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PushedExternalImageResponse" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/images/push": { + "post": { + "tags": [ + "External Images" + ], + "summary": "Push an external Docker image", + "operationId": "push_external_image", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PushImageRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Image pushed successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PushedExternalImageResponse" + } + } + } + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/images/{image_id}": { + "get": { + "tags": [ + "External Images" + ], + "summary": "Get details of a specific external image", + "operationId": "get_external_image", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "image_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Image details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PushedExternalImageResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Image not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/incidents": { + "get": { + "tags": [ + "Status Page" + ], + "summary": "List incidents for a project", + "operationId": "list_incidents", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Filter by environment ID", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "status", + "in": "query", + "description": "Filter by status", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "page", + "in": "query", + "description": "Page number", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "page_size", + "in": "query", + "description": "Items per page", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved incidents" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Status Page" + ], + "summary": "Create a new incident", + "operationId": "create_incident", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateIncidentRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Incident created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IncidentResponse" + } + } + } + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/incidents/bucketed": { + "get": { + "tags": [ + "Status Page" + ], + "summary": "Get bucketed incident data for a project", + "operationId": "get_bucketed_incidents", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Filter by environment ID", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "interval", + "in": "query", + "description": "Bucket interval: '5min', 'hourly', or 'daily' (default: hourly)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "start_time", + "in": "query", + "description": "Start time (ISO 8601) (default: 7 days ago)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "end_time", + "in": "query", + "description": "End time (ISO 8601) (default: now)", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved bucketed incident data", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IncidentBucketedResponse" + } + } + } + }, + "400": { + "description": "Invalid parameters" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/logs": { + "delete": { + "tags": [ + "Logs" + ], + "summary": "Purge all logs for a project before a given timestamp", + "operationId": "purge_project_logs", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PurgeLogsRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Purge completed" + }, + "400": { + "description": "Invalid parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/mcp-servers": { + "get": { + "tags": [ + "Agents" + ], + "operationId": "list_mcps", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListMcpsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Agents" + ], + "operationId": "create_mcp", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateMcpRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/McpDefinitionResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/mcp-servers/{slug}": { + "get": { + "tags": [ + "Agents" + ], + "operationId": "get_mcp", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "slug", + "in": "path", + "description": "MCP server slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/McpDefinitionResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "MCP server not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "put": { + "tags": [ + "Agents" + ], + "operationId": "update_mcp", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "slug", + "in": "path", + "description": "MCP server slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateMcpRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/McpDefinitionResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "MCP server not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "Agents" + ], + "operationId": "delete_mcp", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "slug", + "in": "path", + "description": "MCP server slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "MCP server deleted" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "MCP server not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/mcp-servers/{slug}/config/{field}": { + "get": { + "tags": [ + "Agents" + ], + "operationId": "reveal_mcp_config", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "slug", + "in": "path", + "description": "MCP server slug", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "field", + "in": "path", + "description": "Sensitive field path, such as url or env.API_TOKEN", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SensitiveMcpConfigValueResponse" + } + } + } + }, + "400": { + "description": "Field is not revealable" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Missing secrets:read permission" + }, + "404": { + "description": "MCP server or field not found" + }, + "500": { + "description": "Configuration read or audit failed" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/monitors": { + "get": { + "tags": [ + "Status Page" + ], + "summary": "List monitors for a project", + "operationId": "list_monitors", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Filter by environment ID", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved monitors", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MonitorResponse" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Status Page" + ], + "summary": "Create a new monitor", + "operationId": "create_monitor", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateMonitorRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Monitor created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MonitorResponse" + } + } + } + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/observe/events": { + "get": { + "tags": [ + "Observability" + ], + "summary": "List a merged page of observability events for a project.", + "description": "Each row carries everything the side panel needs to render \u2014 no\nfollow-up fetch is required for the common case. Heavy fields\n(stacktraces, headers, span attributes) are truncated server-side and\nexpose a `*_truncated` flag; clients fetch the full row from the\n`/full` endpoint only when the user explicitly clicks \"Show full\".", + "operationId": "observability_list_events", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "kinds", + "in": "query", + "description": "Comma-separated kinds: `log,request,span,error,revenue`. Empty or\nmissing returns every kind.", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "from", + "in": "query", + "description": "Inclusive lower bound on event timestamp (ISO 8601, `Z` suffix).", + "required": false, + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "to", + "in": "query", + "description": "Inclusive upper bound on event timestamp.", + "required": false, + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "deployment_id", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "search", + "in": "query", + "description": "Free-text substring matched against per-kind summary fields\n(request path / error class / revenue event_type).", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "description": "Page size (default 50, max 200).", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "hide_bots", + "in": "query", + "description": "When `true`, exclude bot/crawler request rows. When `false`, only\ninclude bot rows. Omitted means \"include everything\" (default).\nOnly affects the `Request` kind.", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "Merged event page", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventsResponse" + } + } + } + }, + "400": { + "description": "Invalid filter (kinds, time range, \u2026)", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/observe/events/{kind}/{event_id}/full": { + "get": { + "tags": [ + "Observability" + ], + "summary": "Fetch the un-truncated form of one event by `(kind, id)`. Side panel\n\"Show full\" action calls this \u2014 the list response carries truncated\npreviews + a `*_truncated` flag to let the UI decide whether to fetch.", + "operationId": "observability_full_event", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "kind", + "in": "path", + "description": "Event kind discriminator", + "required": true, + "schema": { + "$ref": "#/components/schemas/EventKind" + } + }, + { + "name": "event_id", + "in": "path", + "description": "Per-kind identity: request_id for requests, `{trace_id}:{span_id}` for spans, serial id for errors/revenue", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "ts", + "in": "query", + "description": "The row's event timestamp as returned by the list endpoint. Optional,\nbut strongly recommended: it bounds the lookup to the storage\npartitions/chunks around that instant instead of scanning the whole\nretention window.", + "required": false, + "schema": { + "type": "string", + "format": "date-time" + } + } + ], + "responses": { + "200": { + "description": "Full row", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FullEvent" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "404": { + "description": "Event not found in project", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/releases/{release}/source-files": { + "get": { + "tags": [ + "source-maps" + ], + "summary": "List uploaded source files for a release (metadata only).", + "operationId": "list_source_files", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "release", + "in": "path", + "description": "Release version", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "List of source files", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SourceFileListResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "source-maps" + ], + "summary": "Upload a raw source file for a release (native symbolication).", + "description": "Accepts a multipart form with:\n- `file`: the source file bytes (required)\n- `file_path`: the path of the file as it appears in stack frames (required;\n derived from the uploaded filename if omitted). Normalized with the `~`\n prefix convention, matching source-map storage.\n\nRequires the project's `error_source_context_enabled` toggle to be on.\nUpserts on (project, release, file_path).", + "operationId": "upload_source_file", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "release", + "in": "path", + "description": "Release version", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "201": { + "description": "Source file uploaded", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SourceFileResponse" + } + } + } + }, + "400": { + "description": "Missing fields" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "409": { + "description": "Source context disabled for project" + }, + "413": { + "description": "Source file too large" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "source-maps" + ], + "summary": "Delete all uploaded source files for a release.", + "operationId": "delete_release_source_files", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "release", + "in": "path", + "description": "Release version", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Source files deleted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/releases/{release}/source-maps": { + "get": { + "tags": [ + "source-maps" + ], + "summary": "List all source maps for a specific release", + "operationId": "list_source_maps", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "release", + "in": "path", + "description": "Release version", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "List of source maps", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SourceMapListResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "source-maps" + ], + "summary": "Upload a source map for a release.", + "description": "Accepts a multipart form with:\n- `file`: The .map file (required)\n- `file_path`: The URL path of the minified file as it appears in stack traces (required).\n Uses the ~ prefix convention (e.g., \"~/assets/main.js\").\n If a full URL is provided, it will be normalized automatically.\n- `dist`: Optional distribution identifier\n\nIf a source map already exists for the same (project, release, file_path), it is replaced.", + "operationId": "upload_source_map", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "release", + "in": "path", + "description": "Release version", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "201": { + "description": "Source map uploaded", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SourceMapResponse" + } + } + } + }, + "400": { + "description": "Invalid source map or missing fields" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "413": { + "description": "Source map too large" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "source-maps" + ], + "summary": "Delete all source maps for a specific release", + "operationId": "delete_release_source_maps", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "release", + "in": "path", + "description": "Release version", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Source maps deleted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/revenue/events": { + "get": { + "tags": [ + "Revenue" + ], + "summary": "Recent ingested events for the activity feed.", + "operationId": "revenue_recent_events", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RecentEventResponse" + } + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/revenue/integrations": { + "get": { + "tags": [ + "Revenue" + ], + "summary": "List revenue integrations for a project.", + "operationId": "revenue_list_integrations", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IntegrationResponse" + } + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Revenue" + ], + "summary": "Create a new revenue integration. Response contains the generated\nwebhook path that the user must paste into their provider's dashboard.", + "operationId": "revenue_create_integration", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateIntegrationBody" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IntegrationResponse" + } + } + } + }, + "400": { + "description": "Validation error" + }, + "409": { + "description": "Already connected" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/revenue/integrations/{integration_id}": { + "delete": { + "tags": [ + "Revenue" + ], + "summary": "Delete a revenue integration (permanent \u2014 use rotate_token to refresh\ncredentials without breaking history).", + "operationId": "revenue_delete_integration", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "integration_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/revenue/integrations/{integration_id}/config": { + "post": { + "tags": [ + "Revenue" + ], + "summary": "Replace the typed provider config on an integration. Passing `null`\nclears the config back to the accept-everything default. The config's\nprovider tag must match the integration's provider.", + "operationId": "revenue_update_config", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "integration_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateConfigBody" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IntegrationResponse" + } + } + } + }, + "400": { + "description": "Validation error" + }, + "404": { + "description": "Integration not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/revenue/integrations/{integration_id}/import/invoices": { + "post": { + "tags": [ + "Revenue" + ], + "summary": "Import a Stripe invoices CSV export. Each paid invoice becomes an\n`invoice.paid` event so historical MRR/charge totals populate the\ntimeseries. Ingestion is idempotent: re-uploading the same file is a\nno-op.", + "operationId": "revenue_import_invoices_csv", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "integration_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ImportOutcomeResponse" + } + } + } + }, + "400": { + "description": "Malformed CSV or wrong provider" + }, + "404": { + "description": "Integration not found" + }, + "413": { + "description": "CSV too large" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/revenue/integrations/{integration_id}/import/subscriptions": { + "post": { + "tags": [ + "Revenue" + ], + "summary": "Import a Stripe subscriptions CSV export. Use this to backfill MRR /\nactive subscriptions when migrating from Stripe without providing\nAPI keys. Webhooks remain the source of truth for live updates \u2014\nCSV rows never overwrite newer webhook state.", + "operationId": "revenue_import_subscriptions_csv", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "integration_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ImportOutcomeResponse" + } + } + } + }, + "400": { + "description": "Malformed CSV or wrong provider" + }, + "404": { + "description": "Integration not found" + }, + "413": { + "description": "CSV too large" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/revenue/integrations/{integration_id}/rotate-token": { + "post": { + "tags": [ + "Revenue" + ], + "summary": "Rotate the webhook path token. Returns the new integration state \u2014\nthe user must paste the new URL into their provider's dashboard.", + "operationId": "revenue_rotate_token", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "integration_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IntegrationResponse" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/revenue/integrations/{integration_id}/update-secret": { + "post": { + "tags": [ + "Revenue" + ], + "summary": "Replace the stored signing secret without rotating the webhook URL.\nUse this after rotating the secret in the provider's dashboard.", + "operationId": "revenue_update_secret", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "integration_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateSecretBody" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IntegrationResponse" + } + } + } + }, + "400": { + "description": "Validation error" + }, + "404": { + "description": "Integration not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/revenue/metrics/customers": { + "get": { + "tags": [ + "Revenue" + ], + "summary": "New + churned customers per bucket.", + "operationId": "revenue_metrics_customers", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomerMovementResponse" + } + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/revenue/metrics/mrr": { + "get": { + "tags": [ + "Revenue" + ], + "summary": "Bucketed MRR timeseries for the revenue chart.", + "operationId": "revenue_metrics_mrr", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MrrBucketResponse" + } + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/revenue/metrics/summary": { + "get": { + "tags": [ + "Revenue" + ], + "summary": "Current MRR / ARR / churn / ARPU for a project, in one currency.", + "operationId": "revenue_metrics_summary", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MetricsSummaryResponse" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/secrets": { + "get": { + "tags": [ + "Secrets" + ], + "summary": "List project secrets (metadata only \u2014 values never returned).", + "operationId": "listProjectSecrets", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Optional environment filter", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "List of secrets (metadata only, no values)", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProjectSecretResponse" + } + } + } + } + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + } + }, + "post": { + "tags": [ + "Secrets" + ], + "summary": "Create a new secret. The value is encrypted before storage and will be\nmounted as a file at `/run/secrets/` on the next deployment.\nThe plaintext value is NOT returned \u2014 the response carries only metadata.", + "operationId": "createProjectSecret", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateProjectSecretRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Secret created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectSecretResponse" + } + } + } + }, + "400": { + "description": "Invalid key or value too large" + }, + "409": { + "description": "Key already exists in project" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/secrets/{secret_id}": { + "put": { + "tags": [ + "Secrets" + ], + "summary": "Update a project secret. Value rotation requires a redeploy to take effect \u2014\nrunning containers keep their currently-mounted values until the next\ndeployment.", + "operationId": "updateProjectSecret", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "secret_id", + "in": "path", + "description": "Secret ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateProjectSecretRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Secret updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectSecretResponse" + } + } + } + }, + "400": { + "description": "Value too large" + }, + "404": { + "description": "Secret not found" + }, + "500": { + "description": "Internal server error" + } + } + }, + "delete": { + "tags": [ + "Secrets" + ], + "summary": "Delete a project secret. Running containers keep their mounted secret files\nuntil they are redeployed.", + "operationId": "deleteProjectSecret", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "secret_id", + "in": "path", + "description": "Secret ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Secret deleted" + }, + "404": { + "description": "Secret not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/projects/{project_id}/settings": { + "post": { + "tags": [ + "Projects" + ], + "summary": "Update project settings", + "operationId": "update_project_settings", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateProjectSettingsRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Project settings updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/skills": { + "get": { + "tags": [ + "Agents" + ], + "operationId": "list_skills", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListSkillsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Agents" + ], + "operationId": "create_skill", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateSkillRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SkillDefinitionResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/skills/upload": { + "post": { + "tags": [ + "Agents" + ], + "summary": "Upload a skill with an archive (tar.gz) \u2014 project-scoped.", + "operationId": "upload_skill", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "string" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SkillDefinitionResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/skills/{slug}": { + "get": { + "tags": [ + "Agents" + ], + "operationId": "get_skill", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "slug", + "in": "path", + "description": "Skill slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SkillDefinitionResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Skill not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "put": { + "tags": [ + "Agents" + ], + "operationId": "update_skill", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "slug", + "in": "path", + "description": "Skill slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateSkillRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SkillDefinitionResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Skill not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "Agents" + ], + "operationId": "delete_skill", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "slug", + "in": "path", + "description": "Skill slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Skill deleted" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Skill not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/skills/{slug}/archive": { + "get": { + "tags": [ + "Agents" + ], + "summary": "Download a skill's archive (tar.gz) \u2014 project-scoped.", + "operationId": "download_skill_archive", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "slug", + "in": "path", + "description": "Skill slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Skill archive tar.gz", + "content": { + "application/gzip": {} + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Skill not found or has no archive" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/source-map-releases": { + "get": { + "tags": [ + "source-maps" + ], + "summary": "List all releases that have source maps for a project", + "operationId": "list_releases", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "List of releases", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReleaseListResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/source-maps/{source_map_id}": { + "delete": { + "tags": [ + "source-maps" + ], + "summary": "Delete a specific source map by ID", + "operationId": "delete_source_map", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "source_map_id", + "in": "path", + "description": "Source map ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Source map deleted" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Source map not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/static-bundles": { + "get": { + "tags": [ + "Static Bundles" + ], + "summary": "List static bundles for a project", + "operationId": "list_static_bundles", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "page", + "in": "query", + "description": "Page number (default: 1)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "page_size", + "in": "query", + "description": "Items per page (default: 20)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "List of static bundles", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PaginatedStaticBundlesResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/static-bundles/{bundle_id}": { + "get": { + "tags": [ + "Static Bundles" + ], + "summary": "Get details of a specific static bundle", + "operationId": "get_static_bundle", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "bundle_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Bundle details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StaticBundleResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Bundle not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "Static Bundles" + ], + "summary": "Delete a static bundle", + "operationId": "delete_static_bundle", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "bundle_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Bundle deleted" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Bundle not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/status": { + "get": { + "tags": [ + "Status Page" + ], + "summary": "Get status page overview", + "operationId": "get_status_overview", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Filter by environment ID", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved status overview", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StatusPageOverview" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/unique-counts": { + "get": { + "tags": [ + "Events" + ], + "summary": "Get unique counts over time frame", + "operationId": "get_unique_counts", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "start_date", + "in": "query", + "description": "Start date in '%Y-%m-%d %H:%M:%S' format", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "end_date", + "in": "query", + "description": "End date in '%Y-%m-%d %H:%M:%S' format", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Filter by environment ID", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "deployment_id", + "in": "query", + "description": "Filter by deployment ID", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "metric", + "in": "query", + "description": "Metric to count: 'sessions' (unique sessions), 'visitors' (unique visitors), 'returning_visitors' (visitors seen before the range), or 'page_views' (total page views) (default: 'sessions')", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved count", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UniqueCountsResponse" + } + } + } + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/upload/static": { + "post": { + "tags": [ + "Static Bundles" + ], + "summary": "Upload a static bundle for later deployment", + "description": "Uploads a tar.gz or zip file containing static assets. The bundle can be\ndeployed later using the deploy/static endpoint.", + "operationId": "upload_static_bundle", + "parameters": [ + { + "name": "project_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "201": { + "description": "Bundle uploaded successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StaticBundleResponse" + } + } + } + }, + "400": { + "description": "Invalid request or unsupported format" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Project not found" + }, + "413": { + "description": "Bundle too large" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/vulnerability-scans": { + "get": { + "tags": [ + "Vulnerability Scans" + ], + "operationId": "list_project_scans", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "page", + "in": "query", + "description": "Page number (default: 1)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "page_size", + "in": "query", + "description": "Page size (default: 20, max: 100)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "List of vulnerability scans", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ScanResponse" + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Vulnerability Scans" + ], + "operationId": "trigger_scan", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TriggerScanRequest" + } + } + }, + "required": true + }, + "responses": { + "202": { + "description": "Scan triggered successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TriggerScanResponse" + } + } + } + }, + "400": { + "description": "Invalid request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/vulnerability-scans/environments": { + "get": { + "tags": [ + "Vulnerability Scans" + ], + "operationId": "get_latest_scans_per_environment", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Latest scans per environment for current deployments", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ScanResponse" + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/vulnerability-scans/latest": { + "get": { + "tags": [ + "Vulnerability Scans" + ], + "operationId": "get_latest_scan", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Filter by environment ID", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Latest scan for project", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScanResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "No scans found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/webhooks": { + "get": { + "tags": [ + "Webhooks" + ], + "summary": "List all webhooks for a project", + "operationId": "list_webhooks", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "page", + "in": "query", + "description": "Page number (1-indexed)", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + }, + "example": 1 + }, + { + "name": "page_size", + "in": "query", + "description": "Number of items per page (max 100)", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + }, + "example": 20 + }, + { + "name": "sort_by", + "in": "query", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "sort_order", + "in": "query", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + } + ], + "responses": { + "200": { + "description": "List of webhooks", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/WebhookResponse" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Webhooks" + ], + "summary": "Create a new webhook", + "operationId": "create_webhook", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateWebhookRequestBody" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Webhook created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WebhookResponse" + } + } + } + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/webhooks/{webhook_id}": { + "get": { + "tags": [ + "Webhooks" + ], + "summary": "Get a specific webhook", + "operationId": "get_webhook", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "webhook_id", + "in": "path", + "description": "Webhook ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Webhook details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WebhookResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Webhook not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "put": { + "tags": [ + "Webhooks" + ], + "summary": "Update a webhook", + "operationId": "update_webhook", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "webhook_id", + "in": "path", + "description": "Webhook ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateWebhookRequestBody" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Webhook updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WebhookResponse" + } + } + } + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Webhook not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "Webhooks" + ], + "summary": "Delete a webhook", + "operationId": "delete_webhook", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "webhook_id", + "in": "path", + "description": "Webhook ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Webhook deleted" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Webhook not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/webhooks/{webhook_id}/deliveries": { + "get": { + "tags": [ + "Webhook Deliveries" + ], + "summary": "List webhook deliveries", + "operationId": "list_deliveries", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "webhook_id", + "in": "path", + "description": "Webhook ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "limit", + "in": "query", + "description": "Number of deliveries to return (default: 50)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "List of deliveries", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/WebhookDeliveryResponse" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/webhooks/{webhook_id}/deliveries/{delivery_id}": { + "get": { + "tags": [ + "Webhook Deliveries" + ], + "summary": "Get a specific webhook delivery by ID", + "operationId": "get_delivery", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "webhook_id", + "in": "path", + "description": "Webhook ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "delivery_id", + "in": "path", + "description": "Delivery ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Delivery details including full payload", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WebhookDeliveryResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Delivery not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/webhooks/{webhook_id}/deliveries/{delivery_id}/retry": { + "post": { + "tags": [ + "Webhook Deliveries" + ], + "summary": "Retry a failed delivery", + "operationId": "retry_delivery", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "webhook_id", + "in": "path", + "description": "Webhook ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "delivery_id", + "in": "path", + "description": "Delivery ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Delivery retried", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WebhookDeliveryResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Delivery not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/projects/{project_id}/workflows/dry-run": { + "post": { + "tags": [ + "Workflows" + ], + "operationId": "workflow_dry_run", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WorkflowDryRunRequest" + } + } + }, + "required": true + }, + "responses": { + "202": { + "description": "Ephemeral run created and queued", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentRunResponse" + } + } + } + }, + "400": { + "description": "Validation error (bad YAML, oversized payload, capped limits exceeded)" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/proxy-logs": { + "get": { + "tags": [ + "Proxy Logs" + ], + "summary": "Get proxy logs with optional filters and pagination", + "operationId": "get_proxy_logs", + "parameters": [ + { + "name": "project_id", + "in": "query", + "description": "Filter by project ID", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Filter by environment ID", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + }, + { + "name": "deployment_id", + "in": "query", + "description": "Filter by deployment ID", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + }, + { + "name": "session_id", + "in": "query", + "description": "Filter by session ID", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + }, + { + "name": "visitor_id", + "in": "query", + "description": "Filter by visitor ID", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + }, + { + "name": "start_date", + "in": "query", + "description": "Start date for filtering (ISO 8601 format).\n\n**Defaults to 1 hour before `end_date` (or before now) when omitted.**\nThe listing is always time-bounded: an unbounded query would have to\nconsider the entire retention window \u2014 100M+ rows on a busy deployment \u2014\nto return a single page. Pass an explicit `start_date` to widen the\nwindow, up to the configured retention horizon.\n\nThe maximum span between `start_date` and `end_date` is 7 days when\n`project_id` is omitted, or 30 days when a single `project_id` is set \u2014\na project-scoped query is bounded by that project's own row count\nrather than the whole deployment's. A wider request is rejected with a\n400 naming the applicable cap.", + "required": false, + "schema": { + "type": [ + "string", + "null" + ], + "format": "date-time" + } + }, + { + "name": "end_date", + "in": "query", + "description": "End date for filtering (ISO 8601 format). Defaults to now.", + "required": false, + "schema": { + "type": [ + "string", + "null" + ], + "format": "date-time" + } + }, + { + "name": "method", + "in": "query", + "description": "Filter by HTTP method (GET, POST, etc.)", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "host", + "in": "query", + "description": "Filter by host header", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "path", + "in": "query", + "description": "Filter by path (supports partial match)", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "client_ip", + "in": "query", + "description": "Filter by client IP address", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "status_code", + "in": "query", + "description": "Filter by HTTP status code", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + }, + { + "name": "response_time_min", + "in": "query", + "description": "Filter by minimum response time in ms", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + }, + { + "name": "response_time_max", + "in": "query", + "description": "Filter by maximum response time in ms", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + }, + { + "name": "routing_status", + "in": "query", + "description": "Filter by routing status (routed, no_project, error, pending)", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "request_source", + "in": "query", + "description": "Filter by request source (proxy, api, console, cli)", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "is_system_request", + "in": "query", + "description": "Filter by system request flag", + "required": false, + "schema": { + "type": [ + "boolean", + "null" + ] + } + }, + { + "name": "user_agent", + "in": "query", + "description": "Filter by user agent string (partial match)", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "browser", + "in": "query", + "description": "Filter by browser name", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "operating_system", + "in": "query", + "description": "Filter by operating system", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "device_type", + "in": "query", + "description": "Filter by device type (mobile, desktop, tablet)", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "is_bot", + "in": "query", + "description": "Filter by bot detection", + "required": false, + "schema": { + "type": [ + "boolean", + "null" + ] + } + }, + { + "name": "exclude_bots", + "in": "query", + "description": "When `true`, exclude rows flagged as bots while KEEPING rows whose\n`is_bot` is NULL (older rows without detection metadata). This is the\ntri-state complement of `is_bot=false`, which matches only rows\nexplicitly detected as non-bots. `false`/omitted is a no-op.", + "required": false, + "schema": { + "type": [ + "boolean", + "null" + ] + } + }, + { + "name": "bot_name", + "in": "query", + "description": "Filter by bot name", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "ai_provider", + "in": "query", + "description": "Filter by AI provider (e.g. `OpenAI`, `Anthropic`, `Perplexity`). Matches\nthe canonical provider returned by the AI agent detector.", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "ai_agent", + "in": "query", + "description": "Filter by AI agent name (e.g. `GPTBot`, `ChatGPT-User`). Equivalent to\nfiltering `bot_name` against a known AI taxonomy.", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "is_ai_agent", + "in": "query", + "description": "When `true`, only return requests classified as known AI agents\n(regardless of provider/agent). Mutually compatible with the above.", + "required": false, + "schema": { + "type": [ + "boolean", + "null" + ] + } + }, + { + "name": "request_size_min", + "in": "query", + "description": "Filter by minimum request size in bytes", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int64" + } + }, + { + "name": "request_size_max", + "in": "query", + "description": "Filter by maximum request size in bytes", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int64" + } + }, + { + "name": "response_size_min", + "in": "query", + "description": "Filter by minimum response size in bytes", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int64" + } + }, + { + "name": "response_size_max", + "in": "query", + "description": "Filter by maximum response size in bytes", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int64" + } + }, + { + "name": "cache_status", + "in": "query", + "description": "Filter by cache status", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "container_id", + "in": "query", + "description": "Filter by container ID", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "upstream_host", + "in": "query", + "description": "Filter by upstream host", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "has_error", + "in": "query", + "description": "Filter by presence of error message", + "required": false, + "schema": { + "type": [ + "boolean", + "null" + ] + } + }, + { + "name": "page", + "in": "query", + "description": "Page number (default: 1)", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + } + }, + { + "name": "page_size", + "in": "query", + "description": "Page size (default: 20, max: 100)", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + } + }, + { + "name": "sort_by", + "in": "query", + "description": "Sort by field (default: timestamp)", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "sort_order", + "in": "query", + "description": "Sort order (asc or desc, default: desc)", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + } + ], + "responses": { + "200": { + "description": "List of proxy logs", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProxyLogsPaginatedResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/proxy-logs/ai-agents/known": { + "get": { + "tags": [ + "Proxy Logs" + ], + "summary": "List every AI agent the detector knows how to classify.", + "description": "Returned in the same order as the internal taxonomy so the UI can use it as\na stable dropdown.", + "operationId": "list_known_ai_agents", + "responses": { + "200": { + "description": "Known AI agents", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KnownAiAgentsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/proxy-logs/request/{request_id}": { + "get": { + "tags": [ + "Proxy Logs" + ], + "summary": "Get a proxy log by request ID (for tracing)", + "operationId": "get_proxy_log_by_request_id", + "parameters": [ + { + "name": "request_id", + "in": "path", + "description": "Request ID from pingora", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "timestamp", + "in": "query", + "description": "Event time of the log row (ISO 8601). When provided, the lookup is\nbounded to the hypertable chunks around this instant instead of\nscanning (and decompressing) the whole retention window. The list\nendpoint already returns this value per row \u2014 always pass it when\nnavigating from a list.", + "required": false, + "schema": { + "type": [ + "string", + "null" + ], + "format": "date-time" + } + } + ], + "responses": { + "200": { + "description": "Proxy log found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProxyLogResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Proxy log not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/proxy-logs/stats/ai-agent-pages": { + "get": { + "tags": [ + "Proxy Logs" + ], + "summary": "Get the top pages accessed by a specific AI agent over a time window.", + "description": "Returns page paths ranked by request count, scoped to a single canonical\nagent name (e.g. `ChatGPT-User`). Use `GET /proxy-logs/ai-agents/known` to\nlist all valid agent names. Unknown agent names return an empty items array.", + "operationId": "get_ai_agent_pages", + "parameters": [ + { + "name": "agent", + "in": "query", + "description": "Canonical agent name to filter by (e.g. `ChatGPT-User`, `ClaudeBot`).\nMust be a name returned by `GET /proxy-logs/ai-agents/known`.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "project_id", + "in": "query", + "description": "Filter by project ID.", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Filter by environment ID.", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + }, + { + "name": "start_time", + "in": "query", + "description": "Start time (ISO 8601). Defaults to `end_time - 7d`.", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + }, + "example": "2026-05-22T00:00:00Z" + }, + { + "name": "end_time", + "in": "query", + "description": "End time (ISO 8601). Defaults to now.", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + }, + "example": "2026-05-29T00:00:00Z" + }, + { + "name": "limit", + "in": "query", + "description": "Maximum rows to return. Capped at 100 server-side.", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "Pages breakdown for the requested agent", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiAgentPagesResponse" + } + } + } + }, + "400": { + "description": "Invalid parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/proxy-logs/stats/ai-agents": { + "get": { + "tags": [ + "Proxy Logs" + ], + "summary": "Get the per-AI-agent breakdown for a project over a time window.", + "operationId": "get_ai_agent_breakdown", + "parameters": [ + { + "name": "project_id", + "in": "query", + "description": "Filter by project ID (recommended for per-project analytics).", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Filter by environment ID.", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + }, + { + "name": "start_time", + "in": "query", + "description": "Start time (ISO 8601). Defaults to `end_time - 7d`.", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + }, + "example": "2026-05-22T00:00:00Z" + }, + { + "name": "end_time", + "in": "query", + "description": "End time (ISO 8601). Defaults to now.", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + }, + "example": "2026-05-29T00:00:00Z" + }, + { + "name": "limit", + "in": "query", + "description": "Maximum rows to return. Capped at 100 server-side.", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + } + }, + { + "name": "path", + "in": "query", + "description": "Optional exact path filter. Only used by the AI pages breakdown \u2014 when\nset, returns the single matching page so callers can ask \"how many AI\nagents hit this page?\".", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + } + ], + "responses": { + "200": { + "description": "AI agent breakdown", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiAgentBreakdownResponse" + } + } + } + }, + "400": { + "description": "Invalid parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/proxy-logs/stats/ai-agents/timeline": { + "get": { + "tags": [ + "Proxy Logs" + ], + "summary": "Time-bucketed AI-agent request volume, split by provider or agent.", + "description": "Powers the \"AI agents over time\" stacked chart. Same data source as the AI\nagent breakdown (request logs), just bucketed.", + "operationId": "get_ai_agent_timeline", + "parameters": [ + { + "name": "project_id", + "in": "query", + "description": "Filter by project ID.", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Filter by environment ID.", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + }, + { + "name": "start_time", + "in": "query", + "description": "Start time (ISO 8601). Defaults to `end_time - 7d`.", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + }, + "example": "2026-05-22T00:00:00Z" + }, + { + "name": "end_time", + "in": "query", + "description": "End time (ISO 8601). Defaults to now.", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + }, + "example": "2026-05-29T00:00:00Z" + }, + { + "name": "group_by", + "in": "query", + "description": "Grouping dimension: `provider` (default) or `agent`.", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + }, + "example": "provider" + }, + { + "name": "bucket", + "in": "query", + "description": "Bucket interval override (e.g. `1 hour`, `1 day`). Auto-selected from the\nwindow width when omitted.", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + }, + "example": "1 hour" + } + ], + "responses": { + "200": { + "description": "AI agent timeline", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiAgentTimelineResponse" + } + } + } + }, + "400": { + "description": "Invalid parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/proxy-logs/stats/ai-pages": { + "get": { + "tags": [ + "Proxy Logs" + ], + "summary": "Get the top pages crawled by AI agents over a time window.", + "operationId": "get_ai_page_breakdown", + "parameters": [ + { + "name": "project_id", + "in": "query", + "description": "Filter by project ID (recommended for per-project analytics).", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Filter by environment ID.", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + }, + { + "name": "start_time", + "in": "query", + "description": "Start time (ISO 8601). Defaults to `end_time - 7d`.", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + }, + "example": "2026-05-22T00:00:00Z" + }, + { + "name": "end_time", + "in": "query", + "description": "End time (ISO 8601). Defaults to now.", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + }, + "example": "2026-05-29T00:00:00Z" + }, + { + "name": "limit", + "in": "query", + "description": "Maximum rows to return. Capped at 100 server-side.", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + } + }, + { + "name": "path", + "in": "query", + "description": "Optional exact path filter. Only used by the AI pages breakdown \u2014 when\nset, returns the single matching page so callers can ask \"how many AI\nagents hit this page?\".", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + } + ], + "responses": { + "200": { + "description": "AI page breakdown", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiPageBreakdownResponse" + } + } + } + }, + "400": { + "description": "Invalid parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/proxy-logs/stats/ai-status": { + "get": { + "tags": [ + "Proxy Logs" + ], + "summary": "HTTP status-class breakdown for AI-agent traffic \u2014 are bots being served\n(2xx) or hitting broken/blocked pages (4xx/5xx)?", + "operationId": "get_ai_status_breakdown", + "parameters": [ + { + "name": "project_id", + "in": "query", + "description": "Filter by project ID (recommended for per-project analytics).", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Filter by environment ID.", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + }, + { + "name": "start_time", + "in": "query", + "description": "Start time (ISO 8601). Defaults to `end_time - 7d`.", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + }, + "example": "2026-05-22T00:00:00Z" + }, + { + "name": "end_time", + "in": "query", + "description": "End time (ISO 8601). Defaults to now.", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + }, + "example": "2026-05-29T00:00:00Z" + }, + { + "name": "limit", + "in": "query", + "description": "Maximum rows to return. Capped at 100 server-side.", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "minimum": 0 + } + }, + { + "name": "path", + "in": "query", + "description": "Optional exact path filter. Only used by the AI pages breakdown \u2014 when\nset, returns the single matching page so callers can ask \"how many AI\nagents hit this page?\".", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + } + ], + "responses": { + "200": { + "description": "AI status breakdown", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiStatusBreakdownResponse" + } + } + } + }, + "400": { + "description": "Invalid parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/proxy-logs/stats/projects-health": { + "get": { + "tags": [ + "Proxy Logs" + ], + "summary": "Get health summaries for multiple projects (last 1 hour)", + "operationId": "get_projects_health", + "parameters": [ + { + "name": "project_ids", + "in": "query", + "description": "Comma-separated list of project IDs", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "start_time", + "in": "query", + "description": "Optional start time (ISO 8601). Defaults to `end_time - 1h`.", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + }, + "example": "2025-10-23T00:00:00Z" + }, + { + "name": "end_time", + "in": "query", + "description": "Optional end time (ISO 8601). Defaults to now.", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + }, + "example": "2025-10-23T23:59:59Z" + }, + { + "name": "is_bot", + "in": "query", + "description": "Filter by bot detection. Pass `false` to exclude bots, `true` for bots only.", + "required": false, + "schema": { + "type": [ + "boolean", + "null" + ] + } + } + ], + "responses": { + "200": { + "description": "Health summaries per project", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectsHealthResponse" + } + } + } + }, + "400": { + "description": "Invalid parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/proxy-logs/stats/time-buckets": { + "get": { + "tags": [ + "Proxy Logs" + ], + "summary": "Get time-bucketed statistics with optional filters", + "operationId": "get_time_bucket_stats", + "parameters": [ + { + "name": "start_time", + "in": "query", + "description": "Start time (ISO 8601 format)", + "required": true, + "schema": { + "type": "string" + }, + "example": "2025-10-23T00:00:00Z" + }, + { + "name": "end_time", + "in": "query", + "description": "End time (ISO 8601 format)", + "required": true, + "schema": { + "type": "string" + }, + "example": "2025-10-23T23:59:59Z" + }, + { + "name": "bucket_interval", + "in": "query", + "description": "Bucket interval (e.g., \"1 hour\", \"1 day\", \"5 minutes\")", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "method", + "in": "query", + "description": "Filter by HTTP method", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "client_ip", + "in": "query", + "description": "Filter by client IP", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "project_id", + "in": "query", + "description": "Filter by project ID", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Filter by environment ID", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "deployment_id", + "in": "query", + "description": "Filter by deployment ID", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "host", + "in": "query", + "description": "Filter by host", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "status_code", + "in": "query", + "description": "Filter by status code", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "status_code_class", + "in": "query", + "description": "Filter by status code class (e.g. \"2xx\", \"3xx\", \"4xx\", \"5xx\")", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "routing_status", + "in": "query", + "description": "Filter by routing status", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "request_source", + "in": "query", + "description": "Filter by request source", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "is_bot", + "in": "query", + "description": "Filter by bot detection", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "name": "device_type", + "in": "query", + "description": "Filter by device type", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "has_project", + "in": "query", + "description": "When true, only count requests that matched a project\n(project_id IS NOT NULL). Makes chart totals line up with the\nper-project health cards.", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "Time-bucketed statistics", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TimeBucketStatsResponse" + } + } + } + }, + "400": { + "description": "Invalid parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/proxy-logs/stats/today": { + "get": { + "tags": [ + "Proxy Logs" + ], + "summary": "Get today's request count with optional filters", + "operationId": "get_today_stats", + "parameters": [ + { + "name": "method", + "in": "query", + "description": "Filter by HTTP method", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "client_ip", + "in": "query", + "description": "Filter by client IP", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "project_id", + "in": "query", + "description": "Filter by project ID", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Filter by environment ID", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + }, + { + "name": "deployment_id", + "in": "query", + "description": "Filter by deployment ID", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + }, + { + "name": "host", + "in": "query", + "description": "Filter by host", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "status_code", + "in": "query", + "description": "Filter by status code", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + }, + { + "name": "status_code_class", + "in": "query", + "description": "Filter by status code class (e.g. \"2xx\", \"3xx\", \"4xx\", \"5xx\")", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "routing_status", + "in": "query", + "description": "Filter by routing status", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "request_source", + "in": "query", + "description": "Filter by request source", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "name": "is_bot", + "in": "query", + "description": "Filter by bot detection", + "required": false, + "schema": { + "type": [ + "boolean", + "null" + ] + } + }, + { + "name": "device_type", + "in": "query", + "description": "Filter by device type", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + } + ], + "responses": { + "200": { + "description": "Today's request count", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TodayStatsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/proxy-logs/{id}": { + "get": { + "tags": [ + "Proxy Logs" + ], + "summary": "Get a single proxy log by ID", + "operationId": "get_proxy_log_by_id", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Proxy log ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "timestamp", + "in": "query", + "description": "Event time of the log row (ISO 8601). When provided, the lookup is\nbounded to the hypertable chunks around this instant instead of\nscanning (and decompressing) the whole retention window. The list\nendpoint already returns this value per row \u2014 always pass it when\nnavigating from a list.", + "required": false, + "schema": { + "type": [ + "string", + "null" + ], + "format": "date-time" + } + } + ], + "responses": { + "200": { + "description": "Proxy log found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProxyLogResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Proxy log not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/repositories": { + "get": { + "tags": [ + "Git Providers" + ], + "summary": "List synced repositories with advanced filtering", + "description": "Lists repositories that have been synced to the database with filtering options.\nThis provides fast access to repository metadata with filtering by connection, search, and other criteria.", + "operationId": "list_synced_repositories", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "Page number for pagination", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "per_page", + "in": "query", + "description": "Number of items per page (max 100)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "sort", + "in": "query", + "description": "Sort field (name, created_at, updated_at, stars, watchers, size, issues)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "direction", + "in": "query", + "description": "Sort direction (asc, desc)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "search", + "in": "query", + "description": "Search term to filter repositories", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "owner", + "in": "query", + "description": "Filter by repository owner", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "language", + "in": "query", + "description": "Filter by programming language", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "private", + "in": "query", + "description": "Filter by private status (true/false)", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "name": "git_provider_connection_id", + "in": "query", + "description": "Filter by git provider connection ID", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "List of synced repositories", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RepositoryListResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/repositories/{owner}/{name}": { + "get": { + "tags": [ + "Git Providers" + ], + "summary": "Get repository by owner and name from any connection", + "operationId": "get_repository_by_name", + "parameters": [ + { + "name": "owner", + "in": "path", + "description": "Repository owner", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "name", + "in": "path", + "description": "Repository name", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "connection_id", + "in": "query", + "description": "Optional specific connection ID to search", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Repository found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RepositoryResponse" + } + } + } + }, + "404": { + "description": "Repository not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/repositories/{owner}/{name}/all": { + "get": { + "tags": [ + "Git Providers" + ], + "summary": "Get all repositories with same owner/name from all git providers", + "operationId": "get_all_repositories_by_name", + "parameters": [ + { + "name": "owner", + "in": "path", + "description": "Repository owner", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "name", + "in": "path", + "description": "Repository name", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Repositories found from all providers", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RepositoryResponse" + } + } + } + } + }, + "404": { + "description": "No repositories found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/repositories/{owner}/{name}/preset": { + "get": { + "tags": [ + "Git Providers" + ], + "summary": "Get repository preset by owner and name", + "operationId": "get_repository_preset_by_name", + "parameters": [ + { + "name": "owner", + "in": "path", + "description": "Repository owner", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "name", + "in": "path", + "description": "Repository name", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "branch", + "in": "query", + "description": "Git branch to check (defaults to repository's default branch)", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Repository preset calculated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RepositoryPresetResponse" + } + } + } + }, + "404": { + "description": "Repository not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/repositories/{owner}/{repo}/branches": { + "get": { + "tags": [ + "Repositories" + ], + "summary": "Get repository branches", + "operationId": "get_repository_branches", + "parameters": [ + { + "name": "owner", + "in": "path", + "description": "Repository owner", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "repo", + "in": "path", + "description": "Repository name", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "connection_id", + "in": "query", + "description": "Git provider connection ID (required when multiple connections have the same repo)", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fresh", + "in": "query", + "description": "Force fetch fresh data, bypassing cache (default: false)", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "List of branches", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BranchListResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Repository not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/repositories/{owner}/{repo}/tags": { + "get": { + "tags": [ + "Repositories" + ], + "summary": "Get repository tags", + "operationId": "get_repository_tags", + "parameters": [ + { + "name": "owner", + "in": "path", + "description": "Repository owner", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "repo", + "in": "path", + "description": "Repository name", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "connection_id", + "in": "query", + "description": "Git provider connection ID (required when multiple connections have the same repo)", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fresh", + "in": "query", + "description": "Force fetch fresh data, bypassing cache (default: false)", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "List of tags", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagListResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Repository not found" + }, + "429": { + "description": "Fresh tag lookup rate limit exceeded" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/repositories/{repository_id}/preset/live": { + "get": { + "tags": [ + "Git Providers" + ], + "operationId": "get_repository_preset_live", + "parameters": [ + { + "name": "repository_id", + "in": "path", + "description": "Repository ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "branch", + "in": "query", + "description": "Git branch to check (defaults to repository's default branch)", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Repository presets calculated successfully - includes root preset and projects in subdirectories", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RepositoryPresetResponse" + } + } + } + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "The git provider rejected the stored credential - the connection must be re-authorized" + }, + "404": { + "description": "Repository not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/repository/{repository_id}": { + "get": { + "tags": [ + "Git Providers" + ], + "summary": "Get repository by ID", + "operationId": "get_repository_by_id", + "parameters": [ + { + "name": "repository_id", + "in": "path", + "description": "Repository ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Repository found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RepositoryResponse" + } + } + } + }, + "404": { + "description": "Repository not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/repository/{repository_id}/branches": { + "get": { + "tags": [ + "Repositories" + ], + "summary": "Get repository branches by repository ID", + "operationId": "get_branches_by_repository_id", + "parameters": [ + { + "name": "repository_id", + "in": "path", + "description": "Repository ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fresh", + "in": "query", + "description": "Force fetch fresh data, bypassing cache (default: false)", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "List of branches", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BranchListResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Repository not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/repository/{repository_id}/commits": { + "get": { + "tags": [ + "Repositories" + ], + "summary": "List recent commits for a repository branch", + "operationId": "list_commits_by_repository_id", + "parameters": [ + { + "name": "repository_id", + "in": "path", + "description": "Repository ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "branch", + "in": "query", + "description": "Branch name to list commits for", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "per_page", + "in": "query", + "description": "Number of commits to return (default: 20, max: 100)", + "required": false, + "schema": { + "type": [ + "integer", + "null" + ], + "format": "int32", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "List of commits", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommitListResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Repository not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/repository/{repository_id}/commits/{commit_sha}": { + "get": { + "tags": [ + "Repositories" + ], + "summary": "Check if a commit exists in a repository", + "operationId": "check_commit_exists", + "parameters": [ + { + "name": "repository_id", + "in": "path", + "description": "Repository ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "commit_sha", + "in": "path", + "description": "Commit SHA to check", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Commit existence check result", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommitExistsResponse" + } + } + } + }, + "400": { + "description": "Invalid commit SHA" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Repository not found" + }, + "429": { + "description": "Commit lookup rate limit exceeded" + }, + "500": { + "description": "Internal server error" + }, + "502": { + "description": "Git provider request failed" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/repository/{repository_id}/tags": { + "get": { + "tags": [ + "Repositories" + ], + "summary": "Get repository tags by repository ID", + "operationId": "get_tags_by_repository_id", + "parameters": [ + { + "name": "repository_id", + "in": "path", + "description": "Repository ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fresh", + "in": "query", + "description": "Force fetch fresh data, bypassing cache (default: false)", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "List of tags", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagListResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Repository not found" + }, + "429": { + "description": "Fresh tag lookup rate limit exceeded" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/restore-runs/{id}": { + "get": { + "tags": [ + "Restore" + ], + "operationId": "get_restore_run", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Restore run id", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Restore run progress", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RestoreRunView" + } + } + } + }, + "404": { + "description": "Restore run not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/revenue/events": { + "get": { + "tags": [ + "Revenue" + ], + "summary": "Org-wide revenue events across every project. Powers the revenue\ntransactions page. Supports filtering by project, date range, and\nevent type.", + "operationId": "revenue_global_events", + "parameters": [ + { + "name": "project_id", + "in": "query", + "description": "Filter to a single project", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "from", + "in": "query", + "description": "Lower bound (inclusive), ISO-8601", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "to", + "in": "query", + "description": "Upper bound (inclusive), ISO-8601", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "event_types", + "in": "query", + "description": "Comma-separated event types (e.g. `invoice.paid,charge.succeeded`)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "description": "Max rows, default 100, max 500", + "required": false, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GlobalRecentEventResponse" + } + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/revenue/metrics/global-mrr": { + "get": { + "tags": [ + "Revenue" + ], + "summary": "Org-wide MRR total, summed across every project in the install.\nPowers the single-number MRR card on the main dashboard.", + "operationId": "revenue_metrics_global_mrr", + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GlobalMrrResponse" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/revenue/metrics/global-summary": { + "get": { + "tags": [ + "Revenue" + ], + "summary": "Org-wide revenue summary: MRR, paid cash (30d + all-time), refunds,\nactive subscriptions/customers, and transaction count. Powers the\nheader on the Revenue transactions page.", + "operationId": "revenue_metrics_global_summary", + "parameters": [ + { + "name": "currency", + "in": "query", + "description": "ISO-4217 currency code, default USD", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GlobalRevenueSummaryResponse" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/revenue/providers": { + "get": { + "tags": [ + "Revenue" + ], + "summary": "List registered providers (what the UI needs to render the \"Connect\"\ndropdown + its wizard instructions).", + "operationId": "revenue_list_providers", + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProviderDescriptor" + } + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/session-replays": { + "get": { + "tags": [ + "Analytics" + ], + "summary": "Get session replays for a project", + "operationId": "get_project_session_replays", + "parameters": [ + { + "name": "project_id", + "in": "query", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Environment ID (optional)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "page", + "in": "query", + "description": "Page number (1-based)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "per_page", + "in": "query", + "description": "Items per page", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "Session replays retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetProjectSessionReplaysResponse" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Authentication required", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/sessions/{session_id}/events": { + "get": { + "tags": [ + "Events" + ], + "summary": "Get events for a specific session", + "operationId": "get_session_events", + "parameters": [ + { + "name": "session_id", + "in": "path", + "description": "Session ID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "environment_id", + "in": "query", + "description": "Filter by environment ID", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved session events", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AnalyticsSessionEventsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Session not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/settings": { + "get": { + "tags": [ + "Settings" + ], + "summary": "Get application settings", + "operationId": "get_settings", + "responses": { + "200": { + "description": "Application settings with masked sensitive fields", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AppSettingsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "put": { + "tags": [ + "Settings" + ], + "summary": "Update application settings", + "operationId": "update_settings", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AppSettings" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Settings updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SettingsUpdateResponse" + } + } + } + }, + "400": { + "description": "Bad request - invalid settings" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/settings/agent-token": { + "post": { + "tags": [ + "Agents" + ], + "summary": "Save an encrypted AI provider token for use in sandbox containers.", + "operationId": "save_agent_token", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SaveAgentTokenRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Token encrypted and persisted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SaveAgentTokenResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Encryption or database error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/settings/ai-providers": { + "get": { + "tags": [ + "Agents" + ], + "summary": "List the AI provider catalog. Includes per-provider \"is a credential\nconfigured?\" so the settings UI can render configured/not-configured\nbadges without leaking the encrypted credential.", + "operationId": "list_ai_providers", + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProviderCatalogResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/settings/ai-providers/{provider_id}": { + "patch": { + "tags": [ + "Agents" + ], + "summary": "Update provider-scoped settings without touching the saved credential.\nToday that means just `default_model`; future per-provider settings\n(base URL overrides, request headers, etc.) can land here too without\nchanging the shape of `save_credential`.", + "operationId": "update_ai_provider", + "parameters": [ + { + "name": "provider_id", + "in": "path", + "description": "AI provider ID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateAiProviderRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateAiProviderResponse" + } + } + } + }, + "400": { + "description": "Unknown provider" + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/settings/ai-providers/{provider_id}/activate": { + "post": { + "tags": [ + "Agents" + ], + "summary": "Activate a provider as the platform-wide default. Refuses to activate a\nprovider that doesn't have a credential saved yet \u2014 the UI enforces the\nsame rule on the button, but we re-check server-side so a stale tab\ncan't bypass it.", + "operationId": "activate_ai_provider", + "parameters": [ + { + "name": "provider_id", + "in": "path", + "description": "AI provider ID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ActivateProviderResponse" + } + } + } + }, + "400": { + "description": "Provider not configured" + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/settings/ai-providers/{provider_id}/credential": { + "post": { + "tags": [ + "Agents" + ], + "summary": "Save (or replace) a provider's credential. The credential is encrypted\nwith `EncryptionService` and stored inside\n`agent_sandbox.providers[provider_id].credentials_encrypted`.", + "description": "The plaintext shape depends on the flavor's `credential_format`:\n - `ApiKey` / `OauthToken`: the key/token string.\n - `ConfigFile`: the full file body (e.g. OpenCode's `auth.json`).", + "operationId": "save_ai_provider_credential", + "parameters": [ + { + "name": "provider_id", + "in": "path", + "description": "AI provider ID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SaveCredentialRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SaveCredentialResponse" + } + } + } + }, + "400": { + "description": "Validation error" + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/settings/disk-status": { + "get": { + "tags": [ + "Settings" + ], + "summary": "Get current disk usage for the control-plane server", + "description": "Returns live disk usage for the monitored path along with any disks that\nmeet or exceed the configured alert threshold. Read-only \u2014 does not send\nnotifications. Used by the dashboard to surface a low-disk-space warning.", + "operationId": "get_disk_status", + "responses": { + "200": { + "description": "Current disk usage and threshold alerts", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DiskSpaceCheckResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/settings/enrollment-tokens": { + "get": { + "tags": [ + "Settings" + ], + "summary": "List currently-valid node enrollment tokens (hashes elided).", + "operationId": "list_enrollment_tokens", + "responses": { + "200": { + "description": "Active enrollment tokens", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnrollmentTokenListResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Settings" + ], + "summary": "Mint a short-lived, single-use node enrollment token.", + "operationId": "mint_enrollment_token", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MintEnrollmentTokenRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Enrollment token minted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MintEnrollmentTokenResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/settings/enrollment-tokens/{id}": { + "delete": { + "tags": [ + "Settings" + ], + "summary": "Revoke a node enrollment token by id.", + "operationId": "revoke_enrollment_token", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Enrollment token id", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Enrollment token revoked", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SettingsUpdateResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Enrollment token not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/settings/join-token": { + "delete": { + "tags": [ + "Settings" + ], + "summary": "Revoke the current join token", + "description": "Removes the stored join token hash, allowing any node to register\n(if no other authentication is in place).", + "operationId": "revoke_join_token", + "responses": { + "200": { + "description": "Join token revoked", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SettingsUpdateResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/settings/join-token/generate": { + "post": { + "tags": [ + "Settings" + ], + "summary": "Generate a new join token for multi-node cluster registration", + "description": "Creates a random 32-byte hex token, stores the SHA-256 hash in settings,\nand returns the plaintext exactly once. If a token already exists, it is replaced.", + "operationId": "generate_join_token", + "responses": { + "200": { + "description": "Join token generated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GenerateJoinTokenResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/settings/join-token/status": { + "get": { + "tags": [ + "Settings" + ], + "summary": "Check whether a join token is currently configured", + "operationId": "get_join_token_status", + "responses": { + "200": { + "description": "Join token status", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/JoinTokenStatusResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/settings/mcp-servers": { + "get": { + "tags": [ + "Agents" + ], + "operationId": "list_global_mcps", + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListMcpsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Agents" + ], + "operationId": "create_global_mcp", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateMcpRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/McpDefinitionResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/settings/mcp-servers/{slug}": { + "get": { + "tags": [ + "Agents" + ], + "operationId": "get_global_mcp", + "parameters": [ + { + "name": "slug", + "in": "path", + "description": "MCP server slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/McpDefinitionResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "MCP server not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "put": { + "tags": [ + "Agents" + ], + "operationId": "update_global_mcp", + "parameters": [ + { + "name": "slug", + "in": "path", + "description": "MCP server slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateMcpRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/McpDefinitionResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "MCP server not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "Agents" + ], + "operationId": "delete_global_mcp", + "parameters": [ + { + "name": "slug", + "in": "path", + "description": "MCP server slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "MCP server deleted" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "MCP server not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/settings/mcp-servers/{slug}/config/{field}": { + "get": { + "tags": [ + "Agents" + ], + "operationId": "reveal_global_mcp_config", + "parameters": [ + { + "name": "slug", + "in": "path", + "description": "MCP server slug", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "field", + "in": "path", + "description": "Sensitive field path, such as url or env.API_TOKEN", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SensitiveMcpConfigValueResponse" + } + } + } + }, + "400": { + "description": "Field is not revealable" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Missing secrets:read permission" + }, + "404": { + "description": "MCP server or field not found" + }, + "500": { + "description": "Configuration read or audit failed" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/settings/routes/refresh": { + "post": { + "tags": [ + "Settings" + ], + "summary": "Manually refresh the proxy route table", + "description": "Reloads all routes from the database into the in-memory proxy cache.\nUseful as a workaround when routes are out of sync.", + "operationId": "refresh_route_table", + "responses": { + "200": { + "description": "Route table refreshed", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RouteRefreshResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/settings/sandbox-rebuild": { + "post": { + "tags": [ + "Agents" + ], + "operationId": "rebuild_sandbox_image", + "responses": { + "200": { + "description": "Server-Sent Events stream of rebuild progress; final event `{\"type\":\"done\",\"success\":bool,...}`", + "content": { + "text/event-stream": {} + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/settings/sandbox-status": { + "get": { + "tags": [ + "Agents" + ], + "operationId": "get_global_sandbox_status", + "responses": { + "200": { + "description": "Global sandbox readiness for the settings page", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxStatusResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/settings/secrets": { + "get": { + "tags": [ + "Secrets" + ], + "operationId": "list_secrets", + "responses": { + "200": { + "description": "List of global agent secrets", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListSecretsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Secrets" + ], + "operationId": "upsert_secret", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpsertSecretRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Secret created/updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SecretResponse" + } + } + } + }, + "400": { + "description": "Validation error" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/settings/secrets/{name}": { + "delete": { + "tags": [ + "Secrets" + ], + "operationId": "delete_secret", + "parameters": [ + { + "name": "name", + "in": "path", + "description": "Secret name", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Secret deleted" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Secret not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/settings/skills": { + "get": { + "tags": [ + "Agents" + ], + "operationId": "list_global_skills", + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListSkillsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Agents" + ], + "operationId": "create_global_skill", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateSkillRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SkillDefinitionResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/settings/skills/upload": { + "post": { + "tags": [ + "Agents" + ], + "summary": "Upload a skill with an archive (tar.gz) \u2014 global.", + "operationId": "upload_global_skill", + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "string" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SkillDefinitionResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/settings/skills/{slug}": { + "get": { + "tags": [ + "Agents" + ], + "operationId": "get_global_skill", + "parameters": [ + { + "name": "slug", + "in": "path", + "description": "Skill slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SkillDefinitionResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Skill not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "put": { + "tags": [ + "Agents" + ], + "operationId": "update_global_skill", + "parameters": [ + { + "name": "slug", + "in": "path", + "description": "Skill slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateSkillRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SkillDefinitionResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Skill not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "Agents" + ], + "operationId": "delete_global_skill", + "parameters": [ + { + "name": "slug", + "in": "path", + "description": "Skill slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Skill deleted" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Skill not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/settings/skills/{slug}/archive": { + "get": { + "tags": [ + "Agents" + ], + "summary": "Download a skill's archive (tar.gz) \u2014 global.", + "operationId": "download_global_skill_archive", + "parameters": [ + { + "name": "slug", + "in": "path", + "description": "Skill slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Skill archive tar.gz", + "content": { + "application/gzip": {} + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Skill not found or has no archive" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/settings/update-status": { + "get": { + "tags": [ + "Settings" + ], + "summary": "Report whether a newer temps release is available for this install.", + "operationId": "get_update_status", + "responses": { + "200": { + "description": "Release update status for this install", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateStatusResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/teams": { + "get": { + "tags": [ + "Teams" + ], + "operationId": "list_teams", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "1-indexed page", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "page_size", + "in": "query", + "description": "default 20, max 100", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "Paginated teams", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TeamListResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Teams" + ], + "operationId": "create_team", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateTeamRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Team created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TeamResponse" + } + } + } + }, + "400": { + "description": "Validation error" + }, + "403": { + "description": "Insufficient permissions" + }, + "409": { + "description": "Slug already taken" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/teams/{team_id}": { + "get": { + "tags": [ + "Teams" + ], + "operationId": "get_team", + "parameters": [ + { + "name": "team_id", + "in": "path", + "description": "Team id", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Team", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TeamResponse" + } + } + } + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Team not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "Teams" + ], + "operationId": "delete_team", + "parameters": [ + { + "name": "team_id", + "in": "path", + "description": "Team id", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Team deleted" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Team not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "patch": { + "tags": [ + "Teams" + ], + "operationId": "update_team", + "parameters": [ + { + "name": "team_id", + "in": "path", + "description": "Team id", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateTeamRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Updated team", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TeamResponse" + } + } + } + }, + "400": { + "description": "Validation error" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Team not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/teams/{team_id}/members": { + "get": { + "tags": [ + "Teams" + ], + "operationId": "list_team_members", + "parameters": [ + { + "name": "team_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Members", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TeamMemberResponse" + } + } + } + } + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Team not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Teams" + ], + "operationId": "add_team_member", + "parameters": [ + { + "name": "team_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateTeamMemberRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Member added", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TeamMemberResponse" + } + } + } + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Team not found" + }, + "409": { + "description": "User already a member" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/teams/{team_id}/members/{user_id}": { + "delete": { + "tags": [ + "Teams" + ], + "operationId": "remove_team_member", + "parameters": [ + { + "name": "team_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "user_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Member removed" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Member not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "patch": { + "tags": [ + "Teams" + ], + "operationId": "update_team_member_role", + "parameters": [ + { + "name": "team_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "user_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateMemberRoleRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Updated membership", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TeamMemberResponse" + } + } + } + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Member not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/teams/{team_id}/projects": { + "get": { + "tags": [ + "Teams" + ], + "operationId": "list_team_projects", + "parameters": [ + { + "name": "team_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Projects this team has access to", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProjectAccessResponse" + } + } + } + } + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Team not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/templates": { + "get": { + "tags": [ + "Templates" + ], + "summary": "List all available templates", + "description": "Returns a list of all public templates, optionally filtered by tag or featured status.", + "operationId": "list_project_templates", + "parameters": [ + { + "name": "tag", + "in": "query", + "description": "Filter templates by tag", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "featured", + "in": "query", + "description": "Only return featured templates", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "List of templates", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListTemplatesResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/templates/tags": { + "get": { + "tags": [ + "Templates" + ], + "summary": "List all available template tags", + "description": "Returns a list of all unique tags used by public templates.", + "operationId": "list_project_template_tags", + "responses": { + "200": { + "description": "List of tags", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListTagsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/templates/{slug}": { + "get": { + "tags": [ + "Templates" + ], + "summary": "Get a specific template by slug", + "description": "Returns detailed information about a single template.", + "operationId": "get_project_template", + "parameters": [ + { + "name": "slug", + "in": "path", + "description": "Template slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Template details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TemplateResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Template not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/user/me": { + "get": { + "tags": [ + "Authentication" + ], + "operationId": "get_current_user", + "responses": { + "200": { + "description": "Successfully retrieved user information", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "session_token": [] + } + ] + } + }, + "/users": { + "get": { + "tags": [ + "Users" + ], + "operationId": "list_users", + "parameters": [ + { + "name": "include_deleted", + "in": "query", + "description": "Include deleted users in the response", + "required": true, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "List all users with their roles", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RouteUserWithRoles" + } + } + } + } + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Users" + ], + "summary": "Create a new user with roles", + "operationId": "create_user", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateUserRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "User created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RouteUserWithRoles" + } + } + } + }, + "400": { + "description": "Invalid input" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/users/me": { + "patch": { + "tags": [ + "Users" + ], + "summary": "Update current user's information", + "operationId": "update_self", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateSelfRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "User updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RouteUserWithRoles" + } + } + } + }, + "400": { + "description": "Invalid input" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/users/me/mfa": { + "delete": { + "tags": [ + "Users" + ], + "operationId": "disable_mfa", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DisableMfaRequest" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "MFA disabled" + }, + "400": { + "description": "Invalid verification code" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/users/me/mfa/setup": { + "post": { + "tags": [ + "Users" + ], + "operationId": "setup_mfa", + "responses": { + "200": { + "description": "MFA setup data", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MfaSetupResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/users/me/mfa/verify": { + "post": { + "tags": [ + "Users" + ], + "operationId": "verify_and_enable_mfa", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VerifyMfaRequest" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "MFA verified and enabled" + }, + "400": { + "description": "Invalid code" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/users/me/password": { + "post": { + "tags": [ + "Users" + ], + "operationId": "change_password_self", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChangePasswordRequest" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Password updated" + }, + "400": { + "description": "Validation error (weak password, same as current, MFA missing)" + }, + "401": { + "description": "Current password incorrect or MFA code invalid" + }, + "403": { + "description": "Account has no password set (SSO only)" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/users/{user_id}": { + "delete": { + "tags": [ + "Users" + ], + "summary": "Delete a user", + "operationId": "delete_user", + "parameters": [ + { + "name": "user_id", + "in": "path", + "description": "User ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "User deleted successfully" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - Cannot delete yourself or non-admin attempt" + }, + "404": { + "description": "User not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "patch": { + "tags": [ + "Users" + ], + "summary": "Update user information (admin only)", + "operationId": "update_user", + "parameters": [ + { + "name": "user_id", + "in": "path", + "description": "User ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateUserRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "User updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RouteUserWithRoles" + } + } + } + }, + "400": { + "description": "Invalid input" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - Non-admin attempt" + }, + "404": { + "description": "User not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/users/{user_id}/restore": { + "post": { + "tags": [ + "Users" + ], + "operationId": "restore_user", + "parameters": [ + { + "name": "user_id", + "in": "path", + "description": "User ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "User restored successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RouteUserWithRoles" + } + } + } + }, + "400": { + "description": "User is not deleted" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - Non-admin attempt" + }, + "404": { + "description": "User not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/users/{user_id}/roles": { + "post": { + "tags": [ + "Users" + ], + "operationId": "assign_role", + "parameters": [ + { + "name": "user_id", + "in": "path", + "description": "User ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssignRoleRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Role assigned successfully" + }, + "400": { + "description": "Invalid role type" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Admin role required or self-modification forbidden" + }, + "404": { + "description": "User or role not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/users/{user_id}/roles/{role_type}": { + "delete": { + "tags": [ + "Users" + ], + "operationId": "remove_role", + "parameters": [ + { + "name": "user_id", + "in": "path", + "description": "User ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "role_type", + "in": "path", + "description": "Role type to remove", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Role removed successfully" + }, + "400": { + "description": "Invalid role type" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - Cannot modify own roles or non-admin attempt" + }, + "404": { + "description": "User or role not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/v1/sandboxes": { + "get": { + "tags": [ + "Sandboxes" + ], + "operationId": "list_sandboxes", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "Page (1-indexed)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "page_size", + "in": "query", + "description": "Items per page (default 20, max 100)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "List sandboxes", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListSandboxesResponse" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Sandboxes" + ], + "operationId": "create_sandbox", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateSandboxBody" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Sandbox created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxResponse" + } + } + } + }, + "400": { + "description": "Validation error" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/v1/sandboxes/rootfs": { + "get": { + "tags": [ + "Sandboxes" + ], + "summary": "Inspect rootfs storage: the Firecracker digest-keyed cache (with which\nsandboxes reference each entry) and per-VM disks. Empty on Docker-only\nhosts. Admin/read scope \u2014 this exposes host storage layout.", + "operationId": "rootfs_report", + "responses": { + "200": { + "description": "Rootfs storage report" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/v1/sandboxes/rootfs/gc": { + "post": { + "tags": [ + "Sandboxes" + ], + "summary": "Reclaim rootfs cache entries not backing any live sandbox. Idempotent;\nsafe to call any time (live VMs hold their own per-VM disks).", + "operationId": "rootfs_gc", + "responses": { + "200": { + "description": "Reclaimed cache entries" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/v1/sandboxes/{id}": { + "get": { + "tags": [ + "Sandboxes" + ], + "operationId": "get_sandbox", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Sandbox details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxResponse" + } + } + } + }, + "404": { + "description": "Not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/v1/sandboxes/{id}/cmd": { + "post": { + "tags": [ + "Sandboxes" + ], + "summary": "Run a command inside the sandbox (`@vercel/sandbox`-compatible).", + "description": "`wait=false` (default) returns `{ command: {..., exitCode: null} }`\nimmediately once the background task is spawned.\n\n`wait=true` streams `application/x-ndjson`: the first line is the\nrunning envelope, the second is the finished envelope with `exitCode`.", + "operationId": "cmd", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CmdBody" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Command started (wait=false) or finished (wait=true)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CmdResponse" + } + } + } + }, + "404": { + "description": "Sandbox not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/v1/sandboxes/{id}/cmd/{cmd_id}": { + "get": { + "tags": [ + "Sandboxes" + ], + "operationId": "get_cmd", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "cmd_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Command snapshot", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CmdResponse" + } + } + } + }, + "404": { + "description": "Sandbox or command not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/v1/sandboxes/{id}/cmd/{cmd_id}/logs": { + "get": { + "tags": [ + "Sandboxes" + ], + "summary": "Stream a command's stdout/stderr as `application/x-ndjson`\n(`@vercel/sandbox`-compatible). Each line is either\n`{stream:\"stdout\"|\"stderr\", data:\"...\"}` or\n`{stream:\"error\", data:{code, message}}`.", + "operationId": "cmd_logs", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "cmd_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "NDJSON stream of log events" + }, + "404": { + "description": "Sandbox or command not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/v1/sandboxes/{id}/destroy": { + "post": { + "tags": [ + "Sandboxes" + ], + "operationId": "destroy_sandbox", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Sandbox destroyed (alias for `/stop` with an explicit verb)" + }, + "404": { + "description": "Not found" + }, + "409": { + "description": "Sandbox belongs to an active agent run \u2014 stop the run instead" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/v1/sandboxes/{id}/domain": { + "get": { + "tags": [ + "Sandboxes" + ], + "operationId": "domain", + "parameters": [ + { + "name": "port", + "in": "query", + "description": "Port inside the sandbox (1..=65535)", + "required": true, + "schema": { + "type": "integer", + "format": "int32", + "minimum": 0 + } + }, + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Preview URL for the port", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxDomainResponse" + } + } + } + }, + "400": { + "description": "Invalid port" + }, + "404": { + "description": "Sandbox not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/v1/sandboxes/{id}/events": { + "get": { + "tags": [ + "Sandboxes" + ], + "summary": "The operations timeline for a sandbox (lifecycle events only \u2014 never\nshell/exec activity), newest first.", + "operationId": "list_events", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Operations timeline", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxEventsResponse" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/v1/sandboxes/{id}/exec": { + "post": { + "tags": [ + "Sandboxes" + ], + "operationId": "exec", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExecBody" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Command finished (non-zero exit is NOT an error)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExecResponse" + } + } + } + }, + "404": { + "description": "Sandbox not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/v1/sandboxes/{id}/exec-detached": { + "post": { + "tags": [ + "Sandboxes" + ], + "operationId": "exec_detached", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExecBody" + } + } + }, + "required": true + }, + "responses": { + "202": { + "description": "Command accepted; poll /jobs/{job_id}", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExecDetachedResponse" + } + } + } + }, + "404": { + "description": "Sandbox not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/v1/sandboxes/{id}/extend-timeout": { + "post": { + "tags": [ + "Sandboxes" + ], + "operationId": "extend_timeout", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExtendTimeoutBody" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Timeout extended", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxResponse" + } + } + } + }, + "400": { + "description": "Validation error" + }, + "404": { + "description": "Not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/v1/sandboxes/{id}/fs/mkdir": { + "post": { + "tags": [ + "Sandboxes" + ], + "operationId": "mkdir", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MkdirBody" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Directory created (or already existed)" + }, + "400": { + "description": "Validation error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/v1/sandboxes/{id}/fs/read": { + "get": { + "tags": [ + "Sandboxes" + ], + "operationId": "read_file", + "parameters": [ + { + "name": "path", + "in": "query", + "description": "Absolute file path inside the sandbox", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "File contents (base64)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReadFileResponse" + } + } + } + }, + "400": { + "description": "Validation error" + }, + "404": { + "description": "Sandbox or file not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/v1/sandboxes/{id}/fs/stat": { + "get": { + "tags": [ + "Sandboxes" + ], + "operationId": "stat_path", + "parameters": [ + { + "name": "path", + "in": "query", + "description": "Absolute path inside the sandbox", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Stat info (exists=false when missing \u2014 not an error)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StatResponse" + } + } + } + }, + "400": { + "description": "Validation error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/v1/sandboxes/{id}/fs/write": { + "post": { + "tags": [ + "Sandboxes" + ], + "summary": "Write a file into the sandbox. Accepts two body shapes \u2014 the SDK\npicks one based on `Content-Type`:", + "description": "- **`application/json`** (temps-native): `{path, contents_b64, mode}`\n \u2014 one file, base64-encoded.\n- **`application/gzip`** (`@vercel/sandbox`): a gzipped tarball of\n one-or-more entries, with the target extract dir carried in the\n `x-cwd` header. The SDK's `writeFile` and `writeFiles` both post\n here; they differ only in how many entries the tarball contains.\n\nWhy merge them on one route: the SDK is hardcoded to\n`POST /fs/write`, so splitting tar uploads onto a separate path would\nforce us to break SDK compat. Instead we dispatch on Content-Type,\npreserve JSON for native callers, and add tar for SDK callers.", + "operationId": "write_file", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WriteFileBody" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "File(s) written" + }, + "400": { + "description": "Validation error or invalid base64" + }, + "404": { + "description": "Sandbox not found" + }, + "415": { + "description": "Unsupported Content-Type (expected application/json or application/gzip)" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/v1/sandboxes/{id}/fs/write-batch": { + "post": { + "tags": [ + "Sandboxes" + ], + "summary": "Batch-write multiple files in a single request. Mirrors\n`@vercel/sandbox` `writeFiles()`. Semantics are fail-fast: if any\nfile errors, previously-written entries are left in place and the\nerror describes which file broke.", + "operationId": "write_files", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WriteFilesBody" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "All files written", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WriteFilesResponse" + } + } + } + }, + "400": { + "description": "Validation error or invalid base64" + }, + "404": { + "description": "Sandbox not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/v1/sandboxes/{id}/jobs": { + "get": { + "tags": [ + "Sandboxes" + ], + "operationId": "list_jobs", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Detached jobs for this sandbox", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListJobsResponse" + } + } + } + }, + "404": { + "description": "Sandbox not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/v1/sandboxes/{id}/jobs/{job_id}": { + "get": { + "tags": [ + "Sandboxes" + ], + "operationId": "job_status", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "job_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Job status snapshot", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/JobStatusResponse" + } + } + } + }, + "404": { + "description": "Sandbox or job not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/v1/sandboxes/{id}/jobs/{job_id}/kill": { + "post": { + "tags": [ + "Sandboxes" + ], + "summary": "Terminate a detached job. Aborts the server-side tracking task and\nsends SIGTERM (or SIGKILL if `force=true`) to any matching processes\ninside the sandbox container. Returns 204 on success; 404 if the\nsandbox or job is unknown.", + "operationId": "kill_job", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "job_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KillJobBody" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Job killed" + }, + "404": { + "description": "Sandbox or job not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/v1/sandboxes/{id}/jobs/{job_id}/logs": { + "get": { + "tags": [ + "Sandboxes" + ], + "summary": "SSE endpoint streaming each stdout/stderr line from a detached job\nas it's produced. Mirrors the `Command.logs()` async iterator shape\non `@vercel/sandbox` \u2014 events carry `{ stream, data }`.", + "description": "Late subscribers only see events produced after they connect. The\nJobState snapshot (`GET /jobs/{job_id}`) covers the history.\n\nA \"done\" sentinel event fires when the broadcast channel closes\n(the exec task has exited and dropped the sender), signalling\ncallers they can stop reading.", + "operationId": "job_logs", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "job_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "SSE stream of log events" + }, + "404": { + "description": "Sandbox or job not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/v1/sandboxes/{id}/pause": { + "post": { + "tags": [ + "Sandboxes" + ], + "operationId": "pause_sandbox", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Sandbox paused (container stopped, state preserved)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxResponse" + } + } + } + }, + "404": { + "description": "Not found" + }, + "409": { + "description": "Sandbox is in an incompatible state (e.g. already destroyed)" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/v1/sandboxes/{id}/preview-link": { + "post": { + "tags": [ + "Sandboxes" + ], + "summary": "Mint a shareable link to a sandbox preview.", + "description": "`GET /domain` returns the bare preview URL, which is useless to anyone who\ndoes not already hold the sandbox's preview password \u2014 so sharing a\nprotected preview meant sharing that password, which is the same secret for\nevery recipient and can only be withdrawn by rotating it for all of them.\n\nThis returns the same URL carrying a short-lived, sandbox-scoped grant. The\nrecipient's browser exchanges it for the ordinary preview cookie and lands\non `path`. The grant never reaches the sandbox, so preview application code\ncannot read it and re-share it.\n\nAnyone holding the returned URL can view the preview until it expires;\nthere is no per-link revocation short of rotating the preview password.", + "operationId": "sandbox_create_preview_link", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PreviewShareLinkBody" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Shareable preview link", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PreviewShareLinkResponse" + } + } + } + }, + "400": { + "description": "Invalid port" + }, + "404": { + "description": "Sandbox not found" + }, + "409": { + "description": "Sandbox has no preview password" + }, + "500": { + "description": "Preview grant minting failed" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/v1/sandboxes/{id}/preview-password": { + "put": { + "tags": [ + "Sandboxes" + ], + "operationId": "set_preview_password", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetPreviewPasswordBody" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Preview password set or rotated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetPreviewPasswordResponse" + } + } + } + }, + "400": { + "description": "Password too short or too long" + }, + "404": { + "description": "Sandbox not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "Sandboxes" + ], + "operationId": "clear_preview_password", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Preview password removed (sandbox is now URL-only protected)" + }, + "404": { + "description": "Sandbox not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/v1/sandboxes/{id}/resize": { + "post": { + "tags": [ + "Sandboxes" + ], + "summary": "Grow a Firecracker sandbox's root disk. Offline resize \u2014 the VM reboots\n(filesystem/data persist) rather than resizing fully live.", + "operationId": "resize_sandbox", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResizeSandboxBody" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Resized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxResponse" + } + } + } + }, + "400": { + "description": "Invalid size or unsupported backend" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/v1/sandboxes/{id}/restart": { + "post": { + "tags": [ + "Sandboxes" + ], + "operationId": "restart_sandbox", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Sandbox container restarted in place", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxResponse" + } + } + } + }, + "404": { + "description": "Not found" + }, + "409": { + "description": "Sandbox is stopped (use /resume) or already destroyed" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/v1/sandboxes/{id}/resume": { + "post": { + "tags": [ + "Sandboxes" + ], + "operationId": "resume_sandbox", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Sandbox resumed; expires_at refreshed", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxResponse" + } + } + } + }, + "404": { + "description": "Not found" + }, + "409": { + "description": "Sandbox is not in a resumable state" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/v1/sandboxes/{id}/source": { + "post": { + "tags": [ + "Sandboxes" + ], + "operationId": "source_sandbox", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SourceBody" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Source content seeded into the sandbox work dir", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxResponse" + } + } + } + }, + "400": { + "description": "Validation error (embedded creds, conflicting fields, etc.)" + }, + "404": { + "description": "Sandbox not found" + }, + "409": { + "description": "Sandbox is not running" + }, + "500": { + "description": "Source seed failed inside sandbox" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/v1/sandboxes/{id}/stop": { + "post": { + "tags": [ + "Sandboxes" + ], + "operationId": "stop_sandbox", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Sandbox stopped and destroyed" + }, + "404": { + "description": "Not found" + }, + "409": { + "description": "Sandbox belongs to an active agent run \u2014 stop the run instead" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/v1/sandboxes/{id}/{cmd_id}/kill": { + "post": { + "tags": [ + "Sandboxes" + ], + "summary": "Kill a running command (`@vercel/sandbox`-compatible). The SDK\ncalls `POST /v1/sandboxes/{id}/{cmdId}/kill` \u2014 note the path has the\ncommand ID directly under the sandbox, NOT under `/jobs/` or `/cmd/`.", + "operationId": "cmd_kill", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "cmd_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CmdKillBody" + } + } + } + }, + "responses": { + "200": { + "description": "Command killed; returns final snapshot", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CmdResponse" + } + } + } + }, + "404": { + "description": "Sandbox or command not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/visitors/{visitor_id}/session-replays": { + "get": { + "tags": [ + "Analytics" + ], + "summary": "Get session replays for a visitor", + "operationId": "get_visitor_sessions", + "parameters": [ + { + "name": "visitor_id", + "in": "path", + "description": "Visitor ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "page", + "in": "query", + "description": "Page number (1-based)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "per_page", + "in": "query", + "description": "Items per page", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "Session replays retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetVisitorSessionsResponse" + } + } + } + }, + "401": { + "description": "Authentication required", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/visitors/{visitor_id}/session-replays/{session_id}": { + "get": { + "tags": [ + "Analytics" + ], + "summary": "Get session replay data with visitor info (without events)", + "operationId": "get_session_replay", + "parameters": [ + { + "name": "visitor_id", + "in": "path", + "description": "Visitor ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "session_id", + "in": "path", + "description": "Session ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Session replay retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetSessionReplayResponse" + } + } + } + }, + "401": { + "description": "Authentication required", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Session not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "Analytics" + ], + "summary": "Delete a session replay", + "operationId": "delete_session_replay", + "parameters": [ + { + "name": "visitor_id", + "in": "path", + "description": "Visitor ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "session_id", + "in": "path", + "description": "Session ID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Session replay deleted successfully" + }, + "401": { + "description": "Authentication required", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Session not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/visitors/{visitor_id}/session-replays/{session_id}/duration": { + "put": { + "tags": [ + "Analytics" + ], + "summary": "Update session duration", + "operationId": "update_session_duration", + "parameters": [ + { + "name": "visitor_id", + "in": "path", + "description": "Visitor ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "session_id", + "in": "path", + "description": "Session ID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateSessionDurationRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Session duration updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateSessionDurationResponse" + } + } + } + }, + "401": { + "description": "Authentication required", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Session not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/visitors/{visitor_id}/session-replays/{session_id}/events": { + "get": { + "tags": [ + "Analytics" + ], + "summary": "Get session replay events (with session and visitor metadata)", + "operationId": "get_session_replay_events", + "parameters": [ + { + "name": "visitor_id", + "in": "path", + "description": "Visitor ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "session_id", + "in": "path", + "description": "Session ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Session replay with events retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionReplayWithEventsDto" + } + } + } + }, + "401": { + "description": "Authentication required", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Session not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "post": { + "tags": [ + "Analytics" + ], + "summary": "Add events to an existing session", + "operationId": "add_events", + "parameters": [ + { + "name": "visitor_id", + "in": "path", + "description": "Visitor ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "session_id", + "in": "path", + "description": "Session ID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddEventsRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Events added successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddEventsResponse" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Authentication required", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Session not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/vulnerability-scans/{scan_id}": { + "get": { + "tags": [ + "Vulnerability Scans" + ], + "operationId": "get_scan", + "parameters": [ + { + "name": "scan_id", + "in": "path", + "description": "Scan ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Scan details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScanResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Scan not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + }, + "delete": { + "tags": [ + "Vulnerability Scans" + ], + "operationId": "delete_scan", + "parameters": [ + { + "name": "scan_id", + "in": "path", + "description": "Scan ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Scan deleted" + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Scan not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/vulnerability-scans/{scan_id}/vulnerabilities": { + "get": { + "tags": [ + "Vulnerability Scans" + ], + "operationId": "get_scan_vulnerabilities", + "parameters": [ + { + "name": "scan_id", + "in": "path", + "description": "Scan ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "page", + "in": "query", + "description": "Page number (default: 1)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "page_size", + "in": "query", + "description": "Page size (default: 20, max: 100)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "severity", + "in": "query", + "description": "Filter by severity (CRITICAL, HIGH, MEDIUM, LOW)", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "List of vulnerabilities", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/VulnerabilityResponse" + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Scan not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/webhook-event-types": { + "get": { + "tags": [ + "Webhooks" + ], + "summary": "List available event types", + "operationId": "list_event_types", + "responses": { + "200": { + "description": "List of available event types", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EventTypeResponse" + } + } + } + } + } + } + } + }, + "/weekly-digest/trigger": { + "post": { + "tags": [ + "Notification Preferences" + ], + "summary": "Trigger weekly digest generation manually", + "operationId": "trigger_weekly_digest", + "responses": { + "200": { + "description": "Weekly digest triggered successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TriggerDigestResponse" + } + } + } + }, + "500": { + "description": "Failed to generate digest" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/x/plugins": { + "get": { + "tags": [ + "External Plugins" + ], + "summary": "List all running external plugins and their manifests.", + "description": "Requires only a valid session/token (no specific permission) since the\nmanifest drives sidebar navigation rendering for every authenticated\nuser, not just admins.", + "operationId": "list_external_plugins", + "responses": { + "200": { + "description": "List of all running external plugins", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PluginManifest" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/x/plugins/reload": { + "post": { + "tags": [ + "External Plugins" + ], + "summary": "Reload all external plugins.", + "description": "Stops all running plugin processes, re-scans the plugins directory,\nstarts any discovered binaries, and hot-swaps the proxy router so new\nand removed plugins take effect immediately without a server restart.\n\nRequires `SystemAdmin` permission.", + "operationId": "reload_plugins", + "responses": { + "200": { + "description": "Plugins reloaded successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReloadResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/{project_id}/envelope/": { + "post": { + "tags": [ + "sentry-ingestor" + ], + "summary": "Ingest a Sentry envelope (binary payload)", + "operationId": "ingest_sentry_envelope", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "description": "Sentry envelope as binary data", + "content": { + "application/octet-stream": { + "schema": { + "type": "string" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Envelope ingested" + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "413": { + "description": "Request body too large (exceeds 2 MiB)" + } + } + } + }, + "/{project_id}/store/": { + "post": { + "tags": [ + "sentry-ingestor" + ], + "summary": "Ingest a Sentry event (JSON payload)", + "operationId": "ingest_sentry_event", + "parameters": [ + { + "name": "project_id", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SentryEventRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Event ingested", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SentryEventResponse" + } + } + } + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "413": { + "description": "Request body too large (exceeds 2 MiB)" + } + } + } + }, + "audit/logs": { + "get": { + "tags": [ + "Audit Logs" + ], + "summary": "List audit logs with optional filtering", + "operationId": "list_audit_logs", + "parameters": [ + { + "name": "operation_type", + "in": "query", + "description": "Filter logs by operation type (omit for all)", + "required": false, + "schema": { + "type": "string" + }, + "example": "user.login" + }, + { + "name": "user_id", + "in": "query", + "description": "Filter logs by user ID (omit for all users)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + }, + "example": 1 + }, + { + "name": "from", + "in": "query", + "description": "Start timestamp (milliseconds since epoch)", + "required": false, + "schema": { + "type": "string", + "format": "date-time" + }, + "example": 1 + }, + { + "name": "to", + "in": "query", + "description": "End timestamp (milliseconds since epoch)", + "required": false, + "schema": { + "type": "string", + "format": "date-time" + }, + "example": 1 + }, + { + "name": "limit", + "in": "query", + "description": "Maximum number of logs to return", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + }, + "example": 100 + }, + { + "name": "offset", + "in": "query", + "description": "Number of logs to skip", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + }, + "example": 0 + } + ], + "responses": { + "200": { + "description": "List of audit logs", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AuditLogResponse" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "api_key": [] + } + ] + } + }, + "audit/logs/{id}": { + "get": { + "tags": [ + "Audit Logs" + ], + "summary": "Get a specific audit log entry by ID", + "operationId": "get_audit_log", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Audit log details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuditLogResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Audit log not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "api_key": [] + } + ] + } + }, + "/cloud": { + "delete": { + "tags": [ + "Cloud" + ], + "operationId": "disconnect_cloud", + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CloudStatus" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/cloud/capability": { + "get": { + "tags": [ + "Cloud" + ], + "operationId": "get_cloud_capability", + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CloudCapability" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/cloud/enroll": { + "post": { + "tags": [ + "Cloud" + ], + "operationId": "enroll_cloud", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnrollCloudRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CloudStatus" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, + "/cloud/status": { + "get": { + "tags": [ + "Cloud" + ], + "operationId": "get_cloud_status", + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CloudStatus" + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + } + }, + "servers": [ + { + "url": "/api", + "description": "Base path for all API endpoints" + } + ], + "tags": [ + { + "name": "Events", + "description": "Analytics events tracking endpoints" + }, + { + "name": "Metrics", + "description": "Analytics metrics collection endpoints including performance web vitals" + }, + { + "name": "Funnels", + "description": "Funnel management endpoints" + }, + { + "name": "Analytics", + "description": "Analytics and session replay management" + }, + { + "name": "Performance", + "description": "Performance metrics management" + }, + { + "name": "geo", + "description": "Geolocation API endpoints" + }, + { + "name": "Platform", + "description": "Platform information and compatibility" + }, + { + "name": "Teams", + "description": "Teams and project-scoped access" + }, + { + "name": "Git Providers", + "description": "Git provider management endpoints" + }, + { + "name": "Repositories", + "description": "Repository management endpoints" + }, + { + "name": "Public Repositories", + "description": "Endpoints for accessing public repositories without authentication. Supports GitHub and GitLab." + }, + { + "name": "Notification Providers", + "description": "Notification provider management endpoints" + }, + { + "name": "Notification Preferences", + "description": "User notification preferences and settings" + }, + { + "name": "DNS Providers", + "description": "DNS provider management endpoints" + }, + { + "name": "Internal DNS", + "description": "Per-node DNS resolver sync (ADR-011)" + }, + { + "name": "Domains", + "description": "Domain management endpoints" + }, + { + "name": "Email Providers", + "description": "Email provider management endpoints" + }, + { + "name": "Email Domains", + "description": "Email domain management and verification" + }, + { + "name": "Emails", + "description": "Email sending and retrieval" + }, + { + "name": "Email Tracking", + "description": "Email open and click tracking" + }, + { + "name": "Email Validation", + "description": "Email address validation and verification" + }, + { + "name": "Webhooks", + "description": "Webhook management endpoints" + }, + { + "name": "Webhook Deliveries", + "description": "Webhook delivery history and retry endpoints" + }, + { + "name": "External Services", + "description": "External service integration endpoints" + }, + { + "name": "External Services - Query", + "description": "Data querying and exploration endpoints" + }, + { + "name": "Metrics", + "description": "Time-series metrics and alert rule endpoints" + }, + { + "name": "KV Store", + "description": "Key-Value storage operations" + }, + { + "name": "KV Management", + "description": "KV service management operations" + }, + { + "name": "Blob", + "description": "Blob storage operations" + }, + { + "name": "Blob Management", + "description": "Blob service management operations" + }, + { + "name": "Feature Flags", + "description": "Runtime configuration that changes without a redeploy" + }, + { + "name": "Environments", + "description": "Environment management operations" + }, + { + "name": "Secrets", + "description": "File-mounted secrets (/run/secrets/)" + }, + { + "name": "Projects", + "description": "Project management endpoints" + }, + { + "name": "Presets", + "description": "Available deployment presets" + }, + { + "name": "Templates", + "description": "Project template endpoints" + }, + { + "name": "Custom Domains", + "description": "Custom domain management for projects" + }, + { + "name": "error-tracking", + "description": "Error tracking data fetching endpoints" + }, + { + "name": "Vulnerability Scans", + "description": "Vulnerability scan management endpoints" + }, + { + "name": "Agents", + "description": "Autonomous AI agents, autofixer (interactive AI debugging), skills/MCP definitions, and preview gateway management." + }, + { + "name": "Crons", + "description": "Cron jobs management API" + }, + { + "name": "Sandboxes", + "description": "Standalone sandbox API (`/v1/sandboxes/*`) for running isolated containers." + }, + { + "name": "Logs", + "description": "Log search, context, live tail, and retention management" + }, + { + "name": "Imports", + "description": "Import workloads from external sources" + }, + { + "name": "Status Page", + "description": "Status page and monitoring endpoints" + }, + { + "name": "OTel Ingest", + "description": "OTLP/HTTP ingest endpoints (protobuf)" + }, + { + "name": "OTel", + "description": "Query endpoints for the monitoring UI" + }, + { + "name": "GenAI", + "description": "GenAI agent activity tracing endpoints" + }, + { + "name": "Alarms", + "description": "Unified alarm history \u2014 list, summarise, acknowledge, resolve" + }, + { + "name": "Authentication", + "description": "Authentication and authorization endpoints" + }, + { + "name": "Users", + "description": "User management endpoints" + }, + { + "name": "Backups", + "description": "Backup management endpoints" + }, + { + "name": "Restore", + "description": "External service restore operations" + }, + { + "name": "Revenue", + "description": "Per-project revenue tracking integrations and analytics" + }, + { + "name": "Observability", + "description": "Unified observability event stream \u2014 runtime logs, requests, spans, errors, revenue" + }, + { + "name": "AI Gateway", + "description": "OpenAI-compatible chat, embeddings, and model endpoints" + }, + { + "name": "AI Gateway Admin", + "description": "Provider key management endpoints" + }, + { + "name": "AI Gateway Usage", + "description": "Usage analytics and reporting endpoints" + }, + { + "name": "AI Gateway Pricing", + "description": "Model pricing endpoints" + }, + { + "name": "API Keys", + "description": "API key management endpoints" + }, + { + "name": "Load Balancer", + "description": "Load balancer management endpoints" + }, + { + "name": "IP Access Control", + "description": "IP access control management endpoints" + }, + { + "name": "Files", + "description": "Static file serving endpoints" + }, + { + "name": "External Plugins", + "description": "External plugin management and discovery" + } + ] +} diff --git a/apps/temps-cli/src/api/client.gen.ts b/apps/temps-cli/src/api/client.gen.ts index 62947795d..4d2221c90 100644 --- a/apps/temps-cli/src/api/client.gen.ts +++ b/apps/temps-cli/src/api/client.gen.ts @@ -1,6 +1,6 @@ // This file is auto-generated by @hey-api/openapi-ts -import { type ClientOptions, type Config, createClient, createConfig } from './client'; +import { type Client, type ClientOptions, type Config, createClient, createConfig } from './client'; import type { ClientOptions as ClientOptions2 } from './types.gen'; /** @@ -13,4 +13,4 @@ import type { ClientOptions as ClientOptions2 } from './types.gen'; */ export type CreateClientConfig = (override?: Config) => Config & T>; -export const client = createClient(createConfig({ baseUrl: '/api' })); +export const client: Client = createClient(createConfig({ baseUrl: '/api' })); diff --git a/apps/temps-cli/src/api/client/client.gen.ts b/apps/temps-cli/src/api/client/client.gen.ts index c2a5190c2..fc3f037f1 100644 --- a/apps/temps-cli/src/api/client/client.gen.ts +++ b/apps/temps-cli/src/api/client/client.gen.ts @@ -3,12 +3,7 @@ import { createSseClient } from '../core/serverSentEvents.gen'; import type { HttpMethod } from '../core/types.gen'; import { getValidRequestBody } from '../core/utils.gen'; -import type { - Client, - Config, - RequestOptions, - ResolvedRequestOptions, -} from './types.gen'; +import type { Client, Config, RequestOptions, ResolvedRequestOptions } from './types.gen'; import { buildUrl, createConfig, @@ -34,27 +29,26 @@ export const createClient = (config: Config = {}): Client => { return getConfig(); }; - const interceptors = createInterceptors< - Request, - Response, - unknown, - ResolvedRequestOptions - >(); + const interceptors = createInterceptors(); - const beforeRequest = async (options: RequestOptions) => { + const beforeRequest = async < + TData = unknown, + TResponseStyle extends 'data' | 'fields' = 'fields', + ThrowOnError extends boolean = boolean, + Url extends string = string, + >( + options: RequestOptions, + ) => { const opts = { ..._config, ...options, fetch: options.fetch ?? _config.fetch ?? globalThis.fetch, headers: mergeHeaders(_config.headers, options.headers), - serializedBody: undefined, + serializedBody: undefined as string | undefined, }; if (opts.security) { - await setAuthParams({ - ...opts, - security: opts.security, - }); + await setAuthParams(opts); } if (opts.requestValidator) { @@ -62,7 +56,7 @@ export const createClient = (config: Config = {}): Client => { } if (opts.body !== undefined && opts.bodySerializer) { - opts.serializedBody = opts.bodySerializer(opts.body); + opts.serializedBody = opts.bodySerializer(opts.body) as string | undefined; } // remove Content-Type header if body is empty to avoid sending invalid requests @@ -70,209 +64,191 @@ export const createClient = (config: Config = {}): Client => { opts.headers.delete('Content-Type'); } - const url = buildUrl(opts); + const resolvedOpts = opts as typeof opts & + ResolvedRequestOptions; + const url = buildUrl(resolvedOpts); - return { opts, url }; + return { opts: resolvedOpts, url }; }; const request: Client['request'] = async (options) => { - // @ts-expect-error - const { opts, url } = await beforeRequest(options); - const requestInit: ReqInit = { - redirect: 'follow', - ...opts, - body: getValidRequestBody(opts), - }; + const throwOnError = options.throwOnError ?? _config.throwOnError; + const responseStyle = options.responseStyle ?? _config.responseStyle; - let request = new Request(url, requestInit); - - for (const fn of interceptors.request.fns) { - if (fn) { - request = await fn(request, opts); - } - } - - // fetch must be assigned here, otherwise it would throw the error: - // TypeError: Failed to execute 'fetch' on 'Window': Illegal invocation - const _fetch = opts.fetch!; - let response: Response; + let request: Request | undefined; + let response: Response | undefined; try { - response = await _fetch(request); - } catch (error) { - // Handle fetch exceptions (AbortError, network errors, etc.) - let finalError = error; + const { opts, url } = await beforeRequest(options); + const requestInit: ReqInit = { + redirect: 'follow', + ...opts, + body: getValidRequestBody(opts), + }; - for (const fn of interceptors.error.fns) { + request = new Request(url, requestInit); + + for (const fn of interceptors.request.fns) { if (fn) { - finalError = (await fn( - error, - undefined as any, - request, - opts, - )) as unknown; + request = await fn(request, opts); } } - finalError = finalError || ({} as unknown); + // fetch must be assigned here, otherwise it would throw the error: + // TypeError: Failed to execute 'fetch' on 'Window': Illegal invocation + const _fetch = opts.fetch!; - if (opts.throwOnError) { - throw finalError; - } - - // Return error response - return opts.responseStyle === 'data' - ? undefined - : { - error: finalError, - request, - response: undefined as any, - }; - } + response = await _fetch(request); - for (const fn of interceptors.response.fns) { - if (fn) { - response = await fn(response, request, opts); + for (const fn of interceptors.response.fns) { + if (fn) { + response = await fn(response, request, opts); + } } - } - const result = { - request, - response, - }; + const result = { + request, + response, + }; + + if (response.ok) { + const parseAs = + (opts.parseAs === 'auto' + ? getParseAs(response.headers.get('Content-Type')) + : opts.parseAs) ?? 'json'; + + if (response.status === 204 || response.headers.get('Content-Length') === '0') { + let emptyData: any; + switch (parseAs) { + case 'arrayBuffer': + case 'blob': + case 'text': + emptyData = await response[parseAs](); + break; + case 'formData': + emptyData = new FormData(); + break; + case 'stream': + emptyData = response.body; + break; + case 'json': + default: + emptyData = {}; + break; + } + return opts.responseStyle === 'data' + ? emptyData + : { + data: emptyData, + ...result, + }; + } - if (response.ok) { - const parseAs = - (opts.parseAs === 'auto' - ? getParseAs(response.headers.get('Content-Type')) - : opts.parseAs) ?? 'json'; - - if ( - response.status === 204 || - response.headers.get('Content-Length') === '0' - ) { - let emptyData: any; + let data: any; switch (parseAs) { case 'arrayBuffer': case 'blob': + case 'formData': case 'text': - emptyData = await response[parseAs](); + data = await response[parseAs](); break; - case 'formData': - emptyData = new FormData(); + case 'json': { + // Some servers return 200 with no Content-Length and empty body. + // response.json() would throw; read as text and parse if non-empty. + const text = await response.text(); + data = text ? JSON.parse(text) : {}; break; + } case 'stream': - emptyData = response.body; - break; - case 'json': - default: - emptyData = {}; - break; + return opts.responseStyle === 'data' + ? response.body + : { + data: response.body, + ...result, + }; } + + if (parseAs === 'json') { + if (opts.responseValidator) { + await opts.responseValidator(data); + } + + if (opts.responseTransformer) { + data = await opts.responseTransformer(data); + } + } + return opts.responseStyle === 'data' - ? emptyData + ? data : { - data: emptyData, + data, ...result, }; } - let data: any; - switch (parseAs) { - case 'arrayBuffer': - case 'blob': - case 'formData': - case 'json': - case 'text': - data = await response[parseAs](); - break; - case 'stream': - return opts.responseStyle === 'data' - ? response.body - : { - data: response.body, - ...result, - }; + const textError = await response.text(); + let jsonError: unknown; + + try { + jsonError = JSON.parse(textError); + } catch { + // noop } - if (parseAs === 'json') { - if (opts.responseValidator) { - await opts.responseValidator(data); - } + throw jsonError ?? textError; + } catch (error) { + let finalError = error; - if (opts.responseTransformer) { - data = await opts.responseTransformer(data); + for (const fn of interceptors.error.fns) { + if (fn) { + finalError = await fn(finalError, response, request, options as ResolvedRequestOptions); } } - return opts.responseStyle === 'data' - ? data - : { - data, - ...result, - }; - } + finalError = finalError || {}; - const textError = await response.text(); - let jsonError: unknown; - - try { - jsonError = JSON.parse(textError); - } catch { - // noop - } - - const error = jsonError ?? textError; - let finalError = error; - - for (const fn of interceptors.error.fns) { - if (fn) { - finalError = (await fn(error, response, request, opts)) as string; + if (throwOnError) { + throw finalError; } - } - finalError = finalError || ({} as string); - - if (opts.throwOnError) { - throw finalError; + // TODO: we probably want to return error and improve types + return responseStyle === 'data' + ? undefined + : { + error: finalError, + request, + response, + }; } - - // TODO: we probably want to return error and improve types - return opts.responseStyle === 'data' - ? undefined - : { - error: finalError, - ...result, - }; }; - const makeMethodFn = - (method: Uppercase) => (options: RequestOptions) => - request({ ...options, method }); + const makeMethodFn = (method: Uppercase) => (options: RequestOptions) => + request({ ...options, method }); - const makeSseFn = - (method: Uppercase) => async (options: RequestOptions) => { - const { opts, url } = await beforeRequest(options); - return createSseClient({ - ...opts, - body: opts.body as BodyInit | null | undefined, - headers: opts.headers as unknown as Record, - method, - onRequest: async (url, init) => { - let request = new Request(url, init); - for (const fn of interceptors.request.fns) { - if (fn) { - request = await fn(request, opts); - } + const makeSseFn = (method: Uppercase) => async (options: RequestOptions) => { + const { opts, url } = await beforeRequest(options); + return createSseClient({ + ...opts, + body: opts.body as BodyInit | null | undefined, + method, + onRequest: async (url, init) => { + let request = new Request(url, init); + for (const fn of interceptors.request.fns) { + if (fn) { + request = await fn(request, opts); } - return request; - }, - url, - }); - }; + } + return request; + }, + serializedBody: getValidRequestBody(opts) as BodyInit | null | undefined, + url, + }); + }; + + const _buildUrl: Client['buildUrl'] = (options) => buildUrl({ ..._config, ...options }); return { - buildUrl, + buildUrl: _buildUrl, connect: makeMethodFn('CONNECT'), delete: makeMethodFn('DELETE'), get: makeMethodFn('GET'), diff --git a/apps/temps-cli/src/api/client/index.ts b/apps/temps-cli/src/api/client/index.ts index b295edeca..8c693310d 100644 --- a/apps/temps-cli/src/api/client/index.ts +++ b/apps/temps-cli/src/api/client/index.ts @@ -9,6 +9,8 @@ export { } from '../core/bodySerializer.gen'; export { buildClientParams } from '../core/params.gen'; export { serializeQueryKeyValue } from '../core/queryKeySerializer.gen'; +export type { ServerSentEventsResult } from '../core/serverSentEvents.gen'; +export type { ClientMeta } from '../core/types.gen'; export { createClient } from './client.gen'; export type { Client, diff --git a/apps/temps-cli/src/api/client/types.gen.ts b/apps/temps-cli/src/api/client/types.gen.ts index b4a499cc0..193646cdd 100644 --- a/apps/temps-cli/src/api/client/types.gen.ts +++ b/apps/temps-cli/src/api/client/types.gen.ts @@ -5,17 +5,13 @@ import type { ServerSentEventsOptions, ServerSentEventsResult, } from '../core/serverSentEvents.gen'; -import type { - Client as CoreClient, - Config as CoreConfig, -} from '../core/types.gen'; +import type { Client as CoreClient, Config as CoreConfig } from '../core/types.gen'; import type { Middleware } from './utils.gen'; export type ResponseStyle = 'data' | 'fields'; export interface Config - extends Omit, - CoreConfig { + extends Omit, CoreConfig { /** * Base URL for all requests made by this client. */ @@ -42,14 +38,7 @@ export interface Config * * @default 'auto' */ - parseAs?: - | 'arrayBuffer' - | 'auto' - | 'blob' - | 'formData' - | 'json' - | 'stream' - | 'text'; + parseAs?: 'arrayBuffer' | 'auto' | 'blob' | 'formData' | 'json' | 'stream' | 'text'; /** * Should we return only data or multiple fields (data, error, response, etc.)? * @@ -69,12 +58,15 @@ export interface RequestOptions< TResponseStyle extends ResponseStyle = 'fields', ThrowOnError extends boolean = boolean, Url extends string = string, -> extends Config<{ +> + extends + Config<{ responseStyle: TResponseStyle; throwOnError: ThrowOnError; }>, Pick< ServerSentEventsOptions, + | 'onRequest' | 'onSseError' | 'onSseEvent' | 'sseDefaultRetryDelay' @@ -101,6 +93,7 @@ export interface ResolvedRequestOptions< ThrowOnError extends boolean = boolean, Url extends string = string, > extends RequestOptions { + headers: Headers; serializedBody?: string; } @@ -116,36 +109,28 @@ export type RequestResult< ? TData[keyof TData] : TData : { - data: TData extends Record - ? TData[keyof TData] - : TData; + data: TData extends Record ? TData[keyof TData] : TData; request: Request; response: Response; } > : Promise< TResponseStyle extends 'data' - ? - | (TData extends Record - ? TData[keyof TData] - : TData) - | undefined + ? (TData extends Record ? TData[keyof TData] : TData) | undefined : ( | { - data: TData extends Record - ? TData[keyof TData] - : TData; + data: TData extends Record ? TData[keyof TData] : TData; error: undefined; } | { data: undefined; - error: TError extends Record - ? TError[keyof TError] - : TError; + error: TError extends Record ? TError[keyof TError] : TError; } ) & { - request: Request; - response: Response; + /** request may be undefined, because error may be from building the request object itself */ + request?: Request; + /** response may be undefined, because error may be from building the request object itself or from a network error */ + response?: Response; } >; @@ -166,12 +151,13 @@ type MethodFn = < type SseFn = < TData = unknown, - TError = unknown, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + _TError = unknown, ThrowOnError extends boolean = false, TResponseStyle extends ResponseStyle = 'fields', >( - options: Omit, 'method'>, -) => Promise>; + options: Omit, 'method'>, +) => Promise>; type RequestFn = < TData = unknown, @@ -180,10 +166,7 @@ type RequestFn = < TResponseStyle extends ResponseStyle = 'fields', >( options: Omit, 'method'> & - Pick< - Required>, - 'method' - >, + Pick>, 'method'>, ) => RequestResult; type BuildUrlFn = < @@ -197,13 +180,7 @@ type BuildUrlFn = < options: TData & Options, ) => string; -export type Client = CoreClient< - RequestFn, - Config, - MethodFn, - BuildUrlFn, - SseFn -> & { +export type Client = CoreClient & { interceptors: Middleware; }; diff --git a/apps/temps-cli/src/api/client/utils.gen.ts b/apps/temps-cli/src/api/client/utils.gen.ts index 4c48a9ee1..d4a728438 100644 --- a/apps/temps-cli/src/api/client/utils.gen.ts +++ b/apps/temps-cli/src/api/client/utils.gen.ts @@ -14,8 +14,8 @@ import type { Client, ClientOptions, Config, RequestOptions } from './types.gen' export const createQuerySerializer = ({ parameters = {}, ...args -}: QuerySerializerOptions = {}) => { - const querySerializer = (queryParams: T) => { +}: QuerySerializerOptions = {}): ((queryParams: T) => string) => { + const querySerializer = (queryParams: T): string => { const search: string[] = []; if (queryParams && typeof queryParams === 'object') { for (const name in queryParams) { @@ -65,9 +65,7 @@ export const createQuerySerializer = ({ /** * Infers parseAs value from provided Content-Type header. */ -export const getParseAs = ( - contentType: string | null, -): Exclude => { +export const getParseAs = (contentType: string | null): Exclude => { if (!contentType) { // If no Content-Type header is provided, the best we can do is return the raw response body, // which is effectively the same as the 'stream' option. @@ -80,10 +78,7 @@ export const getParseAs = ( return; } - if ( - cleanContent.startsWith('application/json') || - cleanContent.endsWith('+json') - ) { + if (cleanContent.startsWith('application/json') || cleanContent.endsWith('+json')) { return 'json'; } @@ -92,9 +87,7 @@ export const getParseAs = ( } if ( - ['application/', 'audio/', 'image/', 'video/'].some((type) => - cleanContent.startsWith(type), - ) + ['application/', 'audio/', 'image/', 'video/'].some((type) => cleanContent.startsWith(type)) ) { return 'blob'; } @@ -125,14 +118,12 @@ const checkForExistence = ( return false; }; -export const setAuthParams = async ({ - security, - ...options -}: Pick, 'security'> & - Pick & { +export async function setAuthParams( + options: Pick & { headers: Headers; - }) => { - for (const auth of security) { + }, +): Promise { + for (const auth of options.security ?? []) { if (checkForExistence(options, auth.name)) { continue; } @@ -161,7 +152,7 @@ export const setAuthParams = async ({ break; } } -}; +} export const buildUrl: Client['buildUrl'] = (options) => getUrl({ @@ -201,10 +192,7 @@ export const mergeHeaders = ( continue; } - const iterator = - header instanceof Headers - ? headersEntries(header) - : Object.entries(header); + const iterator = header instanceof Headers ? headersEntries(header) : Object.entries(header); for (const [key, value] of iterator) { if (value === null) { @@ -214,7 +202,7 @@ export const mergeHeaders = ( mergedHeaders.append(key, v as string); } } else if (value !== undefined) { - // assume object headers are meant to be JSON stringified, i.e. their + // assume object headers are meant to be JSON stringified, i.e., their // content value in OpenAPI specification is 'application/json' mergedHeaders.set( key, @@ -228,15 +216,14 @@ export const mergeHeaders = ( type ErrInterceptor = ( error: Err, - response: Res, - request: Req, + /** response may be undefined due to a network error where no response object is produced */ + response: Res | undefined, + /** request may be undefined, because error may be from building the request object itself */ + request: Req | undefined, options: Options, ) => Err | Promise; -type ReqInterceptor = ( - request: Req, - options: Options, -) => Req | Promise; +type ReqInterceptor = (request: Req, options: Options) => Req | Promise; type ResInterceptor = ( response: Res, @@ -270,10 +257,7 @@ class Interceptors { return this.fns.indexOf(id); } - update( - id: number | Interceptor, - fn: Interceptor, - ): number | Interceptor | false { + update(id: number | Interceptor, fn: Interceptor): number | Interceptor | false { const index = this.getInterceptorIndex(id); if (this.fns[index]) { this.fns[index] = fn; diff --git a/apps/temps-cli/src/api/core/auth.gen.ts b/apps/temps-cli/src/api/core/auth.gen.ts index f8a73266f..c66366448 100644 --- a/apps/temps-cli/src/api/core/auth.gen.ts +++ b/apps/temps-cli/src/api/core/auth.gen.ts @@ -9,6 +9,13 @@ export interface Auth { * @default 'header' */ in?: 'header' | 'query' | 'cookie'; + /** + * A unique identifier for the security scheme. + * + * Defined only when there are multiple security schemes whose `Auth` + * shape would otherwise be identical. + */ + key?: string; /** * Header or query parameter name. * @@ -23,8 +30,7 @@ export const getAuthToken = async ( auth: Auth, callback: ((auth: Auth) => Promise | AuthToken) | AuthToken, ): Promise => { - const token = - typeof callback === 'function' ? await callback(auth) : callback; + const token = typeof callback === 'function' ? await callback(auth) : callback; if (!token) { return; diff --git a/apps/temps-cli/src/api/core/bodySerializer.gen.ts b/apps/temps-cli/src/api/core/bodySerializer.gen.ts index 552b50f7c..67daca60f 100644 --- a/apps/temps-cli/src/api/core/bodySerializer.gen.ts +++ b/apps/temps-cli/src/api/core/bodySerializer.gen.ts @@ -1,14 +1,10 @@ // This file is auto-generated by @hey-api/openapi-ts -import type { - ArrayStyle, - ObjectStyle, - SerializerOptions, -} from './pathSerializer.gen'; +import type { ArrayStyle, ObjectStyle, SerializerOptions } from './pathSerializer.gen'; export type QuerySerializer = (query: Record) => string; -export type BodySerializer = (body: any) => any; +export type BodySerializer = (body: unknown) => unknown; type QuerySerializerOptionsObject = { allowReserved?: boolean; @@ -24,11 +20,7 @@ export type QuerySerializerOptions = QuerySerializerOptionsObject & { parameters?: Record; }; -const serializeFormDataPair = ( - data: FormData, - key: string, - value: unknown, -): void => { +const serializeFormDataPair = (data: FormData, key: string, value: unknown): void => { if (typeof value === 'string' || value instanceof Blob) { data.append(key, value); } else if (value instanceof Date) { @@ -38,11 +30,7 @@ const serializeFormDataPair = ( } }; -const serializeUrlSearchParamsPair = ( - data: URLSearchParams, - key: string, - value: unknown, -): void => { +const serializeUrlSearchParamsPair = (data: URLSearchParams, key: string, value: unknown): void => { if (typeof value === 'string') { data.append(key, value); } else { @@ -51,12 +39,10 @@ const serializeUrlSearchParamsPair = ( }; export const formDataBodySerializer = { - bodySerializer: | Array>>( - body: T, - ): FormData => { + bodySerializer: (body: unknown): FormData => { const data = new FormData(); - Object.entries(body).forEach(([key, value]) => { + Object.entries(body as Record).forEach(([key, value]) => { if (value === undefined || value === null) { return; } @@ -72,19 +58,15 @@ export const formDataBodySerializer = { }; export const jsonBodySerializer = { - bodySerializer: (body: T): string => - JSON.stringify(body, (_key, value) => - typeof value === 'bigint' ? value.toString() : value, - ), + bodySerializer: (body: unknown): string => + JSON.stringify(body, (_key, value) => (typeof value === 'bigint' ? value.toString() : value)), }; export const urlSearchParamsBodySerializer = { - bodySerializer: | Array>>( - body: T, - ): string => { + bodySerializer: (body: unknown): string => { const data = new URLSearchParams(); - Object.entries(body).forEach(([key, value]) => { + Object.entries(body as Record).forEach(([key, value]) => { if (value === undefined || value === null) { return; } diff --git a/apps/temps-cli/src/api/core/params.gen.ts b/apps/temps-cli/src/api/core/params.gen.ts index 602715c46..5e8908f20 100644 --- a/apps/temps-cli/src/api/core/params.gen.ts +++ b/apps/temps-cli/src/api/core/params.gen.ts @@ -62,7 +62,7 @@ type KeyMap = Map< } >; -const buildKeyMap = (fields: FieldsConfig, map?: KeyMap): KeyMap => { +function buildKeyMap(fields: FieldsConfig, map?: KeyMap): KeyMap { if (!map) { map = new Map(); } @@ -85,36 +85,42 @@ const buildKeyMap = (fields: FieldsConfig, map?: KeyMap): KeyMap => { } return map; -}; +} interface Params { - body: unknown; + body?: unknown; headers: Record; path: Record; query: Record; } -const stripEmptySlots = (params: Params) => { +function stripEmptySlots(params: Params): void { for (const [slot, value] of Object.entries(params)) { - if (value && typeof value === 'object' && !Object.keys(value).length) { + if (slot === 'body') continue; + if (value && typeof value === 'object' && !Array.isArray(value) && !Object.keys(value).length) { delete params[slot as Slot]; } } -}; +} -export const buildClientParams = ( - args: ReadonlyArray, - fields: FieldsConfig, -) => { +export function buildClientParams(args: ReadonlyArray, fields: FieldsConfig): Params { const params: Params = { - body: {}, - headers: {}, - path: {}, - query: {}, + headers: Object.create(null), + path: Object.create(null), + query: Object.create(null), }; const map = buildKeyMap(fields); + function writeSlot(slot: Slot, key: string, value: unknown): void { + let record = params[slot] as Record | undefined; + if (record === undefined) { + record = Object.create(null) as Record; + params[slot] = record; + } + record[key] = value; + } + let config: FieldsConfig[number] | undefined; for (const [index, arg] of args.entries()) { @@ -131,7 +137,7 @@ export const buildClientParams = ( const field = map.get(config.key)!; const name = field.map || config.key; if (field.in) { - (params[field.in] as Record)[name] = arg; + writeSlot(field.in, name, arg); } } else { params.body = arg; @@ -143,24 +149,20 @@ export const buildClientParams = ( if (field) { if (field.in) { const name = field.map || key; - (params[field.in] as Record)[name] = value; + writeSlot(field.in, name, value); } else { params[field.map] = value; } } else { - const extra = extraPrefixes.find(([prefix]) => - key.startsWith(prefix), - ); + const extra = extraPrefixes.find(([prefix]) => key.startsWith(prefix)); if (extra) { const [prefix, slot] = extra; - (params[slot] as Record)[ - key.slice(prefix.length) - ] = value; + writeSlot(slot, key.slice(prefix.length), value); } else if ('allowExtra' in config && config.allowExtra) { for (const [slot, allowed] of Object.entries(config.allowExtra)) { if (allowed) { - (params[slot as Slot] as Record)[key] = value; + writeSlot(slot as Slot, key, value); break; } } @@ -173,4 +175,4 @@ export const buildClientParams = ( stripEmptySlots(params); return params; -}; +} diff --git a/apps/temps-cli/src/api/core/pathSerializer.gen.ts b/apps/temps-cli/src/api/core/pathSerializer.gen.ts index 8d9993104..fab1ed4b9 100644 --- a/apps/temps-cli/src/api/core/pathSerializer.gen.ts +++ b/apps/temps-cli/src/api/core/pathSerializer.gen.ts @@ -1,8 +1,6 @@ // This file is auto-generated by @hey-api/openapi-ts -interface SerializeOptions - extends SerializePrimitiveOptions, - SerializerOptions {} +interface SerializeOptions extends SerializePrimitiveOptions, SerializerOptions {} interface SerializePrimitiveOptions { allowReserved?: boolean; @@ -27,7 +25,7 @@ interface SerializePrimitiveParam extends SerializePrimitiveOptions { value: string; } -export const separatorArrayExplode = (style: ArraySeparatorStyle) => { +export const separatorArrayExplode = (style: ArraySeparatorStyle): '.' | ';' | ',' | '&' => { switch (style) { case 'label': return '.'; @@ -40,7 +38,7 @@ export const separatorArrayExplode = (style: ArraySeparatorStyle) => { } }; -export const separatorArrayNoExplode = (style: ArraySeparatorStyle) => { +export const separatorArrayNoExplode = (style: ArraySeparatorStyle): ',' | '|' | '%20' => { switch (style) { case 'form': return ','; @@ -53,7 +51,7 @@ export const separatorArrayNoExplode = (style: ArraySeparatorStyle) => { } }; -export const separatorObjectExplode = (style: ObjectSeparatorStyle) => { +export const separatorObjectExplode = (style: ObjectSeparatorStyle): '.' | ';' | ',' | '&' => { switch (style) { case 'label': return '.'; @@ -74,7 +72,7 @@ export const serializeArrayParam = ({ value, }: SerializeOptions & { value: unknown[]; -}) => { +}): string => { if (!explode) { const joinedValues = ( allowReserved ? value : value.map((v) => encodeURIComponent(v as string)) @@ -105,16 +103,14 @@ export const serializeArrayParam = ({ }); }) .join(separator); - return style === 'label' || style === 'matrix' - ? separator + joinedValues - : joinedValues; + return style === 'label' || style === 'matrix' ? separator + joinedValues : joinedValues; }; export const serializePrimitiveParam = ({ allowReserved, name, value, -}: SerializePrimitiveParam) => { +}: SerializePrimitiveParam): string => { if (value === undefined || value === null) { return ''; } @@ -138,7 +134,7 @@ export const serializeObjectParam = ({ }: SerializeOptions & { value: Record | Date; valueOnly?: boolean; -}) => { +}): string => { if (value instanceof Date) { return valueOnly ? value.toISOString() : `${name}=${value.toISOString()}`; } @@ -146,11 +142,7 @@ export const serializeObjectParam = ({ if (style !== 'deepObject' && !explode) { let values: string[] = []; Object.entries(value).forEach(([key, v]) => { - values = [ - ...values, - key, - allowReserved ? (v as string) : encodeURIComponent(v as string), - ]; + values = [...values, key, allowReserved ? (v as string) : encodeURIComponent(v as string)]; }); const joinedValues = values.join(','); switch (style) { @@ -175,7 +167,5 @@ export const serializeObjectParam = ({ }), ) .join(separator); - return style === 'label' || style === 'matrix' - ? separator + joinedValues - : joinedValues; + return style === 'label' || style === 'matrix' ? separator + joinedValues : joinedValues; }; diff --git a/apps/temps-cli/src/api/core/queryKeySerializer.gen.ts b/apps/temps-cli/src/api/core/queryKeySerializer.gen.ts index d3bb68396..773b0650b 100644 --- a/apps/temps-cli/src/api/core/queryKeySerializer.gen.ts +++ b/apps/temps-cli/src/api/core/queryKeySerializer.gen.ts @@ -14,12 +14,8 @@ export type JsonValue = /** * Replacer that converts non-JSON values (bigint, Date, etc.) to safe substitutes. */ -export const queryKeyJsonReplacer = (_key: string, value: unknown) => { - if ( - value === undefined || - typeof value === 'function' || - typeof value === 'symbol' - ) { +export const queryKeyJsonReplacer = (_key: string, value: unknown): unknown | undefined => { + if (value === undefined || typeof value === 'function' || typeof value === 'symbol') { return undefined; } if (typeof value === 'bigint') { @@ -61,9 +57,7 @@ const isPlainObject = (value: unknown): value is Record => { * Turns URLSearchParams into a sorted JSON object for deterministic keys. */ const serializeSearchParams = (params: URLSearchParams): JsonValue => { - const entries = Array.from(params.entries()).sort(([a], [b]) => - a.localeCompare(b), - ); + const entries = Array.from(params.entries()).sort(([a], [b]) => a.localeCompare(b)); const result: Record = {}; for (const [key, value] of entries) { @@ -86,26 +80,16 @@ const serializeSearchParams = (params: URLSearchParams): JsonValue => { /** * Normalizes any accepted value into a JSON-friendly shape for query keys. */ -export const serializeQueryKeyValue = ( - value: unknown, -): JsonValue | undefined => { +export const serializeQueryKeyValue = (value: unknown): JsonValue | undefined => { if (value === null) { return null; } - if ( - typeof value === 'string' || - typeof value === 'number' || - typeof value === 'boolean' - ) { + if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') { return value; } - if ( - value === undefined || - typeof value === 'function' || - typeof value === 'symbol' - ) { + if (value === undefined || typeof value === 'function' || typeof value === 'symbol') { return undefined; } @@ -121,10 +105,7 @@ export const serializeQueryKeyValue = ( return stringifyToJsonValue(value); } - if ( - typeof URLSearchParams !== 'undefined' && - value instanceof URLSearchParams - ) { + if (typeof URLSearchParams !== 'undefined' && value instanceof URLSearchParams) { return serializeSearchParams(value); } diff --git a/apps/temps-cli/src/api/core/serverSentEvents.gen.ts b/apps/temps-cli/src/api/core/serverSentEvents.gen.ts index f8fd78e28..ddf3c4d13 100644 --- a/apps/temps-cli/src/api/core/serverSentEvents.gen.ts +++ b/apps/temps-cli/src/api/core/serverSentEvents.gen.ts @@ -2,10 +2,7 @@ import type { Config } from './types.gen'; -export type ServerSentEventsOptions = Omit< - RequestInit, - 'method' -> & +export type ServerSentEventsOptions = Omit & Pick & { /** * Fetch API implementation. You can use this option to provide a custom @@ -74,11 +71,7 @@ export interface StreamEvent { retry?: number; } -export type ServerSentEventsResult< - TData = unknown, - TReturn = void, - TNext = unknown, -> = { +export type ServerSentEventsResult = { stream: AsyncGenerator< TData extends Record ? TData[keyof TData] : TData, TReturn, @@ -86,7 +79,7 @@ export type ServerSentEventsResult< >; }; -export const createSseClient = ({ +export function createSseClient({ onRequest, onSseError, onSseEvent, @@ -98,12 +91,10 @@ export const createSseClient = ({ sseSleepFn, url, ...options -}: ServerSentEventsOptions): ServerSentEventsResult => { +}: ServerSentEventsOptions): ServerSentEventsResult { let lastEventId: string | undefined; - const sleep = - sseSleepFn ?? - ((ms: number) => new Promise((resolve) => setTimeout(resolve, ms))); + const sleep = sseSleepFn ?? ((ms: number) => new Promise((resolve) => setTimeout(resolve, ms))); const createStream = async function* () { let retryDelay: number = sseDefaultRetryDelay ?? 3000; @@ -141,16 +132,11 @@ export const createSseClient = ({ const _fetch = options.fetch ?? globalThis.fetch; const response = await _fetch(request); - if (!response.ok) - throw new Error( - `SSE failed: ${response.status} ${response.statusText}`, - ); + if (!response.ok) throw new Error(`SSE failed: ${response.status} ${response.statusText}`); if (!response.body) throw new Error('No body in SSE response'); - const reader = response.body - .pipeThrough(new TextDecoderStream()) - .getReader(); + const reader = response.body.pipeThrough(new TextDecoderStream()).getReader(); let buffer = ''; @@ -169,6 +155,7 @@ export const createSseClient = ({ const { done, value } = await reader.read(); if (done) break; buffer += value; + buffer = buffer.replace(/\r\n?/g, '\n'); // normalize line endings const chunks = buffer.split('\n\n'); buffer = chunks.pop() ?? ''; @@ -186,10 +173,7 @@ export const createSseClient = ({ } else if (line.startsWith('id:')) { lastEventId = line.replace(/^id:\s*/, ''); } else if (line.startsWith('retry:')) { - const parsed = Number.parseInt( - line.replace(/^retry:\s*/, ''), - 10, - ); + const parsed = Number.parseInt(line.replace(/^retry:\s*/, ''), 10); if (!Number.isNaN(parsed)) { retryDelay = parsed; } @@ -241,18 +225,12 @@ export const createSseClient = ({ // connection failed or aborted; retry after delay onSseError?.(error); - if ( - sseMaxRetryAttempts !== undefined && - attempt >= sseMaxRetryAttempts - ) { + if (sseMaxRetryAttempts !== undefined && attempt >= sseMaxRetryAttempts) { break; // stop after firing error } // exponential backoff: double retry each attempt, cap at 30s - const backoff = Math.min( - retryDelay * 2 ** (attempt - 1), - sseMaxRetryDelay ?? 30000, - ); + const backoff = Math.min(retryDelay * 2 ** (attempt - 1), sseMaxRetryDelay ?? 30000); await sleep(backoff); } } @@ -261,4 +239,4 @@ export const createSseClient = ({ const stream = createStream(); return { stream }; -}; +} diff --git a/apps/temps-cli/src/api/core/types.gen.ts b/apps/temps-cli/src/api/core/types.gen.ts index 643c070c9..c657c8599 100644 --- a/apps/temps-cli/src/api/core/types.gen.ts +++ b/apps/temps-cli/src/api/core/types.gen.ts @@ -1,11 +1,7 @@ // This file is auto-generated by @hey-api/openapi-ts import type { Auth, AuthToken } from './auth.gen'; -import type { - BodySerializer, - QuerySerializer, - QuerySerializerOptions, -} from './bodySerializer.gen'; +import type { BodySerializer, QuerySerializer, QuerySerializerOptions } from './bodySerializer.gen'; export type HttpMethod = | 'connect' @@ -34,9 +30,7 @@ export type Client< setConfig: (config: Config) => Config; } & { [K in HttpMethod]: MethodFn; -} & ([SseFn] extends [never] - ? { sse?: never } - : { sse: { [K in HttpMethod]: SseFn } }); +} & ([SseFn] extends [never] ? { sse?: never } : { sse: { [K in HttpMethod]: SseFn } }); export interface Config { /** @@ -59,13 +53,7 @@ export interface Config { | RequestInit['headers'] | Record< string, - | string - | number - | boolean - | (string | number | boolean)[] - | null - | undefined - | unknown + string | number | boolean | (string | number | boolean)[] | null | undefined | unknown >; /** * The request method. @@ -92,7 +80,7 @@ export interface Config { requestValidator?: (data: unknown) => Promise; /** * A function transforming response data before it's returned. This is useful - * for post-processing data, e.g. converting ISO strings into Date objects. + * for post-processing data, e.g., converting ISO strings into Date objects. */ responseTransformer?: (data: unknown) => Promise; /** @@ -103,6 +91,12 @@ export interface Config { responseValidator?: (data: unknown) => Promise; } +/** + * Arbitrary metadata passed through the `meta` request option. + */ +// eslint-disable-next-line @typescript-eslint/no-empty-object-type +export interface ClientMeta {} + type IsExactlyNeverOrNeverUndefined = [T] extends [never] ? true : [T] extends [never | undefined] @@ -112,7 +106,5 @@ type IsExactlyNeverOrNeverUndefined = [T] extends [never] : false; export type OmitNever> = { - [K in keyof T as IsExactlyNeverOrNeverUndefined extends true - ? never - : K]: T[K]; + [K in keyof T as IsExactlyNeverOrNeverUndefined extends true ? never : K]: T[K]; }; diff --git a/apps/temps-cli/src/api/core/utils.gen.ts b/apps/temps-cli/src/api/core/utils.gen.ts index 0b5389d08..af56e0711 100644 --- a/apps/temps-cli/src/api/core/utils.gen.ts +++ b/apps/temps-cli/src/api/core/utils.gen.ts @@ -13,9 +13,9 @@ export interface PathSerializer { url: string; } -export const PATH_PARAM_RE = /\{[^{}]+\}/g; +export const PATH_PARAM_RE: RegExp = /\{[^{}]+\}/g; -export const defaultPathSerializer = ({ path, url: _url }: PathSerializer) => { +export const defaultPathSerializer = ({ path, url: _url }: PathSerializer): string => { let url = _url; const matches = _url.match(PATH_PARAM_RE); if (matches) { @@ -44,10 +44,7 @@ export const defaultPathSerializer = ({ path, url: _url }: PathSerializer) => { } if (Array.isArray(value)) { - url = url.replace( - match, - serializeArrayParam({ explode, name, style, value }), - ); + url = url.replace(match, serializeArrayParam({ explode, name, style, value })); continue; } @@ -97,7 +94,7 @@ export const getUrl = ({ query?: Record; querySerializer: QuerySerializer; url: string; -}) => { +}): string => { const pathUrl = _url.startsWith('/') ? _url : `/${_url}`; let url = (baseUrl ?? '') + pathUrl; if (path) { @@ -117,7 +114,7 @@ export function getValidRequestBody(options: { body?: unknown; bodySerializer?: BodySerializer | null; serializedBody?: unknown; -}) { +}): unknown { const hasBody = options.body !== undefined; const isSerializedBody = hasBody && options.bodySerializer; @@ -129,7 +126,7 @@ export function getValidRequestBody(options: { return hasSerializedBody ? options.serializedBody : null; } - // not all clients implement a serializedBody property (i.e. client-axios) + // not all clients implement a serializedBody property (i.e., client-axios) return options.body !== '' ? options.body : null; } diff --git a/apps/temps-cli/src/api/index.ts b/apps/temps-cli/src/api/index.ts index c352c1047..e02961b64 100644 --- a/apps/temps-cli/src/api/index.ts +++ b/apps/temps-cli/src/api/index.ts @@ -1,4 +1,4 @@ // This file is auto-generated by @hey-api/openapi-ts -export type * from './types.gen'; -export * from './sdk.gen'; +export { acknowledgeAlarm, activateAiProvider, activateApiKey, activateConnection, activateProvider, addClusterMember, addContext, addEnvironmentDomain, addEvents, addManagedDomain, addSessionReplayEvents, addTeamMember, adminDrainNode, adminDrainStatus, adminGetNode, adminListNodeContainers, adminListNodes, adminRemoveNode, adminUndrainNode, applyHostnameMode, archiveConversation, archiveFlag, assignRole, attachScheduleServices, blobCopy, blobDelete, blobDisable, blobDownload, blobEnable, blobHead, blobList, blobPut, blobStatus, blobUpdate, cancel, cancelBackup, cancelDeployment, cancelDomainOrder, cancelPgUpgrade, cancelRun, cancelScheduleRun, changePasswordSelf, changeProjectSource, chatCompletions, checkAnalyticsHasEvents, checkCommitExists, checkDomainStatus, checkExplorerSupport, checkIpBlocked, checkProviderDeletionSafety, chunkUploadOptions, cleanupExpiredBackups, clearPreviewPassword, cliDeviceApprove, cliDeviceDeny, cliDeviceLookup, cliDevicePoll, cliDeviceStart, cliLogout, cmd, cmdKill, cmdLogs, confirmPendingAction, containerMetricsGetHistory, createAgent, createAlert, createAlertRule, createApiKey, createBackupSchedule, createBitbucketProvider, createCloudflareProvider, createConversation, createCustomDomain, createDashboard, createDeploymentToken, createDnsProvider, createDomain, createDsn, createEmailDomain, createEmailProvider, createEnvironment, createEnvironmentVariable, createFlag, createFunnel, createGenericProvider, createGiteaPatProvider, createGithubPatProvider, createGitlabOauthProvider, createGitlabPatProvider, createGitProvider, createGlobalMcp, createGlobalSkill, createIncident, createIpAccessControl, createMcp, createMonitor, createNotificationEmailProvider, createNotificationProvider, createOidcProvider, createOidcRoleMapping, createOrRecreateOrder, createPlan, createPr, createProject, createProjectFromTemplate, createProjectRelease, createProjectSecret, createProviderKey, createRelease, createRoute, createS3Source, createSandbox, createService, createSkill, createSlackProvider, createTeam, createUser, createWebhook, createWebhookProvider, deactivateApiKey, deactivateConnection, deactivateProvider, deleteAgent, deleteAlert, deleteAlertRule, deleteApiKey, deleteBackup, deleteBackupSchedule, deleteConnection, deleteCustomDomain, deleteDashboard, deleteDeploymentToken, deleteDnsProvider, deleteDomain, deleteEmailDomain, deleteEmailProvider, deleteEnvironment, deleteEnvironmentDomain, deleteEnvironmentVariable, deleteExternalImage, deleteFunnel, deleteGitProvider, deleteGlobalMcp, deleteGlobalSkill, deleteIpAccessControl, deleteMcp, deleteMonitor, deleteNotificationProvider, deleteOidcProvider, deleteOidcRoleMapping, deletePreferences, deleteProject, deleteProjectSecret, deleteProviderKey, deleteProviderSafely, deleteReleaseSourceFiles, deleteReleaseSourceMaps, deleteRoute, deleteS3Source, deleteScan, deleteSecret, deleteService, deleteSessionReplay, deleteSkill, deleteSourceMap, deleteStaticBundle, deleteTeam, deleteUser, deleteWebhook, deployFromImage, deployFromImageUpload, deployFromStatic, deployFromUploadedSource, deploymentMetricsGetLatest, deploymentMetricsGetRange, deploymentMetricsToggle, destroySandbox, detachScheduleService, detectPublicPresets, disableBackupSchedule, disableMfa, disconnectCloud, discoverWorkloads, domain, downloadGlobalSkillArchive, downloadObject, downloadSkillArchive, emailStatus, embeddings, enableBackupSchedule, enrichVisitor, enrollCloud, exec, execDetached, executeDeploymentOperation, executeImport, extendTimeout, externalServiceEnablePgStatStatements, externalServiceMetricsByDatabase, externalServiceMetricsCreateAlertRule, externalServiceMetricsDeleteAlertRule, externalServiceMetricsGetAlertRules, externalServiceMetricsGetLatest, externalServiceMetricsGetRange, externalServiceMetricsStatus, externalServiceMetricsToggle, externalServiceMetricsUpdateAlertRule, externalServiceResetPgStatStatements, finalizeOrder, finalizeProjectRelease, findConversation, generateJoinToken, generatePresetDockerfile, getAccessInfo, getActiveVisitors, getActivityGraph, getAdminGate, getAgent, getAggregatedBuckets, getAiAgentBreakdown, getAiAgentPages, getAiAgentTimeline, getAiDataAccess, getAiPageBreakdown, getAiStatusBreakdown, getAlert, getAlertRule, getAllRepositoriesByName, getAnalyticsActiveVisitors, getAnalyticsEventsCount, getAnalyticsSessionEvents, getAnalyticsVisitorSessions, getApiKey, getApiKeyPermissions, getAuditLog, getBackup, getBackupSchedule, getBranchesByRepositoryId, getBucketedIncidents, getBucketedStatus, getChallengeToken, getChatReadiness, getCliStatus, getCloudCapability, getCloudStatus, getClusterHealth, getClusterMember, getCmd, getContainerDetail, getContainerEnvironmentVariable, getContainerLogs, getContainerLogsById, getContainerMetrics, getConversation, getConversationDetail, getConversations, getCronById, getCronExecutions, getCrossProjectTraceSiblings, getCurrentMonitorStatus, getCurrentUser, getCustomDomain, getDashboard, getDashboardProjectsAnalytics, getDelivery, getDeployment, getDeploymentContainerLogContent, getDeploymentJobLogs, getDeploymentJobs, getDeploymentOperations, getDeploymentOperationStatus, getDeploymentToken, getDiskStatus, getDnsChanges, getDnsProvider, getDomain, getDomainByHost, getDomainById, getDomainByName, getDomainDnsRecords, getDomainOrder, getEmail, getEmailEvents, getEmailLinks, getEmailProvider, getEmailStats, getEmailTracking, getEmailTrackingStatus, getEntityInfo, getEnvironment, getEnvironmentCrons, getEnvironmentDomains, getEnvironments, getEnvironmentVariables, getEnvironmentVariableValue, getErrorDashboardStats, getErrorEvent, getErrorGroup, getErrorStats, getErrorTimeSeries, getEventDetail, getEventEntries, getEventsCount, getEventsTimeline, getEventTypeBreakdown, getEventVisitors, getExternalImage, getFile, getFlag, getFlagSnapshot, getFunnelMetrics, getGenaiTrace, getGeneralStats, getGitProvider, getGlobalEvents, getGlobalEventStats, getGlobalMcp, getGlobalSandboxStatus, getGlobalSkill, getGroupedPageMetrics, getHealth, getHourlyVisits, getHttpChallengeDebug, getImportStatus, getIncident, getIncidentUpdates, getIpAccessControl, getIpGeolocation, getJoinTokenStatus, getLastDeployment, getLatestScan, getLatestScansPerEnvironment, getLiveVisitorsList, getLogContext, getMcp, getMetricsOverTime, getMonitor, getNotificationProvider, getOnDemandCertStatus, getOrCreateDsn, getPageFlow, getPageHourlySessions, getPagePathDetail, getPagePaths, getPagePathsSparklines, getPagePathVisitors, getPendingAction, getPerformanceMetrics, getPgUpgrade, getPgUpgradeLogs, getPipelineStats, getPlatformInfo, getPostgresWalHealth, getPreferences, getPreviewGatewayLogs, getPreviewGatewaySettings, getPreviewGatewayStatus, getPricing, getPrivateIp, getProject, getProjectAlarmsSummary, getProjectBySlug, getProjectDeployments, getProjects, getProjectServiceEnvironmentVariables, getProjectSessionReplays, getProjectsHealth, getProjectsMonitorHealth, getProjectStatistics, getProjectTemplate, getPropertyBreakdown, getPropertyTimeline, getProviderConnections, getProviderMetadata, getProvidersMetadata, getProxyLogById, getProxyLogByRequestId, getProxyLogs, getPublicBranches, getPublicIp, getPublicRepository, getQueryContainerInfo, getQuota, getRecentActivity, getRemoteExternalImage, getRepositoryBranches, getRepositoryById, getRepositoryByName, getRepositoryPresetByName, getRepositoryPresetLive, getRepositoryTags, getResolvedEnvironmentVariables, getResolvedEnvironmentVariableValue, getRestoreCapabilities, getRestoreRun, getRoute, getRun, getRunWithLogs, getS3Credentials, getS3Source, getSandbox, getSandboxStatus, getScan, getScanByDeployment, getScanVulnerabilities, getService, getServiceBySlug, getServiceEnvironmentVariable, getServiceEnvironmentVariables, getServiceHealthStatus, getServicePreviewEnvironmentVariableNames, getServicePreviewEnvironmentVariablesMasked, getServiceRuntime, getServiceStats, getServiceTypeParameters, getServiceTypes, getSessionDetails, getSessionEvents, getSessionLogs, getSessionReplay, getSessionReplayEvents, getSettings, getSkill, getSlowQueries, getStaticBundle, getStatusOverview, getTagsByRepositoryId, getTeam, getTimeBucketStats, getTodayStats, getTrace, getUnifiedTrace, getUniqueCounts, getUniqueEvents, getUpdateStatus, getUptimeHistory, getUsageByProvider, getUsageRecent, getUsageSummary, getUsageTimeseries, getUsageTopModels, getVisitorByGuid, getVisitorById, getVisitorDetails, getVisitorFacets, getVisitorInfo, getVisitorJourney, getVisitors, getVisitorSessions, getVisitorStats, getWebhook, grantProjectAccess, handleGitProviderOauthCallback, hasAnalyticsEvents, hasErrorGroups, hasPerformanceMetrics, importExternalService, ingestLogs, ingestLogsByPath, ingestMetrics, ingestMetricsByPath, ingestSentryEnvelope, ingestSentryEvent, ingestTraces, ingestTracesByPath, initSessionReplay, inspectDropArchive, jobLogs, jobStatus, killJob, kvDel, kvDisable, kvEnable, kvExpire, kvGet, kvIncr, kvKeys, kvSet, kvStatus, kvTtl, kvUpdate, latestRunForSource, linkCustomDomainToCertificate, linkServiceToProject, listAgentRuns, listAgents, listAiProviders, listAlertRules, listAlerts, listAllConversations, listAllRuns, listApiKeys, listAuditLogs, listAvailableContainers, listBackupAlerts, listBackupChildren, listBackupSchedules, listBackupsForSchedule, listCommitsByRepositoryId, listConnections, listContainers, listContainersAtPath, listConversations, listCustomDomainsForProject, listDashboards, listDeliveries, listDeploymentContainerLogs, listDeploymentTokens, listDnsProviders, listDomains, listDsns, listEmailDomains, listEmailProviders, listEmails, listEnrollmentTokens, listEntities, listErrorEvents, listErrorGroups, listEvents, listEventTypes, listExternalImages, listExternalPlugins, listExternalServiceBackups, listFlags, listFunnels, listGitProviders, listGlobalMcps, listGlobalSkills, listIncidents, listInsights, listIpAccessControl, listJobs, listKnownAiAgents, listManagedDomains, listMcps, listMetricLabelKeys, listMetricLabelValues, listMetricNames, listModels, listMonitors, listNotificationProviders, listOidcProviders, listOidcProviderUsers, listOidcRoleMappings, listOnDemandCerts, listOrders, listPeers, listPendingActions, listPgUpgrades, listPresets, listProjectAccess, listProjectAlarms, listProjectScans, listProjectSecrets, listProjectServices, listProjectTemplates, listProjectTemplateTags, listProviderKeys, listProviderZones, listPublicProviders, listReleaseFiles, listReleases, listRemoteExternalImages, listRepositoriesByConnection, listRepositoriesByProvider, listRestoreRunsForService, listRootContainers, listRoutes, listS3Sources, listSandboxes, listScheduleRunJobs, listScheduleRuns, listScheduleServices, listSecrets, listServiceHealthStatuses, listServiceProjects, listServices, listServiceSchedules, listSkills, listSourceBackups, listSourceFiles, listSourceMaps, listSources, listStaticBundles, listSyncedRepositories, listTeamMembers, listTeamProjects, listTeams, listUsers, listWebhooks, login, logout, lookupDnsARecords, mintEnrollmentToken, mkdir, nodeHeartbeat, nodeMetricsGetRange, observabilityFullEvent, observabilityListEvents, oidcCallback, type Options, patchAdminGate, patchPreviewGatewaySettings, pauseDeployment, pauseSandbox, planRestore, postDnsAck, previewAlert, previewFunnelMetrics, previewHostnameMode, promoteClusterMember, promoteDeployment, provisionDomain, purgeProjectLogs, pushExternalImage, queryData, queryGenaiTraces, queryLogs, queryMetrics, queryTraces, queryTraceSummaries, readEntityRows, readFile, reAnalyze, rebuildSandboxImage, recordConsoleEvent, recordEventMetrics, recordFlagExposure, recordSpeedMetrics, refreshRouteTable, regenerateDsn, registerExternalImage, registerNode, reinstallGitlabWebhook, rejectPendingAction, reloadPlugins, removeClusterMember, removeManagedDomain, removeRole, removeTeamMember, renameConversation, renewDomain, requestPasswordReset, resetPassword, resizeSandbox, resolveAlarm, restartContainer, restartPreviewGateway, restartSandbox, restoreFlag, restoreUser, resumeDeployment, resumeSandbox, retryCluster, retryDelivery, retryPgUpgrade, retryRun, revealGlobalMcpConfig, revealMcpConfig, revealNotificationProviderConfig, revealServiceParameter, revenueCreateIntegration, revenueDeleteIntegration, revenueGlobalEvents, revenueImportInvoicesCsv, revenueImportSubscriptionsCsv, revenueListIntegrations, revenueListProviders, revenueMetricsCustomers, revenueMetricsGlobalMrr, revenueMetricsGlobalSummary, revenueMetricsMrr, revenueMetricsSummary, revenueRecentEvents, revenueRotateToken, revenueUpdateConfig, revenueUpdateSecret, revokeDsn, revokeEnrollmentToken, revokeJoinToken, revokeProjectAccess, rollbackPgUpgrade, rollbackToDeployment, rootfsGc, rootfsReport, rotateApiKey, rotateDeploymentToken, runBackupForSource, runConnectionHealthCheck, runExternalServiceBackup, runScheduleNow, sandboxCreatePreviewLink, saveAgentToken, saveAiProviderCredential, searchLogs, sendEmail, sendMessage, setAiDataAccess, setDefaultS3Source, setFlagEnvironment, setPreviewPassword, setupDns, setupDnsChallenge, setupEmailTracking, setupMfa, sleepEnvironment, smokeTestAgent, sourceSandbox, startAnalysis, startContainer, startFix, startGitProviderOauth, startOidcLoginBySlug, startPgUpgrade, startRestore, startService, statPath, stopContainer, stopSandbox, stopService, streamContainerMetrics, streamEvents, streamRunEvents, syncRepositories, tailDeploymentJobLogs, tailLogs, teardownDeployment, teardownEnvironment, testNotificationProvider, testOidcProvider, testProvider, testProviderConnection, testProviderKeyById, testProviderKeyInline, testS3ConnectionPreview, testS3SourceConnection, trackClick, trackOpen, triggerAgent, triggerProjectPipeline, triggerScan, triggerServiceHealthCheck, triggerWeeklyDigest, unlinkServiceFromProject, updateAgent, updateAiProvider, updateAlert, updateAlertRule, updateApiKey, updateAutomaticDeploy, updateBackupSchedule, updateCloudflareProvider, updateConnectionToken, updateCustomDomain, updateDashboard, updateDeploymentToken, updateEmailProvider, updateEnvironmentSettings, updateEnvironmentSubdomain, updateEnvironmentVariable, updateErrorGroup, updateFlag, updateFunnel, updateGitProviderCredentials, updateGitSettings, updateGlobalMcp, updateGlobalSkill, updateIncidentStatus, updateIpAccessControl, updateManagedDomain, updateMcp, updateNotificationEmailProvider, updateNotificationProvider, updateOidcProvider, updatePreferences, updateProject, updateProjectDeploymentConfig, updateProjectSecret, updateProjectSettings, updateProvider, updateProviderKey, updateRoute, updateS3Source, updateSelf, updateService, updateServiceResources, updateSessionDuration, updateSettings, updateSkill, updateSlackProvider, updateSpeedMetrics, updateTeam, updateTeamMemberRole, updateUser, updateWebhook, updateWebhookProvider, upgradePreviewGateway, upgradeService, uploadGlobalSkill, uploadReleaseFile, uploadSkill, uploadSourceFile, uploadSourceMap, uploadStaticBundle, upsertSecret, validateConnection, validateEmail, verifyAndEnableMfa, verifyDomain, verifyEmail, verifyManagedDomain, verifyMfaChallenge, verifyStepUp, wakeEnvironment, webhookTrigger, workflowDryRun, writeFile, writeFiles } from './sdk.gen'; +export type { AcknowledgeAlarmData, AcknowledgeAlarmErrors, AcknowledgeAlarmResponses, AcmeOrderResponse, ActivateAiProviderData, ActivateAiProviderErrors, ActivateAiProviderResponse, ActivateAiProviderResponses, ActivateApiKeyData, ActivateApiKeyErrors, ActivateApiKeyResponse, ActivateApiKeyResponses, ActivateConnectionData, ActivateConnectionErrors, ActivateConnectionResponses, ActivateProviderData, ActivateProviderErrors, ActivateProviderResponse, ActivateProviderResponses, ActiveVisitor, ActiveVisitorsQuery, ActiveVisitorsResponse, ActivityDay, ActivityEvent, ActivityGraphQuery, ActivityGraphResponse, AddClusterMemberData, AddClusterMemberErrors, AddClusterMemberRequest, AddClusterMemberResponse, AddClusterMemberResponses, AddContextData, AddContextErrors, AddContextRequest, AddContextResponses, AddEnvironmentDomainData, AddEnvironmentDomainErrors, AddEnvironmentDomainRequest, AddEnvironmentDomainResponse, AddEnvironmentDomainResponses, AddEventsData, AddEventsError, AddEventsErrors, AddEventsRequest, AddEventsResponse, AddEventsResponse2, AddEventsResponses, AddManagedDomainApiRequest, AddManagedDomainData, AddManagedDomainErrors, AddManagedDomainResponse, AddManagedDomainResponses, AddSessionReplayEventsData, AddSessionReplayEventsError, AddSessionReplayEventsErrors, AddSessionReplayEventsResponse, AddSessionReplayEventsResponses, AddTeamMemberData, AddTeamMemberErrors, AddTeamMemberResponse, AddTeamMemberResponses, AdminDrainNodeData, AdminDrainNodeErrors, AdminDrainNodeResponse, AdminDrainNodeResponses, AdminDrainStatusData, AdminDrainStatusErrors, AdminDrainStatusResponse, AdminDrainStatusResponses, AdminGateResponse, AdminGateSource, AdminGetNodeData, AdminGetNodeErrors, AdminGetNodeResponse, AdminGetNodeResponses, AdminListNodeContainersData, AdminListNodeContainersErrors, AdminListNodeContainersResponse, AdminListNodeContainersResponses, AdminListNodesData, AdminListNodesErrors, AdminListNodesResponse, AdminListNodesResponses, AdminRemoveNodeData, AdminRemoveNodeErrors, AdminRemoveNodeResponse, AdminRemoveNodeResponses, AdminUndrainNodeData, AdminUndrainNodeErrors, AdminUndrainNodeResponse, AdminUndrainNodeResponses, AgentConfigResponse, AgentRunLogResponse, AgentRunResponse, AgentRunWithLogsResponse, AgentSandboxSettings, AgentSandboxSettingsMasked, AggregatedBucketItem, AggregatedBucketsQuery, AggregatedBucketsResponse, AggregationLevel, AggregationTemporality, AiAgentBreakdownResponse, AiAgentBreakdownRow, AiAgentDescriptor, AiAgentPageRow, AiAgentPagesResponse, AiAgentTimelineResponse, AiAgentTimelineRow, AiChatLimitsSettings, AiConfigSettings, AiDataAccessResponse, AiPageBreakdownResponse, AiPageBreakdownRow, AiStatusBreakdownResponse, AiStatusBreakdownRow, AlarmListResponse, AlarmResponse, AlarmSummaryResponse, AlertRuleResponse, AllocEntry, AnalyticsSessionEventsResponse, AnnotatedSpan, AnomalyAlgorithm, AnomalyParams, AnomalyPreviewPointResponse, AnomalyPreviewRequest, AnomalyPreviewResponse, ApiKeyListResponse, ApiKeyResponse, ApplyHostnameModeData, ApplyHostnameModeErrors, ApplyHostnameModeRequest, ApplyHostnameModeResponse, ApplyHostnameModeResponses, AppSettings, AppSettingsResponse, ArchiveConversationData, ArchiveConversationErrors, ArchiveConversationResponse, ArchiveConversationResponses, ArchiveFlagData, ArchiveFlagErrors, ArchiveFlagResponse, ArchiveFlagResponse2, ArchiveFlagResponses, ArchiveMode, AssignRoleData, AssignRoleErrors, AssignRoleRequest, AssignRoleResponses, AttachScheduleServicesData, AttachScheduleServicesError, AttachScheduleServicesErrors, AttachScheduleServicesRequest, AttachScheduleServicesResponse, AttachScheduleServicesResponse2, AttachScheduleServicesResponses, AuditLogIpInfo, AuditLogResponse, AuditLogUserInfo, AuthFlavorDto, AuthResponse, AuthStatusResponse, AuthTokenResponse, AutofixerRunResponse, AutofixerRunWithLogsResponse, AutofixRunConfig, AutoWatchParams, AvailableContainerInfo, AvailablePermissions, BackupAlertListResponse, BackupAlertResponse, BackupResponse, BackupScheduleResponse, BitbucketAuthInput, BlobCopyData, BlobCopyError, BlobCopyErrors, BlobCopyResponse, BlobCopyResponses, BlobDeleteData, BlobDeleteError, BlobDeleteErrors, BlobDeleteResponse, BlobDeleteResponses, BlobDisableData, BlobDisableErrors, BlobDisableResponse, BlobDisableResponses, BlobDownloadData, BlobDownloadError, BlobDownloadErrors, BlobDownloadResponses, BlobEnableData, BlobEnableErrors, BlobEnableResponse, BlobEnableResponses, BlobHeadData, BlobHeadError, BlobHeadErrors, BlobHeadResponses, BlobListData, BlobListError, BlobListErrors, BlobListResponse, BlobListResponses, BlobPutData, BlobPutError, BlobPutErrors, BlobPutResponse, BlobPutResponses, BlobResponse, BlobStatusData, BlobStatusErrors, BlobStatusResponse, BlobStatusResponse2, BlobStatusResponses, BlobUpdateData, BlobUpdateErrors, BlobUpdateResponse, BlobUpdateResponses, BranchInfo, BranchListResponse, BrowserCount, BrowsersQuery, BuildConfiguration, BuildLimitsSettings, CancelBackupData, CancelBackupError, CancelBackupErrors, CancelBackupResponse, CancelBackupResponse2, CancelBackupResponses, CancelData, CancelDeploymentData, CancelDeploymentErrors, CancelDeploymentResponse, CancelDeploymentResponses, CancelDomainOrderData, CancelDomainOrderErrors, CancelDomainOrderResponse, CancelDomainOrderResponses, CancelErrors, CancelPgUpgradeData, CancelPgUpgradeErrors, CancelPgUpgradeResponse, CancelPgUpgradeResponses, CancelResponses, CancelRunData, CancelRunErrors, CancelRunResponse, CancelRunResponses, CancelScheduleRunData, CancelScheduleRunError, CancelScheduleRunErrors, CancelScheduleRunResponse, CancelScheduleRunResponses, CertStatusResponse, ChallengeConfig, ChallengeError, ChallengeValidationStatus, ChangePasswordRequest, ChangePasswordSelfData, ChangePasswordSelfErrors, ChangePasswordSelfResponse, ChangePasswordSelfResponses, ChangeProjectSourceData, ChangeProjectSourceErrors, ChangeProjectSourceRequest, ChangeProjectSourceResponse, ChangeProjectSourceResponses, ChatCompletionChoice, ChatCompletionRequest, ChatCompletionResponse, ChatCompletionsData, ChatCompletionsError, ChatCompletionsErrors, ChatCompletionsResponse, ChatCompletionsResponses, ChatMessage, ChatReadinessResponse, CheckAnalyticsHasEventsData, CheckAnalyticsHasEventsErrors, CheckAnalyticsHasEventsResponse, CheckAnalyticsHasEventsResponses, CheckCommitExistsData, CheckCommitExistsErrors, CheckCommitExistsResponse, CheckCommitExistsResponses, CheckDomainStatusData, CheckDomainStatusErrors, CheckDomainStatusResponse, CheckDomainStatusResponses, CheckExplorerSupportData, CheckExplorerSupportErrors, CheckExplorerSupportResponse, CheckExplorerSupportResponses, CheckIpBlockedData, CheckIpBlockedError, CheckIpBlockedErrors, CheckIpBlockedResponses, CheckProviderDeletionSafetyData, CheckProviderDeletionSafetyErrors, CheckProviderDeletionSafetyResponse, CheckProviderDeletionSafetyResponses, ChildBackupEntryResponse, ChildBackupListResponse, ChunkUploadOptionsData, ChunkUploadOptionsResponse, ChunkUploadOptionsResponses, CleanupExpiredBackupsData, CleanupExpiredBackupsError, CleanupExpiredBackupsErrors, CleanupExpiredBackupsRequest, CleanupExpiredBackupsResponse, CleanupExpiredBackupsResponses, ClearPreviewPasswordData, ClearPreviewPasswordErrors, ClearPreviewPasswordResponse, ClearPreviewPasswordResponses, CliDeviceApproveData, CliDeviceApproveErrors, CliDeviceApproveRequest, CliDeviceApproveResponse, CliDeviceApproveResponse2, CliDeviceApproveResponses, CliDeviceDenyData, CliDeviceDenyErrors, CliDeviceDenyResponse, CliDeviceDenyResponses, CliDeviceLookupData, CliDeviceLookupErrors, CliDeviceLookupResponse, CliDeviceLookupResponse2, CliDeviceLookupResponses, CliDevicePollData, CliDevicePollErrors, CliDevicePollRequest, CliDevicePollResponse, CliDevicePollResponse2, CliDevicePollResponses, CliDeviceStartData, CliDeviceStartErrors, CliDeviceStartRequest, CliDeviceStartResponse, CliDeviceStartResponse2, CliDeviceStartResponses, ClientOptions, CliLoginRequest, CliLogoutData, CliLogoutErrors, CliLogoutResponse, CliLogoutResponses, CloudCapability, CloudflareConfig, CloudProvider, CloudSettings, CloudStatus, ClusterCapacity, ClusterDnsSettings, ClusterHealthReportResponse, ClusterMemberHealthResponse, ClusterMemberRequest, CmdBody, CmdData, CmdErrors, CmdInner, CmdKillBody, CmdKillData, CmdKillErrors, CmdKillResponse, CmdKillResponses, CmdLogsData, CmdLogsErrors, CmdLogsResponses, CmdResponse, CmdResponse2, CmdResponses, CommitExistsResponse, CommitInfo, CommitListResponse, Comparator, ComposePublicPort, ConfirmPendingActionData, ConfirmPendingActionErrors, ConfirmPendingActionResponse, ConfirmPendingActionResponses, ConnectionListQuery, ConnectionListResponse, ConnectionResponse, ConnectionTestResult, ConsoleEventPayload, ContainerActionResponse, ContainerDetailResponse, ContainerEnvironmentVariableValueResponse, ContainerInfoResponse, ContainerInventoryItem, ContainerListResponse, ContainerLogSettings, ContainerLogsQuery, ContainerMetricHistoryPoint, ContainerMetricsGetHistoryData, ContainerMetricsGetHistoryErrors, ContainerMetricsGetHistoryResponse, ContainerMetricsGetHistoryResponses, ContainerMetricsHistoryQuery, ContainerMetricsResponse, ContainerResponse, ContainerRuntimeInfo, ContainerStatsSample, ContentPart, ContextLine, ContextLogsRequest, ContextLogsResponse, ConversationDetailResponse, ConversationResponse, ConversationsQueryParams, ConversationSummary, CopyBlobRequest, CostAnalysis, CreateAgentData, CreateAgentErrors, CreateAgentResponse, CreateAgentResponses, CreateAlertData, CreateAlertError, CreateAlertErrors, CreateAlertResponse, CreateAlertResponses, CreateAlertRuleData, CreateAlertRuleErrors, CreateAlertRuleRequest, CreateAlertRuleResponse, CreateAlertRuleResponses, CreateApiKeyData, CreateApiKeyErrors, CreateApiKeyRequest, CreateApiKeyResponse, CreateApiKeyResponse2, CreateApiKeyResponses, CreateBackupScheduleData, CreateBackupScheduleError, CreateBackupScheduleErrors, CreateBackupScheduleRequest, CreateBackupScheduleResponse, CreateBackupScheduleResponses, CreateBitbucketProviderData, CreateBitbucketProviderErrors, CreateBitbucketProviderResponse, CreateBitbucketProviderResponses, CreateBitbucketRequest, CreateCloudflareProviderData, CreateCloudflareProviderErrors, CreateCloudflareProviderRequest, CreateCloudflareProviderResponse, CreateCloudflareProviderResponses, CreateConversationData, CreateConversationErrors, CreateConversationRequest, CreateConversationResponse, CreateConversationResponses, CreateCustomDomainData, CreateCustomDomainErrors, CreateCustomDomainResponse, CreateCustomDomainResponses, CreateDashboardData, CreateDashboardError, CreateDashboardErrors, CreateDashboardRequest, CreateDashboardResponse, CreateDashboardResponses, CreateDeploymentTokenData, CreateDeploymentTokenErrors, CreateDeploymentTokenRequest, CreateDeploymentTokenResponse, CreateDeploymentTokenResponse2, CreateDeploymentTokenResponses, CreateDnsProviderData, CreateDnsProviderErrors, CreateDnsProviderRequest, CreateDnsProviderResponse, CreateDnsProviderResponses, CreateDomainData, CreateDomainErrors, CreateDomainRequest, CreateDomainResponse, CreateDomainResponses, CreatedResource, CreateDsnData, CreateDsnErrors, CreateDsnRequest, CreateDsnResponse, CreateDsnResponses, CreateEmailDomainData, CreateEmailDomainErrors, CreateEmailDomainRequest, CreateEmailDomainResponse, CreateEmailDomainResponses, CreateEmailProviderData, CreateEmailProviderErrors, CreateEmailProviderRequest, CreateEmailProviderResponse, CreateEmailProviderResponses, CreateEnvironmentData, CreateEnvironmentErrors, CreateEnvironmentRequest, CreateEnvironmentResponse, CreateEnvironmentResponses, CreateEnvironmentVariableData, CreateEnvironmentVariableErrors, CreateEnvironmentVariableRequest, CreateEnvironmentVariableResponse, CreateEnvironmentVariableResponses, CreateExternalServiceRequest, CreateFlagData, CreateFlagErrors, CreateFlagRequest, CreateFlagResponse, CreateFlagResponses, CreateFunnelData, CreateFunnelErrors, CreateFunnelRequest, CreateFunnelResponse, CreateFunnelResponse2, CreateFunnelResponses, CreateFunnelStep, CreateGenericProviderData, CreateGenericProviderErrors, CreateGenericProviderResponse, CreateGenericProviderResponses, CreateGenericRequest, CreateGiteaPatProviderData, CreateGiteaPatProviderErrors, CreateGiteaPatProviderResponse, CreateGiteaPatProviderResponses, CreateGiteaPatRequest, CreateGithubPatProviderData, CreateGithubPatProviderErrors, CreateGithubPatProviderResponse, CreateGithubPatProviderResponses, CreateGitHubPatRequest, CreateGitlabOauthProviderData, CreateGitlabOauthProviderErrors, CreateGitlabOauthProviderResponse, CreateGitlabOauthProviderResponses, CreateGitLabOAuthRequest, CreateGitlabPatProviderData, CreateGitlabPatProviderErrors, CreateGitlabPatProviderResponse, CreateGitlabPatProviderResponses, CreateGitLabPatRequest, CreateGitProviderData, CreateGitProviderErrors, CreateGitProviderResponse, CreateGitProviderResponses, CreateGlobalMcpData, CreateGlobalMcpErrors, CreateGlobalMcpResponse, CreateGlobalMcpResponses, CreateGlobalSkillData, CreateGlobalSkillErrors, CreateGlobalSkillResponse, CreateGlobalSkillResponses, CreateIncidentData, CreateIncidentErrors, CreateIncidentRequest, CreateIncidentResponse, CreateIncidentResponses, CreateIntegrationBody, CreateIpAccessControlData, CreateIpAccessControlError, CreateIpAccessControlErrors, CreateIpAccessControlRequest, CreateIpAccessControlResponse, CreateIpAccessControlResponses, CreateMcpData, CreateMcpErrors, CreateMcpRequest, CreateMcpResponse, CreateMcpResponses, CreateMetricAlertRequest, CreateMonitorData, CreateMonitorErrors, CreateMonitorRequest, CreateMonitorResponse, CreateMonitorResponses, CreateNotificationEmailProviderData, CreateNotificationEmailProviderErrors, CreateNotificationEmailProviderRequest, CreateNotificationEmailProviderResponse, CreateNotificationEmailProviderResponses, CreateNotificationProviderData, CreateNotificationProviderErrors, CreateNotificationProviderResponse, CreateNotificationProviderResponses, CreateOidcProviderData, CreateOidcProviderErrors, CreateOidcProviderRequest, CreateOidcProviderResponse, CreateOidcProviderResponses, CreateOidcRoleMappingData, CreateOidcRoleMappingRequest, CreateOidcRoleMappingResponse, CreateOidcRoleMappingResponses, CreateOrRecreateOrderData, CreateOrRecreateOrderErrors, CreateOrRecreateOrderResponse, CreateOrRecreateOrderResponses, CreatePlanData, CreatePlanErrors, CreatePlanRequest, CreatePlanResponse, CreatePlanResponse2, CreatePlanResponses, CreatePrData, CreatePrErrors, CreateProjectAccessRequest, CreateProjectData, CreateProjectErrors, CreateProjectFromTemplateData, CreateProjectFromTemplateErrors, CreateProjectFromTemplateRequest, CreateProjectFromTemplateResponse, CreateProjectFromTemplateResponse2, CreateProjectFromTemplateResponses, CreateProjectReleaseData, CreateProjectReleaseErrors, CreateProjectReleaseResponse, CreateProjectReleaseResponses, CreateProjectRequest, CreateProjectResponse, CreateProjectResponses, CreateProjectSecretData, CreateProjectSecretErrors, CreateProjectSecretRequest, CreateProjectSecretResponse, CreateProjectSecretResponses, CreateProviderKeyData, CreateProviderKeyError, CreateProviderKeyErrors, CreateProviderKeyRequest, CreateProviderKeyResponse, CreateProviderKeyResponses, CreateProviderRequest, CreatePrResponse, CreatePrResponse2, CreatePrResponses, CreateReleaseData, CreateReleaseErrors, CreateReleaseResponse, CreateReleaseResponses, CreateRouteData, CreateRouteErrors, CreateRouteRequest, CreateRouteResponse, CreateRouteResponses, CreateS3SourceData, CreateS3SourceError, CreateS3SourceErrors, CreateS3SourceRequest, CreateS3SourceResponse, CreateS3SourceResponses, CreateSandboxBody, CreateSandboxData, CreateSandboxErrors, CreateSandboxResponse, CreateSandboxResponses, CreateServiceData, CreateServiceErrors, CreateServiceResponse, CreateServiceResponses, CreateSkillData, CreateSkillErrors, CreateSkillRequest, CreateSkillResponse, CreateSkillResponses, CreateSlackProviderData, CreateSlackProviderErrors, CreateSlackProviderRequest, CreateSlackProviderResponse, CreateSlackProviderResponses, CreateTeamData, CreateTeamErrors, CreateTeamMemberRequest, CreateTeamRequest, CreateTeamResponse, CreateTeamResponses, CreateUserData, CreateUserErrors, CreateUserRequest, CreateUserResponse, CreateUserResponses, CreateWebhookData, CreateWebhookErrors, CreateWebhookProviderData, CreateWebhookProviderErrors, CreateWebhookProviderRequest, CreateWebhookProviderResponse, CreateWebhookProviderResponses, CreateWebhookRequestBody, CreateWebhookResponse, CreateWebhookResponses, CronExecutionInfo, CronInfo, CrossProjectSiblingRef, CrossProjectTraceResponse, CurrentStatusResponse, CustomDomainRequest, CustomDomainResponse, CustomerMovementResponse, DashboardLayout, DashboardProjectsAnalyticsQuery, DashboardProjectsAnalyticsResponse, DashboardSection, DashboardTile, DatabaseMetricsResponse, DatabaseMetricsRow, DataImplication, DataImplicationSeverity, DeactivateApiKeyData, DeactivateApiKeyErrors, DeactivateApiKeyResponse, DeactivateApiKeyResponses, DeactivateConnectionData, DeactivateConnectionErrors, DeactivateConnectionResponses, DeactivateProviderData, DeactivateProviderErrors, DeactivateProviderResponses, DeleteAgentData, DeleteAgentErrors, DeleteAgentResponse, DeleteAgentResponses, DeleteAlertData, DeleteAlertError, DeleteAlertErrors, DeleteAlertResponse, DeleteAlertResponses, DeleteAlertRuleData, DeleteAlertRuleErrors, DeleteAlertRuleResponse, DeleteAlertRuleResponses, DeleteApiKeyData, DeleteApiKeyErrors, DeleteApiKeyResponse, DeleteApiKeyResponses, DeleteBackupData, DeleteBackupError, DeleteBackupErrors, DeleteBackupResponse, DeleteBackupResponses, DeleteBackupScheduleData, DeleteBackupScheduleError, DeleteBackupScheduleErrors, DeleteBackupScheduleResponse, DeleteBackupScheduleResponses, DeleteBlobRequest, DeleteBlobResponse, DeleteConnectionData, DeleteConnectionErrors, DeleteConnectionResponse, DeleteConnectionResponses, DeleteCustomDomainData, DeleteCustomDomainErrors, DeleteCustomDomainResponse, DeleteCustomDomainResponses, DeleteDashboardData, DeleteDashboardError, DeleteDashboardErrors, DeleteDashboardResponse, DeleteDashboardResponses, DeleteDeploymentTokenData, DeleteDeploymentTokenErrors, DeleteDeploymentTokenResponse, DeleteDeploymentTokenResponses, DeleteDnsProviderData, DeleteDnsProviderErrors, DeleteDnsProviderResponse, DeleteDnsProviderResponses, DeleteDomainData, DeleteDomainErrors, DeleteDomainResponse, DeleteDomainResponses, DeleteEmailDomainData, DeleteEmailDomainErrors, DeleteEmailDomainResponse, DeleteEmailDomainResponses, DeleteEmailProviderData, DeleteEmailProviderErrors, DeleteEmailProviderResponse, DeleteEmailProviderResponses, DeleteEnvironmentData, DeleteEnvironmentDomainData, DeleteEnvironmentDomainErrors, DeleteEnvironmentDomainResponse, DeleteEnvironmentDomainResponses, DeleteEnvironmentErrors, DeleteEnvironmentResponse, DeleteEnvironmentResponses, DeleteEnvironmentVariableData, DeleteEnvironmentVariableErrors, DeleteEnvironmentVariableResponse, DeleteEnvironmentVariableResponses, DeleteExternalImageData, DeleteExternalImageErrors, DeleteExternalImageResponse, DeleteExternalImageResponses, DeleteFunnelData, DeleteFunnelErrors, DeleteFunnelResponses, DeleteGitProviderData, DeleteGitProviderErrors, DeleteGitProviderResponse, DeleteGitProviderResponses, DeleteGlobalMcpData, DeleteGlobalMcpErrors, DeleteGlobalMcpResponse, DeleteGlobalMcpResponses, DeleteGlobalSkillData, DeleteGlobalSkillErrors, DeleteGlobalSkillResponse, DeleteGlobalSkillResponses, DeleteIpAccessControlData, DeleteIpAccessControlError, DeleteIpAccessControlErrors, DeleteIpAccessControlResponse, DeleteIpAccessControlResponses, DeleteMcpData, DeleteMcpErrors, DeleteMcpResponse, DeleteMcpResponses, DeleteMonitorData, DeleteMonitorErrors, DeleteMonitorResponse, DeleteMonitorResponses, DeleteNotificationProviderData, DeleteNotificationProviderErrors, DeleteNotificationProviderResponse, DeleteNotificationProviderResponses, DeleteOidcProviderData, DeleteOidcProviderResponse, DeleteOidcProviderResponses, DeleteOidcRoleMappingData, DeleteOidcRoleMappingResponse, DeleteOidcRoleMappingResponses, DeletePreferencesData, DeletePreferencesErrors, DeletePreferencesResponse, DeletePreferencesResponses, DeleteProjectData, DeleteProjectErrors, DeleteProjectResponse, DeleteProjectResponses, DeleteProjectSecretData, DeleteProjectSecretErrors, DeleteProjectSecretResponse, DeleteProjectSecretResponses, DeleteProviderKeyData, DeleteProviderKeyError, DeleteProviderKeyErrors, DeleteProviderKeyResponse, DeleteProviderKeyResponses, DeleteProviderSafelyData, DeleteProviderSafelyErrors, DeleteProviderSafelyResponse, DeleteProviderSafelyResponses, DeleteReleaseSourceFilesData, DeleteReleaseSourceFilesErrors, DeleteReleaseSourceFilesResponse, DeleteReleaseSourceFilesResponses, DeleteReleaseSourceMapsData, DeleteReleaseSourceMapsErrors, DeleteReleaseSourceMapsResponse, DeleteReleaseSourceMapsResponses, DeleteResponse, DeleteRouteData, DeleteRouteErrors, DeleteRouteResponse, DeleteRouteResponses, DeleteS3SourceData, DeleteS3SourceError, DeleteS3SourceErrors, DeleteS3SourceResponse, DeleteS3SourceResponses, DeleteScanData, DeleteScanError, DeleteScanErrors, DeleteScanResponse, DeleteScanResponses, DeleteSecretData, DeleteSecretErrors, DeleteSecretResponse, DeleteSecretResponses, DeleteServiceData, DeleteServiceErrors, DeleteServiceResponse, DeleteServiceResponses, DeleteSessionReplayData, DeleteSessionReplayError, DeleteSessionReplayErrors, DeleteSessionReplayResponses, DeleteSkillData, DeleteSkillErrors, DeleteSkillResponse, DeleteSkillResponses, DeleteSourceMapData, DeleteSourceMapErrors, DeleteSourceMapResponse, DeleteSourceMapResponses, DeleteStaticBundleData, DeleteStaticBundleErrors, DeleteStaticBundleResponse, DeleteStaticBundleResponses, DeleteTeamData, DeleteTeamErrors, DeleteTeamResponse, DeleteTeamResponses, DeleteUserData, DeleteUserErrors, DeleteUserResponse, DeleteUserResponses, DeleteWebhookData, DeleteWebhookErrors, DeleteWebhookResponse, DeleteWebhookResponses, DelRequest, DelResponse, DeployFromImageData, DeployFromImageErrors, DeployFromImageRequest, DeployFromImageResponse, DeployFromImageResponses, DeployFromImageUploadData, DeployFromImageUploadErrors, DeployFromImageUploadQuery, DeployFromImageUploadResponse, DeployFromImageUploadResponses, DeployFromStaticData, DeployFromStaticErrors, DeployFromStaticRequest, DeployFromStaticResponse, DeployFromStaticResponses, DeployFromUploadedSourceData, DeployFromUploadedSourceErrors, DeployFromUploadedSourceResponse, DeployFromUploadedSourceResponses, DeploymentConfig, DeploymentConfigSnapshot, DeploymentConfiguration, DeploymentContainerLogContentResponse, DeploymentContainerLogResponse, DeploymentContainerLogsListResponse, DeploymentEnvironmentResponse, DeploymentJobResponse, DeploymentJobsResponse, DeploymentListResponse, DeploymentMetadata, DeploymentMetricsGetLatestData, DeploymentMetricsGetLatestErrors, DeploymentMetricsGetLatestResponse, DeploymentMetricsGetLatestResponses, DeploymentMetricsGetRangeData, DeploymentMetricsGetRangeErrors, DeploymentMetricsGetRangeResponse, DeploymentMetricsGetRangeResponses, DeploymentMetricsToggleData, DeploymentMetricsToggleErrors, DeploymentMetricsToggleResponses, DeploymentResponse, DeploymentStateResponse, DeploymentStrategy, DeploymentTokenListResponse, DeploymentTokenResponse, DestroySandboxData, DestroySandboxErrors, DestroySandboxResponse, DestroySandboxResponses, DetachScheduleServiceData, DetachScheduleServiceError, DetachScheduleServiceErrors, DetachScheduleServiceResponse, DetachScheduleServiceResponses, DetectionConfig, DetectPublicPresetsData, DetectPublicPresetsErrors, DetectPublicPresetsResponse, DetectPublicPresetsResponses, DeviceCount, DigestSections, Direction, DisableBackupScheduleData, DisableBackupScheduleErrors, DisableBackupScheduleResponse, DisableBackupScheduleResponses, DisableBlobResponse, DisableKvResponse, DisableMfaData, DisableMfaErrors, DisableMfaRequest, DisableMfaResponse, DisableMfaResponses, DisconnectCloudData, DisconnectCloudResponse, DisconnectCloudResponses, DiscoverRequest, DiscoverResponse, DiscoverWorkloadsData, DiscoverWorkloadsErrors, DiscoverWorkloadsResponse, DiscoverWorkloadsResponses, DiskInfo, DiskSpaceAlert, DiskSpaceAlertSettings, DiskSpaceCheckResult, DnsAckRequest, DnsAckResponse, DnsChallengeRecordResult, DnsChangesResponse, DnsCompletionResponse, DnsLookupError, DnsLookupRequest, DnsLookupResponse, DnsProviderCredentials, DnsProviderResponse, DnsProviderSettings, DnsProviderSettingsMasked, DnsProviderType, DnsRecord, DnsRecordChange, DnsRecordContent, DnsRecordResponse, DnsRecordSetupResult, DnsRecordStatusResponse, DnsZone, DockerComposePresetConfig, DockerfilePresetConfig, DockerfileVariant, DockerRegistrySettings, DockerRegistrySettingsMasked, DomainAction, DomainChallengeResponse, DomainData, DomainEnvironmentResponse, DomainError, DomainErrors, DomainPlan, DomainResponse, DomainResponse2, DomainResponses, DownloadGlobalSkillArchiveData, DownloadGlobalSkillArchiveErrors, DownloadGlobalSkillArchiveResponse, DownloadGlobalSkillArchiveResponses, DownloadObjectData, DownloadObjectErrors, DownloadObjectResponse, DownloadObjectResponses, DownloadSkillArchiveData, DownloadSkillArchiveErrors, DownloadSkillArchiveResponse, DownloadSkillArchiveResponses, DrainNodeResponse, DrainStatusResponse, DropArchiveUpload, DropInspectionResponse, DropOffPoint, DropPresetCandidate, EmailConfig, EmailDomainResponse, EmailDomainWithDnsResponse, EmailProviderResponse, EmailProviderTypeRoute, EmailRequest, EmailResponse, EmailStatsResponse, EmailStatusData, EmailStatusErrors, EmailStatusResponse, EmailStatusResponse2, EmailStatusResponses, EmailTrackingResponse, EmailTrackingSetupResponse, EmailTrackingStatusResponse, EmbeddingData, EmbeddingInput, EmbeddingRequest, EmbeddingResponse, EmbeddingsData, EmbeddingsError, EmbeddingsErrors, EmbeddingsResponse, EmbeddingsResponses, EmbeddingUsage, EnableBackupScheduleData, EnableBackupScheduleErrors, EnableBackupScheduleResponse, EnableBackupScheduleResponses, EnableBlobRequest, EnableBlobResponse, EnableKvRequest, EnableKvResponse, EnablePgStatStatementsResponse, EndpointDto, EnqueuedJob, EnrichVisitorData, EnrichVisitorErrors, EnrichVisitorRequest, EnrichVisitorResponse, EnrichVisitorResponse2, EnrichVisitorResponses, EnrollCloudData, EnrollCloudRequest, EnrollCloudResponse, EnrollCloudResponses, EnrollmentTokenInfo, EnrollmentTokenListResponse, EntityInfoResponse, EntityResponse, EnvironmentConfiguration, EnvironmentDomainResponse, EnvironmentInfo, EnvironmentResponse, EnvironmentVariable, EnvironmentVariableInfo, EnvironmentVariableResponse, EnvironmentVariableValueResponse, EnvVarInput, EnvVarIntegrationInfo, EnvVarResponse, EnvVarTemplateResponse, ErrorDashboardStatsQuery, ErrorDashboardStatsResponse, ErrorEventResponse, ErrorGroupResponse, ErrorGroupStatsResponse, ErrorResponse, ErrorRow, ErrorTimeSeriesDataResponse, ErrorTimeSeriesQuery, EventActivityBucket, EventBreakdown, EventBrowserStats, EventCount, EventCountryStats, EventDetailQuery, EventDetailResponse, EventEntriesQuery, EventEntriesResponse, EventEntryInfo, EventKind, EventMetricsPayload, EventReferrerStats, EventsCountQuery, EventsResponse, EventTimeline, EventTimelineQuery, EventType, EventTypeBreakdown, EventTypeBreakdownQuery, EventTypeResponse, EventTypesResponse, EventVisitorInfo, EventVisitorsQuery, EventVisitorsResponse, ExecBody, ExecData, ExecDetachedData, ExecDetachedErrors, ExecDetachedResponse, ExecDetachedResponse2, ExecDetachedResponses, ExecErrors, ExecResponse, ExecResponse2, ExecResponses, ExecuteDeploymentOperationData, ExecuteDeploymentOperationErrors, ExecuteDeploymentOperationResponse, ExecuteDeploymentOperationResponses, ExecuteImportData, ExecuteImportErrors, ExecuteImportRequest, ExecuteImportResponse, ExecuteImportResponse2, ExecuteImportResponses, ExecuteOperationRequest, ExpireRequest, ExpireResponse, ExplorerSupportResponse, ExtendTimeoutBody, ExtendTimeoutData, ExtendTimeoutErrors, ExtendTimeoutResponse, ExtendTimeoutResponses, ExternalImageResponse, ExternalServiceBackupResponse, ExternalServiceDetails, ExternalServiceEnablePgStatStatementsData, ExternalServiceEnablePgStatStatementsErrors, ExternalServiceEnablePgStatStatementsResponse, ExternalServiceEnablePgStatStatementsResponses, ExternalServiceInfo, ExternalServiceMetricsByDatabaseData, ExternalServiceMetricsByDatabaseErrors, ExternalServiceMetricsByDatabaseResponse, ExternalServiceMetricsByDatabaseResponses, ExternalServiceMetricsCreateAlertRuleData, ExternalServiceMetricsCreateAlertRuleErrors, ExternalServiceMetricsCreateAlertRuleResponse, ExternalServiceMetricsCreateAlertRuleResponses, ExternalServiceMetricsDeleteAlertRuleData, ExternalServiceMetricsDeleteAlertRuleErrors, ExternalServiceMetricsDeleteAlertRuleResponse, ExternalServiceMetricsDeleteAlertRuleResponses, ExternalServiceMetricsGetAlertRulesData, ExternalServiceMetricsGetAlertRulesErrors, ExternalServiceMetricsGetAlertRulesResponse, ExternalServiceMetricsGetAlertRulesResponses, ExternalServiceMetricsGetLatestData, ExternalServiceMetricsGetLatestErrors, ExternalServiceMetricsGetLatestResponse, ExternalServiceMetricsGetLatestResponses, ExternalServiceMetricsGetRangeData, ExternalServiceMetricsGetRangeErrors, ExternalServiceMetricsGetRangeResponse, ExternalServiceMetricsGetRangeResponses, ExternalServiceMetricsStatusData, ExternalServiceMetricsStatusErrors, ExternalServiceMetricsStatusResponse, ExternalServiceMetricsStatusResponses, ExternalServiceMetricsToggleData, ExternalServiceMetricsToggleErrors, ExternalServiceMetricsToggleResponses, ExternalServiceMetricsUpdateAlertRuleData, ExternalServiceMetricsUpdateAlertRuleErrors, ExternalServiceMetricsUpdateAlertRuleResponse, ExternalServiceMetricsUpdateAlertRuleResponses, ExternalServiceResetPgStatStatementsData, ExternalServiceResetPgStatStatementsErrors, ExternalServiceResetPgStatStatementsResponse, ExternalServiceResetPgStatStatementsResponses, ExternalServiceSummary, FieldResponse, FinalizeOrderData, FinalizeOrderErrors, FinalizeOrderResponse, FinalizeOrderResponses, FinalizeProjectReleaseData, FinalizeProjectReleaseErrors, FinalizeProjectReleaseResponse, FinalizeProjectReleaseResponses, FindConversationData, FindConversationErrors, FindConversationResponse, FindConversationResponses, FiringSeriesEntry, FlagEnvironmentResponse, FlagListResponse, FlagResponse, FlagSnapshot, FlagSnapshotResponse, FlagValueType, ForecastAlgorithm, ForecastParams, FullError, FullEvent, FullRequest, FunnelMetricsResponse, FunnelResponse, GatewayStatus, GenAiEvent, GenAiSpanDetail, GenAiTraceDetailResponse, GenAiTraceSummariesResponse, GenAiTraceSummary, GeneralStatsQuery, GeneralStatsResponse, GenerateDockerfileRequest, GenerateDockerfileResponse, GenerateJoinTokenData, GenerateJoinTokenErrors, GenerateJoinTokenResponse, GenerateJoinTokenResponse2, GenerateJoinTokenResponses, GeneratePresetDockerfileData, GeneratePresetDockerfileErrors, GeneratePresetDockerfileResponse, GeneratePresetDockerfileResponses, GeoLocationResponse, GeoRestrictionsConfig, GetAccessInfoData, GetAccessInfoErrors, GetAccessInfoResponse, GetAccessInfoResponses, GetActiveVisitorsData, GetActiveVisitorsErrors, GetActiveVisitorsResponse, GetActiveVisitorsResponses, GetActivityGraphData, GetActivityGraphErrors, GetActivityGraphResponse, GetActivityGraphResponses, GetAdminGateData, GetAdminGateErrors, GetAdminGateResponse, GetAdminGateResponses, GetAgentData, GetAgentErrors, GetAgentResponse, GetAgentResponses, GetAggregatedBucketsData, GetAggregatedBucketsErrors, GetAggregatedBucketsResponse, GetAggregatedBucketsResponses, GetAiAgentBreakdownData, GetAiAgentBreakdownError, GetAiAgentBreakdownErrors, GetAiAgentBreakdownResponse, GetAiAgentBreakdownResponses, GetAiAgentPagesData, GetAiAgentPagesError, GetAiAgentPagesErrors, GetAiAgentPagesResponse, GetAiAgentPagesResponses, GetAiAgentTimelineData, GetAiAgentTimelineError, GetAiAgentTimelineErrors, GetAiAgentTimelineResponse, GetAiAgentTimelineResponses, GetAiDataAccessData, GetAiDataAccessErrors, GetAiDataAccessResponse, GetAiDataAccessResponses, GetAiPageBreakdownData, GetAiPageBreakdownError, GetAiPageBreakdownErrors, GetAiPageBreakdownResponse, GetAiPageBreakdownResponses, GetAiStatusBreakdownData, GetAiStatusBreakdownError, GetAiStatusBreakdownErrors, GetAiStatusBreakdownResponse, GetAiStatusBreakdownResponses, GetAlertData, GetAlertError, GetAlertErrors, GetAlertResponse, GetAlertResponses, GetAlertRuleData, GetAlertRuleErrors, GetAlertRuleResponse, GetAlertRuleResponses, GetAllRepositoriesByNameData, GetAllRepositoriesByNameErrors, GetAllRepositoriesByNameResponse, GetAllRepositoriesByNameResponses, GetAnalyticsActiveVisitorsData, GetAnalyticsActiveVisitorsErrors, GetAnalyticsActiveVisitorsResponse, GetAnalyticsActiveVisitorsResponses, GetAnalyticsEventsCountData, GetAnalyticsEventsCountErrors, GetAnalyticsEventsCountResponse, GetAnalyticsEventsCountResponses, GetAnalyticsSessionEventsData, GetAnalyticsSessionEventsErrors, GetAnalyticsSessionEventsResponse, GetAnalyticsSessionEventsResponses, GetAnalyticsVisitorSessionsData, GetAnalyticsVisitorSessionsErrors, GetAnalyticsVisitorSessionsResponse, GetAnalyticsVisitorSessionsResponses, GetApiKeyData, GetApiKeyErrors, GetApiKeyPermissionsData, GetApiKeyPermissionsErrors, GetApiKeyPermissionsResponse, GetApiKeyPermissionsResponses, GetApiKeyResponse, GetApiKeyResponses, GetAuditLogData, GetAuditLogErrors, GetAuditLogResponse, GetAuditLogResponses, GetBackupData, GetBackupError, GetBackupErrors, GetBackupResponse, GetBackupResponses, GetBackupScheduleData, GetBackupScheduleErrors, GetBackupScheduleResponse, GetBackupScheduleResponses, GetBranchesByRepositoryIdData, GetBranchesByRepositoryIdErrors, GetBranchesByRepositoryIdResponse, GetBranchesByRepositoryIdResponses, GetBucketedIncidentsData, GetBucketedIncidentsErrors, GetBucketedIncidentsResponse, GetBucketedIncidentsResponses, GetBucketedStatusData, GetBucketedStatusErrors, GetBucketedStatusResponse, GetBucketedStatusResponses, GetChallengeTokenData, GetChallengeTokenErrors, GetChallengeTokenResponse, GetChallengeTokenResponses, GetChatReadinessData, GetChatReadinessErrors, GetChatReadinessResponse, GetChatReadinessResponses, GetCliStatusData, GetCliStatusErrors, GetCliStatusResponses, GetCloudCapabilityData, GetCloudCapabilityResponse, GetCloudCapabilityResponses, GetCloudStatusData, GetCloudStatusResponse, GetCloudStatusResponses, GetClusterHealthData, GetClusterHealthErrors, GetClusterHealthResponse, GetClusterHealthResponses, GetClusterMemberData, GetClusterMemberErrors, GetClusterMemberResponse, GetClusterMemberResponses, GetCmdData, GetCmdErrors, GetCmdResponse, GetCmdResponses, GetContainerDetailData, GetContainerDetailErrors, GetContainerDetailResponse, GetContainerDetailResponses, GetContainerEnvironmentVariableData, GetContainerEnvironmentVariableErrors, GetContainerEnvironmentVariableResponse, GetContainerEnvironmentVariableResponses, GetContainerLogsByIdData, GetContainerLogsByIdErrors, GetContainerLogsData, GetContainerLogsErrors, GetContainerMetricsData, GetContainerMetricsErrors, GetContainerMetricsResponse, GetContainerMetricsResponses, GetConversationData, GetConversationDetailData, GetConversationDetailError, GetConversationDetailErrors, GetConversationDetailResponse, GetConversationDetailResponses, GetConversationErrors, GetConversationResponse, GetConversationResponses, GetConversationsData, GetConversationsError, GetConversationsErrors, GetConversationsResponse, GetConversationsResponses, GetCronByIdData, GetCronByIdErrors, GetCronByIdResponse, GetCronByIdResponses, GetCronExecutionsData, GetCronExecutionsErrors, GetCronExecutionsResponse, GetCronExecutionsResponses, GetCrossProjectTraceSiblingsData, GetCrossProjectTraceSiblingsError, GetCrossProjectTraceSiblingsErrors, GetCrossProjectTraceSiblingsResponse, GetCrossProjectTraceSiblingsResponses, GetCurrentMonitorStatusData, GetCurrentMonitorStatusErrors, GetCurrentMonitorStatusResponse, GetCurrentMonitorStatusResponses, GetCurrentUserData, GetCurrentUserErrors, GetCurrentUserResponse, GetCurrentUserResponses, GetCustomDomainData, GetCustomDomainErrors, GetCustomDomainResponse, GetCustomDomainResponses, GetDashboardData, GetDashboardError, GetDashboardErrors, GetDashboardProjectsAnalyticsData, GetDashboardProjectsAnalyticsErrors, GetDashboardProjectsAnalyticsResponse, GetDashboardProjectsAnalyticsResponses, GetDashboardResponse, GetDashboardResponses, GetDeliveryData, GetDeliveryErrors, GetDeliveryResponse, GetDeliveryResponses, GetDeploymentContainerLogContentData, GetDeploymentContainerLogContentErrors, GetDeploymentContainerLogContentResponse, GetDeploymentContainerLogContentResponses, GetDeploymentData, GetDeploymentErrors, GetDeploymentJobLogsData, GetDeploymentJobLogsErrors, GetDeploymentJobLogsResponse, GetDeploymentJobLogsResponses, GetDeploymentJobsData, GetDeploymentJobsErrors, GetDeploymentJobsResponse, GetDeploymentJobsResponses, GetDeploymentOperationsData, GetDeploymentOperationsErrors, GetDeploymentOperationsResponse, GetDeploymentOperationsResponses, GetDeploymentOperationStatusData, GetDeploymentOperationStatusErrors, GetDeploymentOperationStatusResponse, GetDeploymentOperationStatusResponses, GetDeploymentResponse, GetDeploymentResponses, GetDeploymentsParams, GetDeploymentTokenData, GetDeploymentTokenErrors, GetDeploymentTokenResponse, GetDeploymentTokenResponses, GetDiskStatusData, GetDiskStatusErrors, GetDiskStatusResponse, GetDiskStatusResponses, GetDnsChangesData, GetDnsChangesErrors, GetDnsChangesResponse, GetDnsChangesResponses, GetDnsProviderData, GetDnsProviderErrors, GetDnsProviderResponse, GetDnsProviderResponses, GetDomainByHostData, GetDomainByHostErrors, GetDomainByHostResponse, GetDomainByHostResponses, GetDomainByIdData, GetDomainByIdErrors, GetDomainByIdResponse, GetDomainByIdResponses, GetDomainByNameData, GetDomainByNameErrors, GetDomainByNameResponse, GetDomainByNameResponses, GetDomainData, GetDomainDnsRecordsData, GetDomainDnsRecordsErrors, GetDomainDnsRecordsResponse, GetDomainDnsRecordsResponses, GetDomainErrors, GetDomainOrderData, GetDomainOrderErrors, GetDomainOrderResponse, GetDomainOrderResponses, GetDomainResponse, GetDomainResponses, GetEmailData, GetEmailErrors, GetEmailEventsData, GetEmailEventsErrors, GetEmailEventsResponse, GetEmailEventsResponses, GetEmailLinksData, GetEmailLinksErrors, GetEmailLinksResponse, GetEmailLinksResponses, GetEmailProviderData, GetEmailProviderErrors, GetEmailProviderResponse, GetEmailProviderResponses, GetEmailResponse, GetEmailResponses, GetEmailStatsData, GetEmailStatsErrors, GetEmailStatsResponse, GetEmailStatsResponses, GetEmailTrackingData, GetEmailTrackingErrors, GetEmailTrackingResponse, GetEmailTrackingResponses, GetEmailTrackingStatusData, GetEmailTrackingStatusErrors, GetEmailTrackingStatusResponse, GetEmailTrackingStatusResponses, GetEntityInfoData, GetEntityInfoErrors, GetEntityInfoResponse, GetEntityInfoResponses, GetEnvironmentCronsData, GetEnvironmentCronsErrors, GetEnvironmentCronsResponse, GetEnvironmentCronsResponses, GetEnvironmentData, GetEnvironmentDomainsData, GetEnvironmentDomainsErrors, GetEnvironmentDomainsResponse, GetEnvironmentDomainsResponses, GetEnvironmentErrors, GetEnvironmentResponse, GetEnvironmentResponses, GetEnvironmentsData, GetEnvironmentsErrors, GetEnvironmentsResponse, GetEnvironmentsResponses, GetEnvironmentVariablesData, GetEnvironmentVariablesErrors, GetEnvironmentVariablesQuery, GetEnvironmentVariablesResponse, GetEnvironmentVariablesResponses, GetEnvironmentVariableValueData, GetEnvironmentVariableValueErrors, GetEnvironmentVariableValueResponse, GetEnvironmentVariableValueResponses, GetErrorDashboardStatsData, GetErrorDashboardStatsErrors, GetErrorDashboardStatsResponse, GetErrorDashboardStatsResponses, GetErrorEventData, GetErrorEventErrors, GetErrorEventResponse, GetErrorEventResponses, GetErrorGroupData, GetErrorGroupErrors, GetErrorGroupResponse, GetErrorGroupResponses, GetErrorStatsData, GetErrorStatsErrors, GetErrorStatsResponse, GetErrorStatsResponses, GetErrorTimeSeriesData, GetErrorTimeSeriesErrors, GetErrorTimeSeriesResponse, GetErrorTimeSeriesResponses, GetEventDetailData, GetEventDetailErrors, GetEventDetailResponse, GetEventDetailResponses, GetEventEntriesData, GetEventEntriesErrors, GetEventEntriesResponse, GetEventEntriesResponses, GetEventsCountData, GetEventsCountErrors, GetEventsCountResponse, GetEventsCountResponses, GetEventsTimelineData, GetEventsTimelineErrors, GetEventsTimelineResponse, GetEventsTimelineResponses, GetEventTypeBreakdownData, GetEventTypeBreakdownErrors, GetEventTypeBreakdownResponse, GetEventTypeBreakdownResponses, GetEventVisitorsData, GetEventVisitorsErrors, GetEventVisitorsResponse, GetEventVisitorsResponses, GetExternalImageData, GetExternalImageErrors, GetExternalImageResponse, GetExternalImageResponses, GetFileData, GetFileErrors, GetFileResponse, GetFileResponses, GetFlagData, GetFlagErrors, GetFlagResponse, GetFlagResponses, GetFlagSnapshotData, GetFlagSnapshotErrors, GetFlagSnapshotResponse, GetFlagSnapshotResponses, GetFunnelMetricsData, GetFunnelMetricsErrors, GetFunnelMetricsQuery, GetFunnelMetricsResponse, GetFunnelMetricsResponses, GetGenaiTraceData, GetGenaiTraceError, GetGenaiTraceErrors, GetGenaiTraceResponse, GetGenaiTraceResponses, GetGeneralStatsData, GetGeneralStatsErrors, GetGeneralStatsResponse, GetGeneralStatsResponses, GetGitProviderData, GetGitProviderErrors, GetGitProviderResponse, GetGitProviderResponses, GetGlobalEventsData, GetGlobalEventsErrors, GetGlobalEventsResponse, GetGlobalEventsResponses, GetGlobalEventStatsData, GetGlobalEventStatsErrors, GetGlobalEventStatsResponse, GetGlobalEventStatsResponses, GetGlobalMcpData, GetGlobalMcpErrors, GetGlobalMcpResponse, GetGlobalMcpResponses, GetGlobalSandboxStatusData, GetGlobalSandboxStatusErrors, GetGlobalSandboxStatusResponse, GetGlobalSandboxStatusResponses, GetGlobalSkillData, GetGlobalSkillErrors, GetGlobalSkillResponse, GetGlobalSkillResponses, GetGroupedPageMetricsData, GetGroupedPageMetricsError, GetGroupedPageMetricsErrors, GetGroupedPageMetricsResponse, GetGroupedPageMetricsResponses, GetHealthData, GetHealthError, GetHealthErrors, GetHealthResponse, GetHealthResponses, GetHourlyVisitsData, GetHourlyVisitsErrors, GetHourlyVisitsResponse, GetHourlyVisitsResponses, GetHttpChallengeDebugData, GetHttpChallengeDebugErrors, GetHttpChallengeDebugResponse, GetHttpChallengeDebugResponses, GetImportStatusData, GetImportStatusErrors, GetImportStatusResponse, GetImportStatusResponses, GetIncidentData, GetIncidentErrors, GetIncidentResponse, GetIncidentResponses, GetIncidentUpdatesData, GetIncidentUpdatesErrors, GetIncidentUpdatesResponse, GetIncidentUpdatesResponses, GetIpAccessControlData, GetIpAccessControlError, GetIpAccessControlErrors, GetIpAccessControlResponse, GetIpAccessControlResponses, GetIpGeolocationData, GetIpGeolocationError, GetIpGeolocationErrors, GetIpGeolocationResponse, GetIpGeolocationResponses, GetJoinTokenStatusData, GetJoinTokenStatusErrors, GetJoinTokenStatusResponse, GetJoinTokenStatusResponses, GetLastDeploymentData, GetLastDeploymentErrors, GetLastDeploymentResponse, GetLastDeploymentResponses, GetLatestScanData, GetLatestScanError, GetLatestScanErrors, GetLatestScanResponse, GetLatestScanResponses, GetLatestScansPerEnvironmentData, GetLatestScansPerEnvironmentError, GetLatestScansPerEnvironmentErrors, GetLatestScansPerEnvironmentResponse, GetLatestScansPerEnvironmentResponses, GetLiveVisitorsListData, GetLiveVisitorsListErrors, GetLiveVisitorsListResponse, GetLiveVisitorsListResponses, GetLogContextData, GetLogContextError, GetLogContextErrors, GetLogContextResponse, GetLogContextResponses, GetMcpData, GetMcpErrors, GetMcpResponse, GetMcpResponses, GetMetricsOverTimeData, GetMetricsOverTimeError, GetMetricsOverTimeErrors, GetMetricsOverTimeResponse, GetMetricsOverTimeResponses, GetMonitorData, GetMonitorErrors, GetMonitorResponse, GetMonitorResponses, GetNotificationProviderData, GetNotificationProviderErrors, GetNotificationProviderResponse, GetNotificationProviderResponses, GetOnDemandCertStatusData, GetOnDemandCertStatusErrors, GetOnDemandCertStatusResponse, GetOnDemandCertStatusResponses, GetOrCreateDsnData, GetOrCreateDsnErrors, GetOrCreateDsnRequest, GetOrCreateDsnResponse, GetOrCreateDsnResponses, GetPageFlowData, GetPageFlowErrors, GetPageFlowResponse, GetPageFlowResponses, GetPageHourlySessionsData, GetPageHourlySessionsErrors, GetPageHourlySessionsResponse, GetPageHourlySessionsResponses, GetPagePathDetailData, GetPagePathDetailErrors, GetPagePathDetailResponse, GetPagePathDetailResponses, GetPagePathsData, GetPagePathsErrors, GetPagePathsResponse, GetPagePathsResponses, GetPagePathsSparklinesData, GetPagePathsSparklinesErrors, GetPagePathsSparklinesResponse, GetPagePathsSparklinesResponses, GetPagePathVisitorsData, GetPagePathVisitorsErrors, GetPagePathVisitorsResponse, GetPagePathVisitorsResponses, GetPendingActionData, GetPendingActionErrors, GetPendingActionResponse, GetPendingActionResponses, GetPerformanceMetricsData, GetPerformanceMetricsError, GetPerformanceMetricsErrors, GetPerformanceMetricsResponse, GetPerformanceMetricsResponses, GetPgUpgradeData, GetPgUpgradeErrors, GetPgUpgradeLogsData, GetPgUpgradeLogsErrors, GetPgUpgradeLogsResponse, GetPgUpgradeLogsResponses, GetPgUpgradeResponse, GetPgUpgradeResponses, GetPipelineStatsData, GetPipelineStatsError, GetPipelineStatsErrors, GetPipelineStatsResponse, GetPipelineStatsResponses, GetPlatformInfoData, GetPlatformInfoErrors, GetPlatformInfoResponse, GetPlatformInfoResponses, GetPostgresWalHealthData, GetPostgresWalHealthErrors, GetPostgresWalHealthResponse, GetPostgresWalHealthResponses, GetPreferencesData, GetPreferencesErrors, GetPreferencesResponse, GetPreferencesResponses, GetPreviewGatewayLogsData, GetPreviewGatewayLogsResponse, GetPreviewGatewayLogsResponses, GetPreviewGatewaySettingsData, GetPreviewGatewaySettingsResponse, GetPreviewGatewaySettingsResponses, GetPreviewGatewayStatusData, GetPreviewGatewayStatusResponse, GetPreviewGatewayStatusResponses, GetPricingData, GetPricingError, GetPricingErrors, GetPricingResponse, GetPricingResponses, GetPrivateIpData, GetPrivateIpErrors, GetPrivateIpResponses, GetProjectAlarmsSummaryData, GetProjectAlarmsSummaryErrors, GetProjectAlarmsSummaryResponse, GetProjectAlarmsSummaryResponses, GetProjectBySlugData, GetProjectBySlugErrors, GetProjectBySlugResponse, GetProjectBySlugResponses, GetProjectData, GetProjectDeploymentsData, GetProjectDeploymentsErrors, GetProjectDeploymentsResponse, GetProjectDeploymentsResponses, GetProjectErrors, GetProjectResponse, GetProjectResponses, GetProjectsData, GetProjectSecretsQuery, GetProjectsErrors, GetProjectServiceEnvironmentVariablesData, GetProjectServiceEnvironmentVariablesErrors, GetProjectServiceEnvironmentVariablesResponse, GetProjectServiceEnvironmentVariablesResponses, GetProjectSessionReplaysData, GetProjectSessionReplaysError, GetProjectSessionReplaysErrors, GetProjectSessionReplaysQuery, GetProjectSessionReplaysResponse, GetProjectSessionReplaysResponse2, GetProjectSessionReplaysResponses, GetProjectsHealthData, GetProjectsHealthError, GetProjectsHealthErrors, GetProjectsHealthResponse, GetProjectsHealthResponses, GetProjectsMonitorHealthData, GetProjectsMonitorHealthErrors, GetProjectsMonitorHealthResponse, GetProjectsMonitorHealthResponses, GetProjectsResponse, GetProjectsResponses, GetProjectStatisticsData, GetProjectStatisticsErrors, GetProjectStatisticsResponse, GetProjectStatisticsResponses, GetProjectTemplateData, GetProjectTemplateErrors, GetProjectTemplateResponse, GetProjectTemplateResponses, GetPropertyBreakdownData, GetPropertyBreakdownErrors, GetPropertyBreakdownResponse, GetPropertyBreakdownResponses, GetPropertyTimelineData, GetPropertyTimelineErrors, GetPropertyTimelineResponse, GetPropertyTimelineResponses, GetProviderConnectionsData, GetProviderConnectionsErrors, GetProviderConnectionsResponse, GetProviderConnectionsResponses, GetProviderMetadataData, GetProviderMetadataErrors, GetProviderMetadataResponse, GetProviderMetadataResponses, GetProvidersMetadataData, GetProvidersMetadataErrors, GetProvidersMetadataResponse, GetProvidersMetadataResponses, GetProxyLogByIdData, GetProxyLogByIdError, GetProxyLogByIdErrors, GetProxyLogByIdResponse, GetProxyLogByIdResponses, GetProxyLogByRequestIdData, GetProxyLogByRequestIdError, GetProxyLogByRequestIdErrors, GetProxyLogByRequestIdResponse, GetProxyLogByRequestIdResponses, GetProxyLogsData, GetProxyLogsError, GetProxyLogsErrors, GetProxyLogsResponse, GetProxyLogsResponses, GetPublicBranchesData, GetPublicBranchesErrors, GetPublicBranchesResponse, GetPublicBranchesResponses, GetPublicIpData, GetPublicIpErrors, GetPublicIpResponses, GetPublicRepositoryData, GetPublicRepositoryErrors, GetPublicRepositoryResponse, GetPublicRepositoryResponses, GetQueryContainerInfoData, GetQueryContainerInfoErrors, GetQueryContainerInfoResponse, GetQueryContainerInfoResponses, GetQuotaData, GetQuotaError, GetQuotaErrors, GetQuotaResponse, GetQuotaResponses, GetRecentActivityData, GetRecentActivityErrors, GetRecentActivityResponse, GetRecentActivityResponses, GetRemoteExternalImageData, GetRemoteExternalImageErrors, GetRemoteExternalImageResponse, GetRemoteExternalImageResponses, GetRepositoryBranchesData, GetRepositoryBranchesErrors, GetRepositoryBranchesResponse, GetRepositoryBranchesResponses, GetRepositoryByIdData, GetRepositoryByIdErrors, GetRepositoryByIdResponse, GetRepositoryByIdResponses, GetRepositoryByNameData, GetRepositoryByNameErrors, GetRepositoryByNameResponse, GetRepositoryByNameResponses, GetRepositoryPresetByNameData, GetRepositoryPresetByNameErrors, GetRepositoryPresetByNameResponse, GetRepositoryPresetByNameResponses, GetRepositoryPresetLiveData, GetRepositoryPresetLiveErrors, GetRepositoryPresetLiveResponse, GetRepositoryPresetLiveResponses, GetRepositoryTagsData, GetRepositoryTagsErrors, GetRepositoryTagsResponse, GetRepositoryTagsResponses, GetRequest, GetResolvedEnvironmentVariablesData, GetResolvedEnvironmentVariablesErrors, GetResolvedEnvironmentVariablesResponse, GetResolvedEnvironmentVariablesResponses, GetResolvedEnvironmentVariableValueData, GetResolvedEnvironmentVariableValueErrors, GetResolvedEnvironmentVariableValueResponse, GetResolvedEnvironmentVariableValueResponses, GetResponse, GetRestoreCapabilitiesData, GetRestoreCapabilitiesError, GetRestoreCapabilitiesErrors, GetRestoreCapabilitiesResponse, GetRestoreCapabilitiesResponses, GetRestoreRunData, GetRestoreRunError, GetRestoreRunErrors, GetRestoreRunResponse, GetRestoreRunResponses, GetRouteData, GetRouteErrors, GetRouteResponse, GetRouteResponses, GetRunData, GetRunErrors, GetRunResponse, GetRunResponses, GetRunWithLogsData, GetRunWithLogsErrors, GetRunWithLogsResponse, GetRunWithLogsResponses, GetS3CredentialsData, GetS3CredentialsErrors, GetS3CredentialsResponse, GetS3CredentialsResponses, GetS3SourceData, GetS3SourceError, GetS3SourceErrors, GetS3SourceResponse, GetS3SourceResponses, GetSandboxData, GetSandboxErrors, GetSandboxResponse, GetSandboxResponses, GetSandboxStatusData, GetSandboxStatusErrors, GetSandboxStatusResponse, GetSandboxStatusResponses, GetScanByDeploymentData, GetScanByDeploymentError, GetScanByDeploymentErrors, GetScanByDeploymentResponse, GetScanByDeploymentResponses, GetScanData, GetScanError, GetScanErrors, GetScanResponse, GetScanResponses, GetScanVulnerabilitiesData, GetScanVulnerabilitiesError, GetScanVulnerabilitiesErrors, GetScanVulnerabilitiesResponse, GetScanVulnerabilitiesResponses, GetServiceBySlugData, GetServiceBySlugErrors, GetServiceBySlugResponse, GetServiceBySlugResponses, GetServiceData, GetServiceEnvironmentVariableData, GetServiceEnvironmentVariableErrors, GetServiceEnvironmentVariableResponse, GetServiceEnvironmentVariableResponses, GetServiceEnvironmentVariablesData, GetServiceEnvironmentVariablesErrors, GetServiceEnvironmentVariablesResponse, GetServiceEnvironmentVariablesResponses, GetServiceErrors, GetServiceHealthStatusData, GetServiceHealthStatusErrors, GetServiceHealthStatusResponse, GetServiceHealthStatusResponses, GetServicePreviewEnvironmentVariableNamesData, GetServicePreviewEnvironmentVariableNamesErrors, GetServicePreviewEnvironmentVariableNamesResponse, GetServicePreviewEnvironmentVariableNamesResponses, GetServicePreviewEnvironmentVariablesMaskedData, GetServicePreviewEnvironmentVariablesMaskedErrors, GetServicePreviewEnvironmentVariablesMaskedResponse, GetServicePreviewEnvironmentVariablesMaskedResponses, GetServiceResponse, GetServiceResponses, GetServiceRuntimeData, GetServiceRuntimeErrors, GetServiceRuntimeResponse, GetServiceRuntimeResponses, GetServiceStatsData, GetServiceStatsErrors, GetServiceStatsResponse, GetServiceStatsResponses, GetServiceTypeParametersData, GetServiceTypeParametersErrors, GetServiceTypeParametersResponses, GetServiceTypesData, GetServiceTypesErrors, GetServiceTypesResponse, GetServiceTypesResponses, GetSessionDetailsData, GetSessionDetailsErrors, GetSessionDetailsResponse, GetSessionDetailsResponses, GetSessionEventsData, GetSessionEventsErrors, GetSessionEventsResponse, GetSessionEventsResponses, GetSessionLogsData, GetSessionLogsErrors, GetSessionLogsResponse, GetSessionLogsResponses, GetSessionReplayData, GetSessionReplayError, GetSessionReplayErrors, GetSessionReplayEventsData, GetSessionReplayEventsError, GetSessionReplayEventsErrors, GetSessionReplayEventsResponse, GetSessionReplayEventsResponses, GetSessionReplayResponse, GetSessionReplayResponse2, GetSessionReplayResponses, GetSettingsData, GetSettingsErrors, GetSettingsResponse, GetSettingsResponses, GetSkillData, GetSkillErrors, GetSkillResponse, GetSkillResponses, GetSlowQueriesData, GetSlowQueriesErrors, GetSlowQueriesResponse, GetSlowQueriesResponses, GetStaticBundleData, GetStaticBundleErrors, GetStaticBundleResponse, GetStaticBundleResponses, GetStatusOverviewData, GetStatusOverviewErrors, GetStatusOverviewResponse, GetStatusOverviewResponses, GetTagsByRepositoryIdData, GetTagsByRepositoryIdErrors, GetTagsByRepositoryIdResponse, GetTagsByRepositoryIdResponses, GetTeamData, GetTeamErrors, GetTeamResponse, GetTeamResponses, GetTimeBucketStatsData, GetTimeBucketStatsError, GetTimeBucketStatsErrors, GetTimeBucketStatsResponse, GetTimeBucketStatsResponses, GetTodayStatsData, GetTodayStatsError, GetTodayStatsErrors, GetTodayStatsResponse, GetTodayStatsResponses, GetTraceData, GetTraceError, GetTraceErrors, GetTraceResponse, GetTraceResponses, GetUnifiedTraceData, GetUnifiedTraceError, GetUnifiedTraceErrors, GetUnifiedTraceResponse, GetUnifiedTraceResponses, GetUniqueCountsData, GetUniqueCountsErrors, GetUniqueCountsResponse, GetUniqueCountsResponses, GetUniqueEventsData, GetUniqueEventsErrors, GetUniqueEventsQuery, GetUniqueEventsResponse, GetUniqueEventsResponses, GetUpdateStatusData, GetUpdateStatusErrors, GetUpdateStatusResponse, GetUpdateStatusResponses, GetUptimeHistoryData, GetUptimeHistoryErrors, GetUptimeHistoryResponse, GetUptimeHistoryResponses, GetUsageByProviderData, GetUsageByProviderError, GetUsageByProviderErrors, GetUsageByProviderResponse, GetUsageByProviderResponses, GetUsageRecentData, GetUsageRecentError, GetUsageRecentErrors, GetUsageRecentResponse, GetUsageRecentResponses, GetUsageSummaryData, GetUsageSummaryError, GetUsageSummaryErrors, GetUsageSummaryResponse, GetUsageSummaryResponses, GetUsageTimeseriesData, GetUsageTimeseriesError, GetUsageTimeseriesErrors, GetUsageTimeseriesResponse, GetUsageTimeseriesResponses, GetUsageTopModelsData, GetUsageTopModelsError, GetUsageTopModelsErrors, GetUsageTopModelsResponse, GetUsageTopModelsResponses, GetVisitorByGuidData, GetVisitorByGuidErrors, GetVisitorByGuidResponse, GetVisitorByGuidResponses, GetVisitorByIdData, GetVisitorByIdErrors, GetVisitorByIdResponse, GetVisitorByIdResponses, GetVisitorDetailsData, GetVisitorDetailsErrors, GetVisitorDetailsResponse, GetVisitorDetailsResponses, GetVisitorFacetsData, GetVisitorFacetsErrors, GetVisitorFacetsResponse, GetVisitorFacetsResponses, GetVisitorInfoData, GetVisitorInfoErrors, GetVisitorInfoResponse, GetVisitorInfoResponses, GetVisitorJourneyData, GetVisitorJourneyErrors, GetVisitorJourneyResponse, GetVisitorJourneyResponses, GetVisitorsData, GetVisitorsErrors, GetVisitorSessionsData, GetVisitorSessionsError, GetVisitorSessionsErrors, GetVisitorSessionsQuery, GetVisitorSessionsResponse, GetVisitorSessionsResponse2, GetVisitorSessionsResponses, GetVisitorsResponse, GetVisitorsResponses, GetVisitorStatsData, GetVisitorStatsErrors, GetVisitorStatsResponse, GetVisitorStatsResponses, GetWebhookData, GetWebhookErrors, GetWebhookResponse, GetWebhookResponses, GitPushEvent, GitRefResponse, GitSourcePlan, GlobalConversationResponse, GlobalEventStatsResponse, GlobalMrrResponse, GlobalRecentEventResponse, GlobalRevenueSummaryResponse, GrantProjectAccessData, GrantProjectAccessErrors, GrantProjectAccessResponse, GrantProjectAccessResponses, GroupedPageMetric, GroupedPageMetricsQuery, GroupedPageMetricsResponse, HandleGitProviderOauthCallbackData, HandleGitProviderOauthCallbackErrors, HasAnalyticsEventsData, HasAnalyticsEventsErrors, HasAnalyticsEventsResponse, HasAnalyticsEventsResponse2, HasAnalyticsEventsResponses, HasErrorGroupsData, HasErrorGroupsErrors, HasErrorGroupsResponse, HasErrorGroupsResponse2, HasErrorGroupsResponses, HasEventsQuery, HasEventsResponse, HasMetricsQuery, HasMetricsResponse, HasPerformanceMetricsData, HasPerformanceMetricsError, HasPerformanceMetricsErrors, HasPerformanceMetricsResponse, HasPerformanceMetricsResponses, HealthCheckConfiguration, HealthCheckEntryResponse, HealthResponse, HealthStatus, HealthSummary, HeartbeatApiRequest, HeartbeatResponse, HierarchyLevel, HistogramSummary, HostnameChange, HostnamePreviewResponse, HourlyPageSessions, HourlyVisitsQuery, HttpChallengeDebugResponse, ImportCredentials, ImportExecutionStatus, ImportExternalServiceData, ImportExternalServiceErrors, ImportExternalServiceRequest, ImportExternalServiceResponse, ImportExternalServiceResponses, ImportOutcomeResponse, ImportPlan, ImportRowErrorResponse, ImportSelector, ImportSource, ImportSourceCapabilities, ImportSourceInfo, ImportStatusResponse, IncidentBucket, IncidentBucketedResponse, IncidentResponse, IncidentUpdateResponse, IncrRequest, IncrResponse, IngestLogsByPathData, IngestLogsByPathError, IngestLogsByPathErrors, IngestLogsByPathResponses, IngestLogsData, IngestLogsError, IngestLogsErrors, IngestLogsResponses, IngestMetricsByPathData, IngestMetricsByPathError, IngestMetricsByPathErrors, IngestMetricsByPathResponses, IngestMetricsData, IngestMetricsError, IngestMetricsErrors, IngestMetricsResponses, IngestSentryEnvelopeData, IngestSentryEnvelopeErrors, IngestSentryEnvelopeResponses, IngestSentryEventData, IngestSentryEventErrors, IngestSentryEventResponse, IngestSentryEventResponses, IngestTracesByPathData, IngestTracesByPathError, IngestTracesByPathErrors, IngestTracesByPathResponses, IngestTracesData, IngestTracesError, IngestTracesErrors, IngestTracesResponses, InitAuthResponse, InitSessionReplayData, InitSessionReplayError, InitSessionReplayErrors, InitSessionReplayResponse, InitSessionReplayResponses, Insight, InsightSeverity, InsightsResponse, InsightStatus, InspectDropArchiveData, InspectDropArchiveErrors, InspectDropArchiveResponse, InspectDropArchiveResponses, IntegrationResponse, IpAccessControlQuery, IpAccessControlResponse, JobLogsData, JobLogsErrors, JobLogsResponses, JobStatusData, JobStatusErrors, JobStatusResponse, JobStatusResponse2, JobStatusResponses, JobSummaryResponse, JoinTokenStatusResponse, JourneyEvent, JourneySession, KeysRequest, KeysResponse, KillJobBody, KillJobData, KillJobErrors, KillJobResponse, KillJobResponses, KnownAiAgentsResponse, KvDelData, KvDelErrors, KvDelResponse, KvDelResponses, KvDisableData, KvDisableErrors, KvDisableResponse, KvDisableResponses, KvEnableData, KvEnableErrors, KvEnableResponse, KvEnableResponses, KvExpireData, KvExpireErrors, KvExpireResponse, KvExpireResponses, KvGetData, KvGetErrors, KvGetResponse, KvGetResponses, KvIncrData, KvIncrErrors, KvIncrResponse, KvIncrResponses, KvKeysData, KvKeysErrors, KvKeysResponse, KvKeysResponses, KvSetData, KvSetErrors, KvSetResponse, KvSetResponses, KvStatusData, KvStatusErrors, KvStatusResponse, KvStatusResponse2, KvStatusResponses, KvTtlData, KvTtlErrors, KvTtlResponse, KvTtlResponses, KvUpdateData, KvUpdateErrors, KvUpdateResponse, KvUpdateResponses, LatestRunForSourceData, LatestRunForSourceErrors, LatestRunForSourceResponse, LatestRunForSourceResponses, LemonSqueezyConfig, LetsEncryptSettings, LineContext, LinkCustomDomainToCertificateData, LinkCustomDomainToCertificateErrors, LinkCustomDomainToCertificateResponse, LinkCustomDomainToCertificateResponses, LinkServiceRequest, LinkServiceToProjectData, LinkServiceToProjectErrors, LinkServiceToProjectResponse, LinkServiceToProjectResponses, ListAgentRunsData, ListAgentRunsErrors, ListAgentRunsResponse, ListAgentRunsResponses, ListAgentsData, ListAgentsErrors, ListAgentsResponse, ListAgentsResponse2, ListAgentsResponses, ListAiProvidersData, ListAiProvidersErrors, ListAiProvidersResponse, ListAiProvidersResponses, ListAlertRulesData, ListAlertRulesErrors, ListAlertRulesResponse, ListAlertRulesResponses, ListAlertsData, ListAlertsError, ListAlertsErrors, ListAlertsResponse, ListAlertsResponses, ListAllConversationsData, ListAllConversationsErrors, ListAllConversationsResponse, ListAllConversationsResponses, ListAllRunsData, ListAllRunsErrors, ListAllRunsResponse, ListAllRunsResponses, ListApiKeysData, ListApiKeysErrors, ListApiKeysQuery, ListApiKeysResponse, ListApiKeysResponses, ListAuditLogsData, ListAuditLogsErrors, ListAuditLogsQuery, ListAuditLogsResponse, ListAuditLogsResponses, ListAvailableContainersData, ListAvailableContainersErrors, ListAvailableContainersResponse, ListAvailableContainersResponses, ListBackupAlertsData, ListBackupAlertsError, ListBackupAlertsErrors, ListBackupAlertsResponse, ListBackupAlertsResponses, ListBackupChildrenData, ListBackupChildrenError, ListBackupChildrenErrors, ListBackupChildrenResponse, ListBackupChildrenResponses, ListBackupSchedulesData, ListBackupSchedulesError, ListBackupSchedulesErrors, ListBackupSchedulesResponse, ListBackupSchedulesResponses, ListBackupsForScheduleData, ListBackupsForScheduleErrors, ListBackupsForScheduleResponse, ListBackupsForScheduleResponses, ListBlobsQuery, ListBlobsResponse, ListCommitsByRepositoryIdData, ListCommitsByRepositoryIdErrors, ListCommitsByRepositoryIdResponse, ListCommitsByRepositoryIdResponses, ListConnectionsData, ListConnectionsErrors, ListConnectionsResponse, ListConnectionsResponses, ListContainersAtPathData, ListContainersAtPathErrors, ListContainersAtPathResponse, ListContainersAtPathResponses, ListContainersData, ListContainersErrors, ListContainersResponse, ListContainersResponses, ListConversationsData, ListConversationsErrors, ListConversationsResponse, ListConversationsResponses, ListCustomDomainsForProjectData, ListCustomDomainsForProjectErrors, ListCustomDomainsForProjectResponse, ListCustomDomainsForProjectResponses, ListCustomDomainsResponse, ListDashboardsData, ListDashboardsError, ListDashboardsErrors, ListDashboardsResponse, ListDashboardsResponses, ListDeliveriesData, ListDeliveriesErrors, ListDeliveriesResponse, ListDeliveriesResponses, ListDeploymentContainerLogsData, ListDeploymentContainerLogsErrors, ListDeploymentContainerLogsResponse, ListDeploymentContainerLogsResponses, ListDeploymentTokensData, ListDeploymentTokensErrors, ListDeploymentTokensQuery, ListDeploymentTokensResponse, ListDeploymentTokensResponses, ListDnsProvidersData, ListDnsProvidersErrors, ListDnsProvidersResponse, ListDnsProvidersResponses, ListDomainsData, ListDomainsErrors, ListDomainsResponse, ListDomainsResponse2, ListDomainsResponses, ListDsnsData, ListDsnsErrors, ListDsnsResponse, ListDsnsResponses, ListEmailDomainsData, ListEmailDomainsErrors, ListEmailDomainsResponse, ListEmailDomainsResponses, ListEmailProvidersData, ListEmailProvidersErrors, ListEmailProvidersResponse, ListEmailProvidersResponses, ListEmailsData, ListEmailsErrors, ListEmailsResponse, ListEmailsResponses, ListEnrollmentTokensData, ListEnrollmentTokensErrors, ListEnrollmentTokensResponse, ListEnrollmentTokensResponses, ListEntitiesData, ListEntitiesErrors, ListEntitiesQuery, ListEntitiesResponse, ListEntitiesResponses, ListErrorEventsData, ListErrorEventsErrors, ListErrorEventsQuery, ListErrorEventsResponse, ListErrorEventsResponses, ListErrorGroupsData, ListErrorGroupsErrors, ListErrorGroupsQuery, ListErrorGroupsResponse, ListErrorGroupsResponses, ListEventsData, ListEventsResponse, ListEventsResponses, ListEventTypesData, ListEventTypesResponse, ListEventTypesResponses, ListExternalImagesData, ListExternalImagesErrors, ListExternalImagesResponse, ListExternalImagesResponses, ListExternalPluginsData, ListExternalPluginsErrors, ListExternalPluginsResponse, ListExternalPluginsResponses, ListExternalServiceBackupsData, ListExternalServiceBackupsError, ListExternalServiceBackupsErrors, ListExternalServiceBackupsResponse, ListExternalServiceBackupsResponses, ListFlagsData, ListFlagsErrors, ListFlagsResponse, ListFlagsResponses, ListFunnelsData, ListFunnelsErrors, ListFunnelsResponse, ListFunnelsResponses, ListGitProvidersData, ListGitProvidersErrors, ListGitProvidersResponse, ListGitProvidersResponses, ListGlobalMcpsData, ListGlobalMcpsErrors, ListGlobalMcpsResponse, ListGlobalMcpsResponses, ListGlobalSkillsData, ListGlobalSkillsErrors, ListGlobalSkillsResponse, ListGlobalSkillsResponses, ListIncidentsData, ListIncidentsErrors, ListIncidentsResponses, ListInsightsData, ListInsightsError, ListInsightsErrors, ListInsightsResponse, ListInsightsResponses, ListIpAccessControlData, ListIpAccessControlError, ListIpAccessControlErrors, ListIpAccessControlResponse, ListIpAccessControlResponses, ListJobsData, ListJobsErrors, ListJobsResponse, ListJobsResponse2, ListJobsResponses, ListKnownAiAgentsData, ListKnownAiAgentsError, ListKnownAiAgentsErrors, ListKnownAiAgentsResponse, ListKnownAiAgentsResponses, ListManagedDomainsData, ListManagedDomainsErrors, ListManagedDomainsResponse, ListManagedDomainsResponses, ListMcpsData, ListMcpsErrors, ListMcpsResponse, ListMcpsResponse2, ListMcpsResponses, ListMetricLabelKeysData, ListMetricLabelKeysError, ListMetricLabelKeysErrors, ListMetricLabelKeysResponse, ListMetricLabelKeysResponses, ListMetricLabelValuesData, ListMetricLabelValuesError, ListMetricLabelValuesErrors, ListMetricLabelValuesResponse, ListMetricLabelValuesResponses, ListMetricNamesData, ListMetricNamesError, ListMetricNamesErrors, ListMetricNamesResponse, ListMetricNamesResponses, ListModelsData, ListModelsError, ListModelsErrors, ListModelsResponse, ListModelsResponses, ListMonitorsData, ListMonitorsErrors, ListMonitorsResponse, ListMonitorsResponses, ListNotificationProvidersData, ListNotificationProvidersErrors, ListNotificationProvidersResponse, ListNotificationProvidersResponses, ListOidcProvidersData, ListOidcProvidersResponse, ListOidcProvidersResponses, ListOidcProviderUsersData, ListOidcProviderUsersErrors, ListOidcProviderUsersResponse, ListOidcProviderUsersResponses, ListOidcRoleMappingsData, ListOidcRoleMappingsResponse, ListOidcRoleMappingsResponses, ListOnDemandCertsData, ListOnDemandCertsErrors, ListOnDemandCertsResponse, ListOnDemandCertsResponse2, ListOnDemandCertsResponses, ListOrdersData, ListOrdersErrors, ListOrdersResponse, ListOrdersResponse2, ListOrdersResponses, ListPeersData, ListPeersErrors, ListPeersResponse, ListPeersResponses, ListPendingActionsData, ListPendingActionsErrors, ListPendingActionsResponse, ListPendingActionsResponses, ListPgUpgradesData, ListPgUpgradesErrors, ListPgUpgradesResponse, ListPgUpgradesResponses, ListPresetsData, ListPresetsErrors, ListPresetsResponse, ListPresetsResponse2, ListPresetsResponses, ListProjectAccessData, ListProjectAccessErrors, ListProjectAccessResponse, ListProjectAccessResponses, ListProjectAlarmsData, ListProjectAlarmsErrors, ListProjectAlarmsResponse, ListProjectAlarmsResponses, ListProjectScansData, ListProjectScansError, ListProjectScansErrors, ListProjectScansResponse, ListProjectScansResponses, ListProjectSecretsData, ListProjectSecretsErrors, ListProjectSecretsResponse, ListProjectSecretsResponses, ListProjectServicesData, ListProjectServicesErrors, ListProjectServicesResponse, ListProjectServicesResponses, ListProjectTemplatesData, ListProjectTemplatesErrors, ListProjectTemplatesResponse, ListProjectTemplatesResponses, ListProjectTemplateTagsData, ListProjectTemplateTagsErrors, ListProjectTemplateTagsResponse, ListProjectTemplateTagsResponses, ListProviderKeysData, ListProviderKeysError, ListProviderKeysErrors, ListProviderKeysResponse, ListProviderKeysResponses, ListProviderZonesData, ListProviderZonesErrors, ListProviderZonesResponse, ListProviderZonesResponses, ListPublicProvidersData, ListPublicProvidersResponse, ListPublicProvidersResponses, ListReleaseFilesData, ListReleaseFilesErrors, ListReleaseFilesResponse, ListReleaseFilesResponses, ListReleasesData, ListReleasesErrors, ListReleasesResponse, ListReleasesResponses, ListRemoteExternalImagesData, ListRemoteExternalImagesErrors, ListRemoteExternalImagesResponse, ListRemoteExternalImagesResponses, ListRepositoriesByConnectionData, ListRepositoriesByConnectionErrors, ListRepositoriesByConnectionResponse, ListRepositoriesByConnectionResponses, ListRepositoriesByProviderData, ListRepositoriesByProviderErrors, ListRepositoriesByProviderResponse, ListRepositoriesByProviderResponses, ListRestoreRunsForServiceData, ListRestoreRunsForServiceResponse, ListRestoreRunsForServiceResponses, ListRootContainersData, ListRootContainersErrors, ListRootContainersResponse, ListRootContainersResponses, ListRoutesData, ListRoutesErrors, ListRoutesResponse, ListRoutesResponses, ListRunsResponse, ListS3SourcesData, ListS3SourcesError, ListS3SourcesErrors, ListS3SourcesResponse, ListS3SourcesResponses, ListSandboxesData, ListSandboxesResponse, ListSandboxesResponse2, ListSandboxesResponses, ListScansQuery, ListScheduleRunJobsData, ListScheduleRunJobsError, ListScheduleRunJobsErrors, ListScheduleRunJobsResponse, ListScheduleRunJobsResponses, ListScheduleRunsData, ListScheduleRunsError, ListScheduleRunsErrors, ListScheduleRunsResponse, ListScheduleRunsResponses, ListScheduleServicesData, ListScheduleServicesError, ListScheduleServicesErrors, ListScheduleServicesResponse, ListScheduleServicesResponses, ListSecretsData, ListSecretsErrors, ListSecretsResponse, ListSecretsResponse2, ListSecretsResponses, ListServiceHealthStatusesData, ListServiceHealthStatusesErrors, ListServiceHealthStatusesResponse, ListServiceHealthStatusesResponses, ListServiceProjectsData, ListServiceProjectsErrors, ListServiceProjectsResponse, ListServiceProjectsResponses, ListServiceSchedulesData, ListServiceSchedulesError, ListServiceSchedulesErrors, ListServiceSchedulesResponse, ListServiceSchedulesResponses, ListServicesData, ListServicesErrors, ListServicesResponse, ListServicesResponses, ListSkillsData, ListSkillsErrors, ListSkillsResponse, ListSkillsResponse2, ListSkillsResponses, ListSourceBackupsData, ListSourceBackupsError, ListSourceBackupsErrors, ListSourceBackupsResponse, ListSourceBackupsResponses, ListSourceFilesData, ListSourceFilesErrors, ListSourceFilesResponse, ListSourceFilesResponses, ListSourceMapsData, ListSourceMapsErrors, ListSourceMapsResponse, ListSourceMapsResponses, ListSourcesData, ListSourcesErrors, ListSourcesResponse, ListSourcesResponses, ListStaticBundlesData, ListStaticBundlesErrors, ListStaticBundlesResponse, ListStaticBundlesResponses, ListSyncedRepositoriesData, ListSyncedRepositoriesErrors, ListSyncedRepositoriesResponse, ListSyncedRepositoriesResponses, ListTagsResponse, ListTeamMembersData, ListTeamMembersErrors, ListTeamMembersResponse, ListTeamMembersResponses, ListTeamProjectsData, ListTeamProjectsErrors, ListTeamProjectsResponse, ListTeamProjectsResponses, ListTeamsData, ListTeamsErrors, ListTeamsResponse, ListTeamsResponses, ListTemplatesQuery, ListTemplatesResponse, ListUsersData, ListUsersErrors, ListUsersResponse, ListUsersResponses, ListVulnerabilitiesQuery, ListWebhooksData, ListWebhooksErrors, ListWebhooksResponse, ListWebhooksResponses, LiveVisitorInfo, LiveVisitorsListResponse, LocationCount, LocationGranularity, LocationInfo, LoginData, LoginErrors, LoginRequest, LoginResponse, LoginResponses, LogLevel, LogoutData, LogoutErrors, LogoutResponses, LogRecord, LogSearchLine, LogSeverity, LogSource, LogsQuery, LogsResponse, LogStream, LookupDnsARecordsData, LookupDnsARecordsError, LookupDnsARecordsErrors, LookupDnsARecordsResponse, LookupDnsARecordsResponses, ManagedDomainResponse, ManualAction, ManualActionTiming, McpDefinitionResponse, MessageContent, MessagePart, MessageResponse, MeteredMode, MetricAggregation, MetricBucket, MetricDataPoint, MetricsOverTimeResponse, MetricsQuery, MetricsRangeQuery, MetricsStatusResponse, MetricsStoreKind, MetricsSummaryResponse, MetricType, MfaRequiredResponse, MfaSetupResponse, MfaVerificationRequest, MigrationStep, MigrationSummary, MintEnrollmentTokenData, MintEnrollmentTokenErrors, MintEnrollmentTokenRequest, MintEnrollmentTokenResponse, MintEnrollmentTokenResponse2, MintEnrollmentTokenResponses, MiscResult, MkdirBody, MkdirData, MkdirErrors, MkdirResponse, MkdirResponses, ModelInfo, ModelListResponse, ModelPricing, ModelUsage, MonitoringSettings, MonitoringSettingsMasked, MonitorResponse, MonitorStatus, MrrBucketResponse, MultiNodeSettings, MultiNodeSettingsMasked, MxResult, NavEntry, NavSection, NetworkConfiguration, NetworkMode, NixpacksPresetConfig, NixpacksProvider, NodeContainerListResponse, NodeContainerResponse, NodeCostInfo, NodeHeartbeatData, NodeHeartbeatErrors, NodeHeartbeatResponse, NodeHeartbeatResponses, NodeInfoResponse, NodeListResponse, NodeMetricsGetRangeData, NodeMetricsGetRangeErrors, NodeMetricsGetRangeResponse, NodeMetricsGetRangeResponses, NotificationPreferencesResponse, NotificationProviderResponse, ObservabilityCompressionSettings, ObservabilityEvent, ObservabilityFullEventData, ObservabilityFullEventError, ObservabilityFullEventErrors, ObservabilityFullEventResponse, ObservabilityFullEventResponses, ObservabilityListEventsData, ObservabilityListEventsError, ObservabilityListEventsErrors, ObservabilityListEventsResponse, ObservabilityListEventsResponses, ObservabilityRetentionSettings, OidcCallbackData, OidcProviderResponse, OidcProvidersListResponse, OidcProviderSummary, OidcProviderUserResponse, OidcRoleMappingResponse, OidcTestConnectionResponse, OnDemandCertAttemptResponse, OnDemandCertRow, OnDemandTlsSettings, OpenAiError, OpenAiErrorResponse, OperatingSystemCount, OperationResultResponse, OperationResultsResponse, OtelDashboardResponse, OtelDashboardsResponse, OtelMetricAlertRuleResponse, OtelMetricAlertsResponse, OtelMetricLabelKeysResponse, OtelMetricLabelValuesResponse, OtelMetricNamesResponse, OtelMetricsResponse, OutlierAlgorithm, OutlierParams, OverprovisioningAssessment, OverprovisioningVerdict, PageActivityBucket, PageCountryStats, PageFlowEntry, PageFlowQuery, PageFlowResponse, PageHourlySessionsQuery, PageHourlySessionsResponse, PagePathDetailQuery, PagePathDetailResponse, PagePathInfo, PagePathSparkline, PagePathSparklinePoint, PagePathsQuery, PagePathsResponse, PagePathsSparklineQuery, PagePathsSparklineResponse, PagePathVisitorsQuery, PagePathVisitorsResponse, PageReferrerStats, PagesComparisonResponse, PageSessionComparison, PageSessionStats, PageSessionStatsQuery, PageTransition, PageVisit, PageVisitorSession, PaginatedEmailsResponse, PaginatedEntitiesResponse, PaginatedErrorEventsResponse, PaginatedErrorGroupsResponse, PaginatedEventsResponse, PaginatedExternalImagesResponse, PaginatedProjectList, PaginatedStaticBundlesResponse, Pagination, PaginationMeta, PaginationParams, PasswordProtectionConfig, PatchAdminGateData, PatchAdminGateErrors, PatchAdminGateResponse, PatchAdminGateResponses, PatchPreviewGatewaySettingsData, PatchPreviewGatewaySettingsResponse, PatchPreviewGatewaySettingsResponses, PatchSettingsRequest, PathVisitors, PathVisitorsAnalyticsQuery, PathVisitorsResponse, PauseDeploymentData, PauseDeploymentErrors, PauseDeploymentResponse, PauseDeploymentResponses, PauseSandboxData, PauseSandboxErrors, PauseSandboxResponse, PauseSandboxResponses, PeerEntry, PeerListResponse, PendingActionResponse, PerformanceMetricsQuery, PerformanceMetricsResponse, PermissionInfo, PgUpgradeLogResponse, PgUpgradeResponse, PipelineStats, PipelineStatsResponse, PlanComplexity, PlanMetadata, PlanRestoreData, PlanRestoreError, PlanRestoreErrors, PlanRestoreResponse, PlanRestoreResponses, PlanSourceBackup, PlanTarget, PlatformInfo, PluginManifest, PortMapping, PostDnsAckData, PostDnsAckErrors, PostDnsAckResponse, PostDnsAckResponses, PostgresWalHealth, PresetConfigSchema, PresetInfo, PresetResponse, PreviewAlertData, PreviewAlertError, PreviewAlertErrors, PreviewAlertResponse, PreviewAlertResponses, PreviewFunnelMetricsData, PreviewFunnelMetricsErrors, PreviewFunnelMetricsResponse, PreviewFunnelMetricsResponses, PreviewGatewaySettings, PreviewGatewaySettingsMasked, PreviewGatewaySettingsResponse, PreviewHostnameModeData, PreviewHostnameModeErrors, PreviewHostnameModeResponse, PreviewHostnameModeResponses, PreviewShareLinkBody, PreviewShareLinkResponse, PricingResponse, ProblemDetails, ProjectAccessResponse, ProjectConfiguration, ProjectDashboardAnalytics, ProjectDsnResponse, ProjectHealthSummary, ProjectInfo, ProjectMonitorHealth, ProjectPresetResponse, ProjectQuery, ProjectRef, ProjectResponse, ProjectSecretEnvironmentInfo, ProjectSecretResponse, ProjectServiceInfo, ProjectsHealthResponse, ProjectsMonitorHealthResponse, ProjectStatisticsResponse, ProjectStatsBreakdown, ProjectType, ProjectUsageInfoResponse, PromoteClusterMemberData, PromoteClusterMemberErrors, PromoteClusterMemberResponses, PromoteDeploymentData, PromoteDeploymentErrors, PromoteDeploymentRequest, PromoteDeploymentResponse, PromoteDeploymentResponses, PropertyBreakdownItem, PropertyBreakdownQuery, PropertyBreakdownResponse, PropertyColumn, PropertyTimelineItem, PropertyTimelineQuery, PropertyTimelineResponse, Protocol, ProviderCatalogDto, ProviderCatalogResponse, ProviderConfig, ProviderConfigMasked, ProviderDeletionCheckResponse, ProviderDescriptor, ProviderKeyResponse, ProviderMetadata, ProviderResponse, ProviderUsage, ProvisionDomainData, ProvisionDomainErrors, ProvisionDomainResponse, ProvisionDomainResponses, ProvisionResponse, ProxyLogResponse, ProxyLogsPaginatedResponse, PublicHostnameStrategy, PublicPresetResponse, PublicRepositoryInfo, PurgeLogsRequest, PurgeProjectLogsData, PurgeProjectLogsError, PurgeProjectLogsErrors, PurgeProjectLogsResponses, PushedExternalImageResponse, PushExternalImageData, PushExternalImageErrors, PushExternalImageResponse, PushExternalImageResponses, PushImageRequest, QueryDataData, QueryDataErrors, QueryDataRequest, QueryDataResponse, QueryDataResponse2, QueryDataResponses, QueryGenaiTracesData, QueryGenaiTracesError, QueryGenaiTracesErrors, QueryGenaiTracesResponse, QueryGenaiTracesResponses, QueryLogsData, QueryLogsError, QueryLogsErrors, QueryLogsResponse, QueryLogsResponses, QueryMetricsData, QueryMetricsError, QueryMetricsErrors, QueryMetricsResponse, QueryMetricsResponses, QueryTracesData, QueryTracesError, QueryTracesErrors, QueryTracesResponse, QueryTracesResponses, QueryTraceSummariesData, QueryTraceSummariesError, QueryTraceSummariesErrors, QueryTraceSummariesResponse, QueryTraceSummariesResponses, QuotaResponse, RateLimitConfig, RateLimitSettings, ReachabilityStatus, ReadEntityRowsData, ReadEntityRowsErrors, ReadEntityRowsResponse, ReadEntityRowsResponses, ReadFileData, ReadFileErrors, ReadFileResponse, ReadFileResponse2, ReadFileResponses, ReadRowsQuery, ReAnalyzeData, ReAnalyzeErrors, ReAnalyzeResponses, RebuildSandboxImageData, RebuildSandboxImageErrors, RebuildSandboxImageResponses, RecentActivityQuery, RecentActivityResponse, RecentEventResponse, RecentQueryParams, RecordConsoleEventData, RecordConsoleEventErrors, RecordConsoleEventResponses, RecordEventMetricsData, RecordEventMetricsErrors, RecordEventMetricsResponse, RecordEventMetricsResponses, RecordExposureRequest, RecordExposureResponse, RecordFlagExposureData, RecordFlagExposureErrors, RecordFlagExposureResponse, RecordFlagExposureResponses, RecordListResponse, RecordSpeedMetricsData, RecordSpeedMetricsError, RecordSpeedMetricsErrors, RecordSpeedMetricsResponse, RecordSpeedMetricsResponses, RecoveryTarget, ReferrerCount, ReferrersAnalyticsQuery, RefreshRouteTableData, RefreshRouteTableErrors, RefreshRouteTableResponse, RefreshRouteTableResponses, RegenerateDsnData, RegenerateDsnErrors, RegenerateDsnRequest, RegenerateDsnResponse, RegenerateDsnResponses, RegisterExternalImageData, RegisterExternalImageErrors, RegisterExternalImageResponse, RegisterExternalImageResponses, RegisterImageRequest, RegisterNodeApiRequest, RegisterNodeData, RegisterNodeErrors, RegisterNodeResponse, RegisterNodeResponse2, RegisterNodeResponses, RegisterRequest, ReinstallGitlabWebhookData, ReinstallGitlabWebhookErrors, ReinstallGitlabWebhookResponse, ReinstallGitlabWebhookResponses, ReinstallWebhookResponse, RejectPendingActionData, RejectPendingActionErrors, RejectPendingActionResponse, RejectPendingActionResponses, ReleaseListResponse, ReloadPluginsData, ReloadPluginsErrors, ReloadPluginsResponse, ReloadPluginsResponses, ReloadResponse, RemoteDeploymentResponse, RemoveClusterMemberData, RemoveClusterMemberErrors, RemoveClusterMemberResponse, RemoveClusterMemberResponses, RemoveManagedDomainData, RemoveManagedDomainErrors, RemoveManagedDomainResponse, RemoveManagedDomainResponses, RemoveNodeResponse, RemoveRoleData, RemoveRoleErrors, RemoveRoleResponse, RemoveRoleResponses, RemoveTeamMemberData, RemoveTeamMemberErrors, RemoveTeamMemberResponse, RemoveTeamMemberResponses, RenameConversationData, RenameConversationErrors, RenameConversationRequest, RenameConversationResponse, RenameConversationResponses, RenewDomainData, RenewDomainErrors, RenewDomainResponse, RenewDomainResponses, RepositoryListQuery, RepositoryListResponse, RepositoryPresetResponse, RepositoryResponse, RepositorySyncStartedResponse, RequestPasswordResetData, RequestPasswordResetErrors, RequestPasswordResetResponse, RequestPasswordResetResponses, RequestRow, ResetPasswordData, ResetPasswordErrors, ResetPasswordRequest, ResetPasswordResponse, ResetPasswordResponses, ResetPgStatStatementsRequest, ResetPgStatStatementsResponse, ResizeSandboxBody, ResizeSandboxData, ResizeSandboxErrors, ResizeSandboxResponse, ResizeSandboxResponses, ResolveAlarmData, ResolveAlarmErrors, ResolveAlarmResponses, ResolvedEnvVarResponse, ResolvedEnvVarSource, ResourceCounts, ResourceFootprint, ResourceInfo, ResourceLimitApplyResult, ResourceLimits, ResourceLimitsResponse, ResourceLimitsUpdateResponse, ResourcesBody, RestartContainerData, RestartContainerErrors, RestartContainerResponse, RestartContainerResponses, RestartPreviewGatewayData, RestartPreviewGatewayResponse, RestartPreviewGatewayResponses, RestartSandboxData, RestartSandboxErrors, RestartSandboxResponse, RestartSandboxResponses, RestoreCapabilities, RestoreCapabilitiesResponse, RestoreFlagData, RestoreFlagErrors, RestoreFlagResponse, RestoreFlagResponses, RestorePlan, RestoreRequestMode, RestoreRunView, RestoreUserData, RestoreUserErrors, RestoreUserResponse, RestoreUserResponses, ResumeDeploymentData, ResumeDeploymentErrors, ResumeDeploymentResponse, ResumeDeploymentResponses, ResumeSandboxData, ResumeSandboxErrors, ResumeSandboxResponse, ResumeSandboxResponses, RetentionCleanupFailure, RetentionCleanupReport, RetryClusterData, RetryClusterErrors, RetryClusterRequest, RetryClusterResponse, RetryClusterResponses, RetryDeliveryData, RetryDeliveryErrors, RetryDeliveryResponse, RetryDeliveryResponses, RetryPgUpgradeData, RetryPgUpgradeErrors, RetryPgUpgradeResponse, RetryPgUpgradeResponses, RetryRunData, RetryRunErrors, RetryRunResponse, RetryRunResponses, RevealGlobalMcpConfigData, RevealGlobalMcpConfigErrors, RevealGlobalMcpConfigResponse, RevealGlobalMcpConfigResponses, RevealMcpConfigData, RevealMcpConfigErrors, RevealMcpConfigResponse, RevealMcpConfigResponses, RevealNotificationProviderConfigData, RevealNotificationProviderConfigErrors, RevealNotificationProviderConfigResponse, RevealNotificationProviderConfigResponses, RevealServiceParameterData, RevealServiceParameterErrors, RevealServiceParameterResponse, RevealServiceParameterResponses, RevenueCreateIntegrationData, RevenueCreateIntegrationErrors, RevenueCreateIntegrationResponse, RevenueCreateIntegrationResponses, RevenueDeleteIntegrationData, RevenueDeleteIntegrationResponse, RevenueDeleteIntegrationResponses, RevenueGlobalEventsData, RevenueGlobalEventsResponse, RevenueGlobalEventsResponses, RevenueImportInvoicesCsvData, RevenueImportInvoicesCsvErrors, RevenueImportInvoicesCsvResponse, RevenueImportInvoicesCsvResponses, RevenueImportSubscriptionsCsvData, RevenueImportSubscriptionsCsvErrors, RevenueImportSubscriptionsCsvResponse, RevenueImportSubscriptionsCsvResponses, RevenueListIntegrationsData, RevenueListIntegrationsResponse, RevenueListIntegrationsResponses, RevenueListProvidersData, RevenueListProvidersResponse, RevenueListProvidersResponses, RevenueMetricsCustomersData, RevenueMetricsCustomersResponse, RevenueMetricsCustomersResponses, RevenueMetricsGlobalMrrData, RevenueMetricsGlobalMrrResponse, RevenueMetricsGlobalMrrResponses, RevenueMetricsGlobalSummaryData, RevenueMetricsGlobalSummaryResponse, RevenueMetricsGlobalSummaryResponses, RevenueMetricsMrrData, RevenueMetricsMrrResponse, RevenueMetricsMrrResponses, RevenueMetricsSummaryData, RevenueMetricsSummaryResponse, RevenueMetricsSummaryResponses, RevenueRecentEventsData, RevenueRecentEventsResponse, RevenueRecentEventsResponses, RevenueRotateTokenData, RevenueRotateTokenResponse, RevenueRotateTokenResponses, RevenueRow, RevenueUpdateConfigData, RevenueUpdateConfigErrors, RevenueUpdateConfigResponse, RevenueUpdateConfigResponses, RevenueUpdateSecretData, RevenueUpdateSecretErrors, RevenueUpdateSecretResponse, RevenueUpdateSecretResponses, RevokeDsnData, RevokeDsnErrors, RevokeDsnResponse, RevokeDsnResponses, RevokeEnrollmentTokenData, RevokeEnrollmentTokenErrors, RevokeEnrollmentTokenResponse, RevokeEnrollmentTokenResponses, RevokeJoinTokenData, RevokeJoinTokenErrors, RevokeJoinTokenResponse, RevokeJoinTokenResponses, RevokeProjectAccessData, RevokeProjectAccessErrors, RevokeProjectAccessResponse, RevokeProjectAccessResponses, RiskLevel, RoleInfo, RollbackPgUpgradeData, RollbackPgUpgradeErrors, RollbackPgUpgradeResponse, RollbackPgUpgradeResponses, RollbackToDeploymentData, RollbackToDeploymentErrors, RollbackToDeploymentResponse, RollbackToDeploymentResponses, RootfsCacheEntry, RootfsGcData, RootfsGcReport, RootfsGcResponses, RootfsReport, RootfsReportData, RootfsReportResponses, RootfsVmEntry, RotateApiKeyData, RotateApiKeyErrors, RotateApiKeyResponse, RotateApiKeyResponses, RotateDeploymentTokenData, RotateDeploymentTokenErrors, RotateDeploymentTokenResponse, RotateDeploymentTokenResponses, RouteRefreshResponse, RouteResponse, RouteRole, RouteUser, RouteUserWithRoles, RunBackupForSourceData, RunBackupForSourceError, RunBackupForSourceErrors, RunBackupForSourceResponse, RunBackupForSourceResponses, RunBackupRequest, RunConnectionHealthCheckData, RunConnectionHealthCheckErrors, RunConnectionHealthCheckResponse, RunConnectionHealthCheckResponses, RunExternalServiceBackupData, RunExternalServiceBackupError, RunExternalServiceBackupErrors, RunExternalServiceBackupRequest, RunExternalServiceBackupResponse, RunExternalServiceBackupResponses, RunScheduleNowData, RunScheduleNowError, RunScheduleNowErrors, RunScheduleNowResponse, RunScheduleNowResponses, S3ConnectionTestResponse, S3CredentialsResponse, S3SourceResponse, S3SourceResponseWritable, SandboxCreatePreviewLinkData, SandboxCreatePreviewLinkErrors, SandboxCreatePreviewLinkResponse, SandboxCreatePreviewLinkResponses, SandboxDomainResponse, SandboxEvent, SandboxEventsResponse, SandboxInner, SandboxResponse, SandboxRoute, SandboxStatusResponse, SaveAgentTokenData, SaveAgentTokenErrors, SaveAgentTokenRequest, SaveAgentTokenResponse, SaveAgentTokenResponse2, SaveAgentTokenResponses, SaveAiProviderCredentialData, SaveAiProviderCredentialErrors, SaveAiProviderCredentialResponse, SaveAiProviderCredentialResponses, SaveCredentialRequest, SaveCredentialResponse, ScalewayCredentialsRequest, ScanResponse, ScheduleRunEntry, ScheduleRunJobEntry, ScheduleRunListResponse, ScheduleRunResponse, ScheduleRunSummary, ScheduleRunSummaryList, ScreenshotSettings, SearchLogsData, SearchLogsError, SearchLogsErrors, SearchLogsRequest, SearchLogsResponse, SearchLogsResponse2, SearchLogsResponses, SearchMode, Seasonality, SecretResponse, SecurityConfig, SecurityHeadersConfig, SecurityHeadersSettings, SendEmailData, SendEmailErrors, SendEmailRequestBody, SendEmailResponse, SendEmailResponseBody, SendEmailResponses, SendMessageData, SendMessageErrors, SendMessageRequest, SendMessageResponses, SensitiveConfigValueResponse, SensitiveMcpConfigValueResponse, SensitiveValueResponse, SentryChunkUploadResponse, SentryCreateReleaseRequest, SentryEventRequest, SentryEventResponse, SentryReleaseFileResponse, SentryReleaseProjectRef, SentryReleaseResponse, SeriesStateEntry, ServiceAccessInfo, ServiceAction, ServiceAlertRuleResponse, ServiceBackupEntryResponse, ServiceBackupListResponse, ServiceCreateAlertRuleRequest, ServiceHealthResponse, ServiceHealthStatusBatchResponse, ServiceHealthStatusEntryResponse, ServiceMemberInfo, ServiceParameter, ServicePlan, ServiceResourceLimits, ServiceRuntimeReport, ServiceStatsReport, ServiceTypeInfo, ServiceTypeRoute, ServiceUpdateAlertRuleRequest, SesCredentialsRequest, SessionDetails, SessionDetailsQuery, SessionEvent, SessionEventDto, SessionEventsQuery, SessionEventsResponse, SessionLogsQuery, SessionLogsResponse, SessionReplayEventsRequest, SessionReplayInfoDto, SessionReplayInitRequest, SessionReplayInitResponse, SessionReplayWithEventsDto, SessionReplayWithVisitorDto, SessionRequestLog, SessionSummary, SetAiDataAccessData, SetAiDataAccessErrors, SetAiDataAccessResponse, SetAiDataAccessResponses, SetDefaultS3SourceData, SetDefaultS3SourceError, SetDefaultS3SourceErrors, SetDefaultS3SourceResponse, SetDefaultS3SourceResponses, SetFlagEnvironmentData, SetFlagEnvironmentErrors, SetFlagEnvironmentRequest, SetFlagEnvironmentResponse, SetFlagEnvironmentResponses, SetPreviewPasswordBody, SetPreviewPasswordData, SetPreviewPasswordErrors, SetPreviewPasswordResponse, SetPreviewPasswordResponse2, SetPreviewPasswordResponses, SetRequest, SetResponse, SettingsUpdateResponse, SetupDnsChallengeData, SetupDnsChallengeErrors, SetupDnsChallengeRequest, SetupDnsChallengeResponse, SetupDnsChallengeResponse2, SetupDnsChallengeResponses, SetupDnsData, SetupDnsErrors, SetupDnsRequest, SetupDnsResponse, SetupDnsResponse2, SetupDnsResponses, SetupEmailTrackingData, SetupEmailTrackingErrors, SetupEmailTrackingResponse, SetupEmailTrackingResponses, SetupMfaData, SetupMfaErrors, SetupMfaResponse, SetupMfaResponses, SiblingRef, SkillDefinitionResponse, SlackConfig, SleepEnvironmentData, SleepEnvironmentErrors, SleepEnvironmentResponse, SleepEnvironmentResponses, SlowQueriesResponse, SlowQueryRow, SmartFilter, SmokeTestAgentData, SmokeTestAgentErrors, SmokeTestAgentResponse, SmokeTestAgentResponses, SmokeTestResponse, SmtpCredentialsRequest, SmtpEncryptionRoute, SmtpResult, SourceArchiveUpload, SourceBackupEntry, SourceBackupIndexResponse, SourceBody, SourceFileListResponse, SourceFileResponse, SourceMapListResponse, SourceMapResponse, SourceSandboxData, SourceSandboxErrors, SourceSandboxResponse, SourceSandboxResponses, SourceType, SpanEvent, SpanKind, SpanRecord, SpanRow, SpanStatusCode, SpeedMetricsPayload, SpeedSegmentFilters, StaleSlot, StartAnalysisData, StartAnalysisErrors, StartAnalysisRequest, StartAnalysisResponse, StartAnalysisResponses, StartContainerData, StartContainerErrors, StartContainerResponse, StartContainerResponses, StartFixData, StartFixErrors, StartFixResponses, StartGitProviderOauthData, StartGitProviderOauthErrors, StartOidcLoginBySlugData, StartOidcLoginBySlugErrors, StartPgUpgradeData, StartPgUpgradeErrors, StartPgUpgradeRequest, StartPgUpgradeResponse, StartPgUpgradeResponses, StartRestoreData, StartRestoreError, StartRestoreErrors, StartRestoreRequest, StartRestoreResponse, StartRestoreResponses, StartServiceData, StartServiceErrors, StartServiceResponse, StartServiceResponses, StaticBundleResponse, StaticParams, StaticPresetConfig, StatPathData, StatPathErrors, StatPathResponse, StatPathResponses, StatResponse, StatsFilters, StatusBucket, StatusBucketedResponse, StatusCodeCount, StatusCodesQuery, StatusPageOverview, StepConversionResponse, StepResourceType, StepResult, StepUpResponse, StopContainerData, StopContainerErrors, StopContainerResponse, StopContainerResponses, StopSandboxData, StopSandboxErrors, StopSandboxResponse, StopSandboxResponses, StopSequence, StopServiceData, StopServiceErrors, StopServiceResponse, StopServiceResponses, StorageQuota, StreamContainerMetricsData, StreamContainerMetricsErrors, StreamContainerMetricsResponses, StreamEventsData, StreamEventsErrors, StreamEventsResponses, StreamRunEventsData, StreamRunEventsErrors, StreamRunEventsResponses, StripeConfig, SyncedRepositoryListQuery, SyncRepositoriesData, SyncRepositoriesErrors, SyncRepositoriesResponse, SyncRepositoriesResponses, SyntaxResult, TagInfo, TagListResponse, TailDeploymentJobLogsData, TailDeploymentJobLogsErrors, TailLogsData, TailLogsError, TailLogsErrors, TailLogsRequest, TailLogsResponses, TargetRecommendation, TeamListResponse, TeamMemberResponse, TeamResponse, TeamRole, TeardownDeploymentData, TeardownDeploymentErrors, TeardownDeploymentResponse, TeardownDeploymentResponses, TeardownEnvironmentData, TeardownEnvironmentErrors, TeardownEnvironmentResponse, TeardownEnvironmentResponses, TemplateResponse, TestEmailRequest, TestEmailResponse, TestNotificationProviderData, TestNotificationProviderErrors, TestNotificationProviderResponse, TestNotificationProviderResponses, TestOidcProviderData, TestOidcProviderResponse, TestOidcProviderResponses, TestProviderConnectionData, TestProviderConnectionErrors, TestProviderConnectionResponse, TestProviderConnectionResponses, TestProviderData, TestProviderErrors, TestProviderKeyByIdData, TestProviderKeyByIdError, TestProviderKeyByIdErrors, TestProviderKeyByIdResponse, TestProviderKeyByIdResponses, TestProviderKeyInlineData, TestProviderKeyInlineError, TestProviderKeyInlineErrors, TestProviderKeyInlineResponse, TestProviderKeyInlineResponses, TestProviderKeyRequest, TestProviderKeyResponse, TestProviderResponse, TestProviderResponse2, TestProviderResponses, TestS3ConnectionPreviewData, TestS3ConnectionPreviewError, TestS3ConnectionPreviewErrors, TestS3ConnectionPreviewResponse, TestS3ConnectionPreviewResponses, TestS3SourceConnectionData, TestS3SourceConnectionError, TestS3SourceConnectionErrors, TestS3SourceConnectionResponse, TestS3SourceConnectionResponses, TimeBucketStats, TimeBucketStatsResponse, TimeseriesBucket, TimeseriesQueryParams, TlsMode, TodayStatsResponse, ToggleAiDataAccessRequest, ToggleDeploymentMetricsRequest, ToggleServiceMetricsRequest, TokenRenewalRequest, ToolCallEvent, ToolInfo, ToolResultEvent, TopModelsQueryParams, TraceProjectRef, TracesResponse, TraceSummariesResponse, TraceSummary, TrackClickData, TrackClickErrors, TrackedLinkResponse, TrackingEventResponse, TrackOpenData, TrackOpenErrors, TrackOpenResponses, TriggerAgentData, TriggerAgentErrors, TriggerAgentRequest, TriggerAgentResponse, TriggerAgentResponses, TriggerDigestResponse, TriggerPipelinePayload, TriggerPipelineResponse, TriggerProjectPipelineData, TriggerProjectPipelineErrors, TriggerProjectPipelineResponse, TriggerProjectPipelineResponses, TriggerScanData, TriggerScanError, TriggerScanErrors, TriggerScanRequest, TriggerScanResponse, TriggerScanResponse2, TriggerScanResponses, TriggerServiceHealthCheckData, TriggerServiceHealthCheckErrors, TriggerServiceHealthCheckResponse, TriggerServiceHealthCheckResponses, TriggerWeeklyDigestData, TriggerWeeklyDigestErrors, TriggerWeeklyDigestResponse, TriggerWeeklyDigestResponses, TtlRequest, TtlResponse, TxtRecord, UiManifest, UiRoute, UndrainNodeResponse, UnifiedTrace, UniqueCountsQuery, UniqueCountsResponse, UnlinkServiceFromProjectData, UnlinkServiceFromProjectErrors, UnlinkServiceFromProjectResponse, UnlinkServiceFromProjectResponses, UnsupportedFeature, UpdateAdminGateRequest, UpdateAgentData, UpdateAgentErrors, UpdateAgentResponse, UpdateAgentResponses, UpdateAiProviderData, UpdateAiProviderErrors, UpdateAiProviderRequest, UpdateAiProviderResponse, UpdateAiProviderResponse2, UpdateAiProviderResponses, UpdateAlertData, UpdateAlertError, UpdateAlertErrors, UpdateAlertResponse, UpdateAlertResponses, UpdateAlertRuleData, UpdateAlertRuleErrors, UpdateAlertRuleRequest, UpdateAlertRuleResponse, UpdateAlertRuleResponses, UpdateApiKeyData, UpdateApiKeyErrors, UpdateApiKeyRequest, UpdateApiKeyResponse, UpdateApiKeyResponses, UpdateAutomaticDeployData, UpdateAutomaticDeployErrors, UpdateAutomaticDeployRequest, UpdateAutomaticDeployResponse, UpdateAutomaticDeployResponses, UpdateBackupScheduleData, UpdateBackupScheduleError, UpdateBackupScheduleErrors, UpdateBackupScheduleRequest, UpdateBackupScheduleResponse, UpdateBackupScheduleResponses, UpdateBlobRequest, UpdateBlobResponse, UpdateCloudflareProviderData, UpdateCloudflareProviderErrors, UpdateCloudflareProviderRequest, UpdateCloudflareProviderResponse, UpdateCloudflareProviderResponses, UpdateConfigBody, UpdateConnectionTokenData, UpdateConnectionTokenErrors, UpdateConnectionTokenResponse, UpdateConnectionTokenResponses, UpdateCustomDomainData, UpdateCustomDomainErrors, UpdateCustomDomainRequest, UpdateCustomDomainResponse, UpdateCustomDomainResponses, UpdateDashboardData, UpdateDashboardError, UpdateDashboardErrors, UpdateDashboardRequest, UpdateDashboardResponse, UpdateDashboardResponses, UpdateDeploymentConfigRequest, UpdateDeploymentTokenData, UpdateDeploymentTokenErrors, UpdateDeploymentTokenRequest, UpdateDeploymentTokenResponse, UpdateDeploymentTokenResponses, UpdateDnsProviderRequest, UpdateEmailProviderData, UpdateEmailProviderErrors, UpdateEmailProviderRequest, UpdateEmailProviderResponse, UpdateEmailProviderResponses, UpdateEnvironmentSettingsData, UpdateEnvironmentSettingsErrors, UpdateEnvironmentSettingsRequest, UpdateEnvironmentSettingsResponse, UpdateEnvironmentSettingsResponses, UpdateEnvironmentSubdomainData, UpdateEnvironmentSubdomainErrors, UpdateEnvironmentSubdomainRequest, UpdateEnvironmentSubdomainResponse, UpdateEnvironmentSubdomainResponses, UpdateEnvironmentVariableData, UpdateEnvironmentVariableErrors, UpdateEnvironmentVariableRequest, UpdateEnvironmentVariableResponse, UpdateEnvironmentVariableResponses, UpdateErrorGroupData, UpdateErrorGroupErrors, UpdateErrorGroupRequest, UpdateErrorGroupResponses, UpdateExternalServiceRequest, UpdateFlagData, UpdateFlagErrors, UpdateFlagRequest, UpdateFlagResponse, UpdateFlagResponses, UpdateFunnelData, UpdateFunnelErrors, UpdateFunnelResponses, UpdateGitProviderCredentialsData, UpdateGitProviderCredentialsErrors, UpdateGitProviderCredentialsResponse, UpdateGitProviderCredentialsResponses, UpdateGitSettingsData, UpdateGitSettingsErrors, UpdateGitSettingsRequest, UpdateGitSettingsResponse, UpdateGitSettingsResponses, UpdateGlobalMcpData, UpdateGlobalMcpErrors, UpdateGlobalMcpResponse, UpdateGlobalMcpResponses, UpdateGlobalSkillData, UpdateGlobalSkillErrors, UpdateGlobalSkillResponse, UpdateGlobalSkillResponses, UpdateIncidentStatusData, UpdateIncidentStatusErrors, UpdateIncidentStatusRequest, UpdateIncidentStatusResponse, UpdateIncidentStatusResponses, UpdateIpAccessControlData, UpdateIpAccessControlError, UpdateIpAccessControlErrors, UpdateIpAccessControlRequest, UpdateIpAccessControlResponse, UpdateIpAccessControlResponses, UpdateKvRequest, UpdateKvResponse, UpdateManagedDomainApiRequest, UpdateManagedDomainData, UpdateManagedDomainErrors, UpdateManagedDomainResponse, UpdateManagedDomainResponses, UpdateMcpData, UpdateMcpErrors, UpdateMcpRequest, UpdateMcpResponse, UpdateMcpResponses, UpdateMemberRoleRequest, UpdateMetricAlertRequest, UpdateNotificationEmailProviderData, UpdateNotificationEmailProviderErrors, UpdateNotificationEmailProviderRequest, UpdateNotificationEmailProviderResponse, UpdateNotificationEmailProviderResponses, UpdateNotificationProviderData, UpdateNotificationProviderErrors, UpdateNotificationProviderResponse, UpdateNotificationProviderResponses, UpdateOidcProviderData, UpdateOidcProviderRequest, UpdateOidcProviderResponse, UpdateOidcProviderResponses, UpdatePreferencesData, UpdatePreferencesErrors, UpdatePreferencesRequest, UpdatePreferencesResponse, UpdatePreferencesResponses, UpdateProjectData, UpdateProjectDeploymentConfigData, UpdateProjectDeploymentConfigErrors, UpdateProjectDeploymentConfigResponse, UpdateProjectDeploymentConfigResponses, UpdateProjectErrors, UpdateProjectResponse, UpdateProjectResponses, UpdateProjectSecretData, UpdateProjectSecretErrors, UpdateProjectSecretRequest, UpdateProjectSecretResponse, UpdateProjectSecretResponses, UpdateProjectSettingsData, UpdateProjectSettingsErrors, UpdateProjectSettingsRequest, UpdateProjectSettingsResponse, UpdateProjectSettingsResponses, UpdateProviderCredentialsRequest, UpdateProviderData, UpdateProviderErrors, UpdateProviderKeyData, UpdateProviderKeyError, UpdateProviderKeyErrors, UpdateProviderKeyRequest, UpdateProviderKeyResponse, UpdateProviderKeyResponses, UpdateProviderRequest, UpdateProviderResponse, UpdateProviderResponses, UpdateRouteData, UpdateRouteErrors, UpdateRouteRequest, UpdateRouteResponse, UpdateRouteResponses, UpdateS3SourceData, UpdateS3SourceError, UpdateS3SourceErrors, UpdateS3SourceRequest, UpdateS3SourceResponse, UpdateS3SourceResponses, UpdateSecretBody, UpdateSelfData, UpdateSelfErrors, UpdateSelfRequest, UpdateSelfResponse, UpdateSelfResponses, UpdateServiceData, UpdateServiceErrors, UpdateServiceResourcesData, UpdateServiceResourcesErrors, UpdateServiceResourcesResponse, UpdateServiceResourcesResponses, UpdateServiceResponse, UpdateServiceResponses, UpdateSessionDurationData, UpdateSessionDurationError, UpdateSessionDurationErrors, UpdateSessionDurationRequest, UpdateSessionDurationResponse, UpdateSessionDurationResponse2, UpdateSessionDurationResponses, UpdateSettingsData, UpdateSettingsErrors, UpdateSettingsResponse, UpdateSettingsResponses, UpdateSkillData, UpdateSkillErrors, UpdateSkillRequest, UpdateSkillResponse, UpdateSkillResponses, UpdateSlackProviderData, UpdateSlackProviderErrors, UpdateSlackProviderRequest, UpdateSlackProviderResponse, UpdateSlackProviderResponses, UpdateSpeedMetricsData, UpdateSpeedMetricsError, UpdateSpeedMetricsErrors, UpdateSpeedMetricsPayload, UpdateSpeedMetricsResponse, UpdateSpeedMetricsResponses, UpdateStatusResponse, UpdateTeamData, UpdateTeamErrors, UpdateTeamMemberRoleData, UpdateTeamMemberRoleErrors, UpdateTeamMemberRoleResponse, UpdateTeamMemberRoleResponses, UpdateTeamRequest, UpdateTeamResponse, UpdateTeamResponses, UpdateTokenRequest, UpdateTokenResponse, UpdateUserData, UpdateUserErrors, UpdateUserRequest, UpdateUserResponse, UpdateUserResponses, UpdateWebhookData, UpdateWebhookErrors, UpdateWebhookProviderData, UpdateWebhookProviderErrors, UpdateWebhookProviderRequest, UpdateWebhookProviderResponse, UpdateWebhookProviderResponses, UpdateWebhookRequestBody, UpdateWebhookResponse, UpdateWebhookResponses, UpgradeExternalServiceRequest, UpgradePreviewGatewayData, UpgradePreviewGatewayResponse, UpgradePreviewGatewayResponses, UpgradeRequest, UpgradeServiceData, UpgradeServiceErrors, UpgradeServiceResponse, UpgradeServiceResponses, UploadGlobalSkillData, UploadGlobalSkillErrors, UploadGlobalSkillResponse, UploadGlobalSkillResponses, UploadReleaseFileData, UploadReleaseFileErrors, UploadReleaseFileResponse, UploadReleaseFileResponses, UploadSkillData, UploadSkillErrors, UploadSkillResponse, UploadSkillResponses, UploadSourceFileData, UploadSourceFileErrors, UploadSourceFileResponse, UploadSourceFileResponses, UploadSourceMapData, UploadSourceMapErrors, UploadSourceMapResponse, UploadSourceMapResponses, UploadStaticBundleData, UploadStaticBundleErrors, UploadStaticBundleResponse, UploadStaticBundleResponses, UpsertAgentRequest, UpsertSecretData, UpsertSecretErrors, UpsertSecretRequest, UpsertSecretResponse, UpsertSecretResponses, UptimeDataPoint, UptimeHistoryResponse, UsageFilter, UsageInfo, UsageLogEntry, UsageLogPage, UsageQueryParams, UsageSource, UsageSummary, UserResponse, ValidateConnectionData, ValidateConnectionErrors, ValidateConnectionResponse, ValidateConnectionResponses, ValidateEmailData, ValidateEmailErrors, ValidateEmailRequest, ValidateEmailResponse, ValidateEmailResponse2, ValidateEmailResponses, ValidationLevel, ValidationReport, ValidationResponse, ValidationResult, ValidationStatus, ValidationSummary, VerifyAndEnableMfaData, VerifyAndEnableMfaErrors, VerifyAndEnableMfaResponse, VerifyAndEnableMfaResponses, VerifyDomainData, VerifyDomainErrors, VerifyDomainResponse, VerifyDomainResponses, VerifyEmailData, VerifyEmailErrors, VerifyEmailResponse, VerifyEmailResponses, VerifyManagedDomainData, VerifyManagedDomainErrors, VerifyManagedDomainResponse, VerifyManagedDomainResponses, VerifyMfaChallengeData, VerifyMfaChallengeErrors, VerifyMfaChallengeResponse, VerifyMfaChallengeResponses, VerifyMfaRequest, VerifyStepUpData, VerifyStepUpErrors, VerifyStepUpRequest, VerifyStepUpResponse, VerifyStepUpResponses, ViewItem, ViewsOverTime, ViewsOverTimeQuery, VisitorDetails, VisitorFacets, VisitorFacetsQuery, VisitorFacetValue, VisitorInfo, VisitorJourneyQuery, VisitorJourneyResponse, VisitorLocationsQuery, VisitorRecord, VisitorSegmentFilters, VisitorSessionsQuery, VisitorSessionsResponse, VisitorsListQuery, VisitorsResponse, VisitorStats, VisitorWithGeolocation, VolumeMount, VolumeType, VulnerabilityResponse, WakeEnvironmentData, WakeEnvironmentErrors, WakeEnvironmentResponse, WakeEnvironmentResponses, WalWarning, WalWarningSeverity, WebhookConfig, WebhookDeliveryResponse, WebhookResponse, WebhookTriggerData, WebhookTriggerErrors, WebhookTriggerRequest, WebhookTriggerResponse, WebhookTriggerResponse2, WebhookTriggerResponses, WorkflowDryRunData, WorkflowDryRunErrors, WorkflowDryRunRequest, WorkflowDryRunResponse, WorkflowDryRunResponses, WorkloadDescriptor, WorkloadId, WorkloadStatus, WorkloadType, WriteFileBody, WriteFileData, WriteFileErrors, WriteFileResponse, WriteFileResponses, WriteFilesBody, WriteFilesData, WriteFilesErrors, WriteFilesResponse, WriteFilesResponse2, WriteFilesResponses, ZoneListResponse } from './types.gen'; diff --git a/apps/temps-cli/src/api/sdk.gen.ts b/apps/temps-cli/src/api/sdk.gen.ts index 2d9341c38..08b522476 100644 --- a/apps/temps-cli/src/api/sdk.gen.ts +++ b/apps/temps-cli/src/api/sdk.gen.ts @@ -1,10 +1,10 @@ // This file is auto-generated by @hey-api/openapi-ts -import { type Client, formDataBodySerializer, type Options as Options2, type TDataShape } from './client'; +import { type Client, type ClientMeta, formDataBodySerializer, type Options as Options2, type RequestResult, type ServerSentEventsResult, type TDataShape } from './client'; import { client } from './client.gen'; -import type { AcknowledgeAlarmData, AcknowledgeAlarmErrors, AcknowledgeAlarmResponses, ActivateAiProviderData, ActivateAiProviderErrors, ActivateAiProviderResponses, ActivateApiKeyData, ActivateApiKeyErrors, ActivateApiKeyResponses, ActivateConnectionData, ActivateConnectionErrors, ActivateConnectionResponses, ActivateProviderData, ActivateProviderErrors, ActivateProviderResponses, AddClusterMemberData, AddClusterMemberErrors, AddClusterMemberResponses, AddContextData, AddContextErrors, AddContextResponses, AddEnvironmentDomainData, AddEnvironmentDomainErrors, AddEnvironmentDomainResponses, AddEventsData, AddEventsErrors, AddEventsResponses, AddManagedDomainData, AddManagedDomainErrors, AddManagedDomainResponses, AddSessionReplayEventsData, AddSessionReplayEventsErrors, AddSessionReplayEventsResponses, AddTeamMemberData, AddTeamMemberErrors, AddTeamMemberResponses, AdminDrainNodeData, AdminDrainNodeErrors, AdminDrainNodeResponses, AdminDrainStatusData, AdminDrainStatusErrors, AdminDrainStatusResponses, AdminGetNodeData, AdminGetNodeErrors, AdminGetNodeResponses, AdminListNodeContainersData, AdminListNodeContainersErrors, AdminListNodeContainersResponses, AdminListNodesData, AdminListNodesErrors, AdminListNodesResponses, AdminRemoveNodeData, AdminRemoveNodeErrors, AdminRemoveNodeResponses, AdminUndrainNodeData, AdminUndrainNodeErrors, AdminUndrainNodeResponses, ApplyHostnameModeData, ApplyHostnameModeErrors, ApplyHostnameModeResponses, ArchiveConversationData, ArchiveConversationErrors, ArchiveConversationResponses, ArchiveFlagData, ArchiveFlagErrors, ArchiveFlagResponses, AssignRoleData, AssignRoleErrors, AssignRoleResponses, AttachScheduleServicesData, AttachScheduleServicesErrors, AttachScheduleServicesResponses, BlobCopyData, BlobCopyErrors, BlobCopyResponses, BlobDeleteData, BlobDeleteErrors, BlobDeleteResponses, BlobDisableData, BlobDisableErrors, BlobDisableResponses, BlobDownloadData, BlobDownloadErrors, BlobDownloadResponses, BlobEnableData, BlobEnableErrors, BlobEnableResponses, BlobHeadData, BlobHeadErrors, BlobHeadResponses, BlobListData, BlobListErrors, BlobListResponses, BlobPutData, BlobPutErrors, BlobPutResponses, BlobStatusData, BlobStatusErrors, BlobStatusResponses, BlobUpdateData, BlobUpdateErrors, BlobUpdateResponses, CancelBackupData, CancelBackupErrors, CancelBackupResponses, CancelData, CancelDeploymentData, CancelDeploymentErrors, CancelDeploymentResponses, CancelDomainOrderData, CancelDomainOrderErrors, CancelDomainOrderResponses, CancelErrors, CancelPgUpgradeData, CancelPgUpgradeErrors, CancelPgUpgradeResponses, CancelResponses, CancelRunData, CancelRunErrors, CancelRunResponses, CancelScheduleRunData, CancelScheduleRunErrors, CancelScheduleRunResponses, ChangePasswordSelfData, ChangePasswordSelfErrors, ChangePasswordSelfResponses, ChangeProjectSourceData, ChangeProjectSourceErrors, ChangeProjectSourceResponses, ChangeRequiredPasswordData, ChangeRequiredPasswordErrors, ChangeRequiredPasswordResponses, ChatCompletionsData, ChatCompletionsErrors, ChatCompletionsResponses, CheckAnalyticsHasEventsData, CheckAnalyticsHasEventsErrors, CheckAnalyticsHasEventsResponses, CheckCommitExistsData, CheckCommitExistsErrors, CheckCommitExistsResponses, CheckDomainStatusData, CheckDomainStatusErrors, CheckDomainStatusResponses, CheckExplorerSupportData, CheckExplorerSupportErrors, CheckExplorerSupportResponses, CheckIpBlockedData, CheckIpBlockedErrors, CheckIpBlockedResponses, CheckProviderDeletionSafetyData, CheckProviderDeletionSafetyErrors, CheckProviderDeletionSafetyResponses, ChunkUploadOptionsData, ChunkUploadOptionsResponses, CleanupExpiredBackupsData, CleanupExpiredBackupsErrors, CleanupExpiredBackupsResponses, ClearPreviewPasswordData, ClearPreviewPasswordErrors, ClearPreviewPasswordResponses, CliDeviceApproveData, CliDeviceApproveErrors, CliDeviceApproveResponses, CliDeviceDenyData, CliDeviceDenyErrors, CliDeviceDenyResponses, CliDeviceLookupData, CliDeviceLookupErrors, CliDeviceLookupResponses, CliDevicePollData, CliDevicePollErrors, CliDevicePollResponses, CliDeviceStartData, CliDeviceStartErrors, CliDeviceStartResponses, CliLogoutData, CliLogoutErrors, CliLogoutResponses, CmdData, CmdErrors, CmdKillData, CmdKillErrors, CmdKillResponses, CmdLogsData, CmdLogsErrors, CmdLogsResponses, CmdResponses, ConfirmPendingActionData, ConfirmPendingActionErrors, ConfirmPendingActionResponses, ContainerMetricsGetHistoryData, ContainerMetricsGetHistoryErrors, ContainerMetricsGetHistoryResponses, CreateAgentData, CreateAgentErrors, CreateAgentResponses, CreateAlertData, CreateAlertErrors, CreateAlertResponses, CreateAlertRuleData, CreateAlertRuleErrors, CreateAlertRuleResponses, CreateApiKeyData, CreateApiKeyErrors, CreateApiKeyResponses, CreateBackupScheduleData, CreateBackupScheduleErrors, CreateBackupScheduleResponses, CreateBitbucketProviderData, CreateBitbucketProviderErrors, CreateBitbucketProviderResponses, CreateCloudflareProviderData, CreateCloudflareProviderErrors, CreateCloudflareProviderResponses, CreateConversationData, CreateConversationErrors, CreateConversationResponses, CreateCustomDomainData, CreateCustomDomainErrors, CreateCustomDomainResponses, CreateDashboardData, CreateDashboardErrors, CreateDashboardResponses, CreateDeploymentTokenData, CreateDeploymentTokenErrors, CreateDeploymentTokenResponses, CreateDnsProviderData, CreateDnsProviderErrors, CreateDnsProviderResponses, CreateDomainData, CreateDomainErrors, CreateDomainResponses, CreateDsnData, CreateDsnErrors, CreateDsnResponses, CreateEmailDomainData, CreateEmailDomainErrors, CreateEmailDomainResponses, CreateEmailProviderData, CreateEmailProviderErrors, CreateEmailProviderResponses, CreateEnvironmentData, CreateEnvironmentErrors, CreateEnvironmentResponses, CreateEnvironmentVariableData, CreateEnvironmentVariableErrors, CreateEnvironmentVariableResponses, CreateFlagData, CreateFlagErrors, CreateFlagResponses, CreateFunnelData, CreateFunnelErrors, CreateFunnelResponses, CreateGenericProviderData, CreateGenericProviderErrors, CreateGenericProviderResponses, CreateGiteaPatProviderData, CreateGiteaPatProviderErrors, CreateGiteaPatProviderResponses, CreateGithubPatProviderData, CreateGithubPatProviderErrors, CreateGithubPatProviderResponses, CreateGitlabOauthProviderData, CreateGitlabOauthProviderErrors, CreateGitlabOauthProviderResponses, CreateGitlabPatProviderData, CreateGitlabPatProviderErrors, CreateGitlabPatProviderResponses, CreateGitProviderData, CreateGitProviderErrors, CreateGitProviderResponses, CreateGlobalMcpData, CreateGlobalMcpErrors, CreateGlobalMcpResponses, CreateGlobalSkillData, CreateGlobalSkillErrors, CreateGlobalSkillResponses, CreateIncidentData, CreateIncidentErrors, CreateIncidentResponses, CreateIpAccessControlData, CreateIpAccessControlErrors, CreateIpAccessControlResponses, CreateMcpData, CreateMcpErrors, CreateMcpResponses, CreateMonitorData, CreateMonitorErrors, CreateMonitorResponses, CreateNotificationEmailProviderData, CreateNotificationEmailProviderErrors, CreateNotificationEmailProviderResponses, CreateNotificationProviderData, CreateNotificationProviderErrors, CreateNotificationProviderResponses, CreateOidcProviderData, CreateOidcProviderErrors, CreateOidcProviderResponses, CreateOidcRoleMappingData, CreateOidcRoleMappingResponses, CreateOrRecreateOrderData, CreateOrRecreateOrderErrors, CreateOrRecreateOrderResponses, CreatePlanData, CreatePlanErrors, CreatePlanResponses, CreatePrData, CreatePrErrors, CreateProjectData, CreateProjectErrors, CreateProjectFromTemplateData, CreateProjectFromTemplateErrors, CreateProjectFromTemplateResponses, CreateProjectReleaseData, CreateProjectReleaseErrors, CreateProjectReleaseResponses, CreateProjectResponses, CreateProjectSecretData, CreateProjectSecretErrors, CreateProjectSecretResponses, CreateProviderKeyData, CreateProviderKeyErrors, CreateProviderKeyResponses, CreatePrResponses, CreateReleaseData, CreateReleaseErrors, CreateReleaseResponses, CreateRouteData, CreateRouteErrors, CreateRouteResponses, CreateS3SourceData, CreateS3SourceErrors, CreateS3SourceResponses, CreateSandboxData, CreateSandboxErrors, CreateSandboxResponses, CreateServiceData, CreateServiceErrors, CreateServiceResponses, CreateSkillData, CreateSkillErrors, CreateSkillResponses, CreateSlackProviderData, CreateSlackProviderErrors, CreateSlackProviderResponses, CreateTeamData, CreateTeamErrors, CreateTeamResponses, CreateUserData, CreateUserErrors, CreateUserResponses, CreateWebhookData, CreateWebhookErrors, CreateWebhookProviderData, CreateWebhookProviderErrors, CreateWebhookProviderResponses, CreateWebhookResponses, DeactivateApiKeyData, DeactivateApiKeyErrors, DeactivateApiKeyResponses, DeactivateConnectionData, DeactivateConnectionErrors, DeactivateConnectionResponses, DeactivateProviderData, DeactivateProviderErrors, DeactivateProviderResponses, DeleteAgentData, DeleteAgentErrors, DeleteAgentResponses, DeleteAlertData, DeleteAlertErrors, DeleteAlertResponses, DeleteAlertRuleData, DeleteAlertRuleErrors, DeleteAlertRuleResponses, DeleteApiKeyData, DeleteApiKeyErrors, DeleteApiKeyResponses, DeleteBackupData, DeleteBackupErrors, DeleteBackupResponses, DeleteBackupScheduleData, DeleteBackupScheduleErrors, DeleteBackupScheduleResponses, DeleteConnectionData, DeleteConnectionErrors, DeleteConnectionResponses, DeleteCustomDomainData, DeleteCustomDomainErrors, DeleteCustomDomainResponses, DeleteDashboardData, DeleteDashboardErrors, DeleteDashboardResponses, DeleteDeploymentTokenData, DeleteDeploymentTokenErrors, DeleteDeploymentTokenResponses, DeleteDnsProviderData, DeleteDnsProviderErrors, DeleteDnsProviderResponses, DeleteDomainData, DeleteDomainErrors, DeleteDomainResponses, DeleteEmailDomainData, DeleteEmailDomainErrors, DeleteEmailDomainResponses, DeleteEmailProviderData, DeleteEmailProviderErrors, DeleteEmailProviderResponses, DeleteEnvironmentData, DeleteEnvironmentDomainData, DeleteEnvironmentDomainErrors, DeleteEnvironmentDomainResponses, DeleteEnvironmentErrors, DeleteEnvironmentResponses, DeleteEnvironmentVariableData, DeleteEnvironmentVariableErrors, DeleteEnvironmentVariableResponses, DeleteExternalImageData, DeleteExternalImageErrors, DeleteExternalImageResponses, DeleteFunnelData, DeleteFunnelErrors, DeleteFunnelResponses, DeleteGitProviderData, DeleteGitProviderErrors, DeleteGitProviderResponses, DeleteGlobalMcpData, DeleteGlobalMcpErrors, DeleteGlobalMcpResponses, DeleteGlobalSkillData, DeleteGlobalSkillErrors, DeleteGlobalSkillResponses, DeleteIpAccessControlData, DeleteIpAccessControlErrors, DeleteIpAccessControlResponses, DeleteMcpData, DeleteMcpErrors, DeleteMcpResponses, DeleteMonitorData, DeleteMonitorErrors, DeleteMonitorResponses, DeleteNotificationProviderData, DeleteNotificationProviderErrors, DeleteNotificationProviderResponses, DeleteOidcProviderData, DeleteOidcProviderResponses, DeleteOidcRoleMappingData, DeleteOidcRoleMappingResponses, DeletePreferencesData, DeletePreferencesErrors, DeletePreferencesResponses, DeleteProjectData, DeleteProjectErrors, DeleteProjectResponses, DeleteProjectSecretData, DeleteProjectSecretErrors, DeleteProjectSecretResponses, DeleteProviderKeyData, DeleteProviderKeyErrors, DeleteProviderKeyResponses, DeleteProviderSafelyData, DeleteProviderSafelyErrors, DeleteProviderSafelyResponses, DeleteReleaseSourceFilesData, DeleteReleaseSourceFilesErrors, DeleteReleaseSourceFilesResponses, DeleteReleaseSourceMapsData, DeleteReleaseSourceMapsErrors, DeleteReleaseSourceMapsResponses, DeleteRouteData, DeleteRouteErrors, DeleteRouteResponses, DeleteS3SourceData, DeleteS3SourceErrors, DeleteS3SourceResponses, DeleteScanData, DeleteScanErrors, DeleteScanResponses, DeleteSecretData, DeleteSecretErrors, DeleteSecretResponses, DeleteServiceData, DeleteServiceErrors, DeleteServiceResponses, DeleteSessionReplayData, DeleteSessionReplayErrors, DeleteSessionReplayResponses, DeleteSkillData, DeleteSkillErrors, DeleteSkillResponses, DeleteSourceMapData, DeleteSourceMapErrors, DeleteSourceMapResponses, DeleteStaticBundleData, DeleteStaticBundleErrors, DeleteStaticBundleResponses, DeleteTeamData, DeleteTeamErrors, DeleteTeamResponses, DeleteUserData, DeleteUserErrors, DeleteUserResponses, DeleteWebhookData, DeleteWebhookErrors, DeleteWebhookResponses, DeployFromImageData, DeployFromImageErrors, DeployFromImageResponses, DeployFromImageUploadData, DeployFromImageUploadErrors, DeployFromImageUploadResponses, DeployFromStaticData, DeployFromStaticErrors, DeployFromStaticResponses, DeployFromUploadedSourceData, DeployFromUploadedSourceErrors, DeployFromUploadedSourceResponses, DeploymentMetricsGetLatestData, DeploymentMetricsGetLatestErrors, DeploymentMetricsGetLatestResponses, DeploymentMetricsGetRangeData, DeploymentMetricsGetRangeErrors, DeploymentMetricsGetRangeResponses, DeploymentMetricsToggleData, DeploymentMetricsToggleErrors, DeploymentMetricsToggleResponses, DestroySandboxData, DestroySandboxErrors, DestroySandboxResponses, DetachScheduleServiceData, DetachScheduleServiceErrors, DetachScheduleServiceResponses, DetectPublicPresetsData, DetectPublicPresetsErrors, DetectPublicPresetsResponses, DisableBackupScheduleData, DisableBackupScheduleErrors, DisableBackupScheduleResponses, DisableMfaData, DisableMfaErrors, DisableMfaResponses, DisconnectCloudData, DisconnectCloudResponses, DiscoverWorkloadsData, DiscoverWorkloadsErrors, DiscoverWorkloadsResponses, DomainData, DomainErrors, DomainResponses, DownloadGlobalSkillArchiveData, DownloadGlobalSkillArchiveErrors, DownloadGlobalSkillArchiveResponses, DownloadObjectData, DownloadObjectErrors, DownloadObjectResponses, DownloadSkillArchiveData, DownloadSkillArchiveErrors, DownloadSkillArchiveResponses, EmailStatusData, EmailStatusErrors, EmailStatusResponses, EmbeddingsData, EmbeddingsErrors, EmbeddingsResponses, EnableBackupScheduleData, EnableBackupScheduleErrors, EnableBackupScheduleResponses, EnrichVisitorData, EnrichVisitorErrors, EnrichVisitorResponses, EnrollCloudData, EnrollCloudResponses, ExecData, ExecDetachedData, ExecDetachedErrors, ExecDetachedResponses, ExecErrors, ExecResponses, ExecuteDeploymentOperationData, ExecuteDeploymentOperationErrors, ExecuteDeploymentOperationResponses, ExecuteImportData, ExecuteImportErrors, ExecuteImportResponses, ExtendTimeoutData, ExtendTimeoutErrors, ExtendTimeoutResponses, ExternalServiceEnablePgStatStatementsData, ExternalServiceEnablePgStatStatementsErrors, ExternalServiceEnablePgStatStatementsResponses, ExternalServiceMetricsByDatabaseData, ExternalServiceMetricsByDatabaseErrors, ExternalServiceMetricsByDatabaseResponses, ExternalServiceMetricsCreateAlertRuleData, ExternalServiceMetricsCreateAlertRuleErrors, ExternalServiceMetricsCreateAlertRuleResponses, ExternalServiceMetricsDeleteAlertRuleData, ExternalServiceMetricsDeleteAlertRuleErrors, ExternalServiceMetricsDeleteAlertRuleResponses, ExternalServiceMetricsGetAlertRulesData, ExternalServiceMetricsGetAlertRulesErrors, ExternalServiceMetricsGetAlertRulesResponses, ExternalServiceMetricsGetLatestData, ExternalServiceMetricsGetLatestErrors, ExternalServiceMetricsGetLatestResponses, ExternalServiceMetricsGetRangeData, ExternalServiceMetricsGetRangeErrors, ExternalServiceMetricsGetRangeResponses, ExternalServiceMetricsStatusData, ExternalServiceMetricsStatusErrors, ExternalServiceMetricsStatusResponses, ExternalServiceMetricsToggleData, ExternalServiceMetricsToggleErrors, ExternalServiceMetricsToggleResponses, ExternalServiceMetricsUpdateAlertRuleData, ExternalServiceMetricsUpdateAlertRuleErrors, ExternalServiceMetricsUpdateAlertRuleResponses, ExternalServiceResetPgStatStatementsData, ExternalServiceResetPgStatStatementsErrors, ExternalServiceResetPgStatStatementsResponses, FinalizeOrderData, FinalizeOrderErrors, FinalizeOrderResponses, FinalizeProjectReleaseData, FinalizeProjectReleaseErrors, FinalizeProjectReleaseResponses, FindConversationData, FindConversationErrors, FindConversationResponses, GenerateJoinTokenData, GenerateJoinTokenErrors, GenerateJoinTokenResponses, GeneratePresetDockerfileData, GeneratePresetDockerfileErrors, GeneratePresetDockerfileResponses, GetAccessInfoData, GetAccessInfoErrors, GetAccessInfoResponses, GetActiveVisitorsData, GetActiveVisitorsErrors, GetActiveVisitorsResponses, GetActivityGraphData, GetActivityGraphErrors, GetActivityGraphResponses, GetAdminGateData, GetAdminGateErrors, GetAdminGateResponses, GetAgentData, GetAgentErrors, GetAgentResponses, GetAggregatedBucketsData, GetAggregatedBucketsErrors, GetAggregatedBucketsResponses, GetAiAgentBreakdownData, GetAiAgentBreakdownErrors, GetAiAgentBreakdownResponses, GetAiAgentPagesData, GetAiAgentPagesErrors, GetAiAgentPagesResponses, GetAiAgentTimelineData, GetAiAgentTimelineErrors, GetAiAgentTimelineResponses, GetAiDataAccessData, GetAiDataAccessErrors, GetAiDataAccessResponses, GetAiPageBreakdownData, GetAiPageBreakdownErrors, GetAiPageBreakdownResponses, GetAiStatusBreakdownData, GetAiStatusBreakdownErrors, GetAiStatusBreakdownResponses, GetAlertData, GetAlertErrors, GetAlertResponses, GetAlertRuleData, GetAlertRuleErrors, GetAlertRuleResponses, GetAllRepositoriesByNameData, GetAllRepositoriesByNameErrors, GetAllRepositoriesByNameResponses, GetAnalyticsActiveVisitorsData, GetAnalyticsActiveVisitorsErrors, GetAnalyticsActiveVisitorsResponses, GetAnalyticsEventsCountData, GetAnalyticsEventsCountErrors, GetAnalyticsEventsCountResponses, GetAnalyticsSessionEventsData, GetAnalyticsSessionEventsErrors, GetAnalyticsSessionEventsResponses, GetAnalyticsVisitorSessionsData, GetAnalyticsVisitorSessionsErrors, GetAnalyticsVisitorSessionsResponses, GetApiKeyData, GetApiKeyErrors, GetApiKeyPermissionsData, GetApiKeyPermissionsErrors, GetApiKeyPermissionsResponses, GetApiKeyResponses, GetAuditLogData, GetAuditLogErrors, GetAuditLogResponses, GetBackupData, GetBackupErrors, GetBackupResponses, GetBackupScheduleData, GetBackupScheduleErrors, GetBackupScheduleResponses, GetBranchesByRepositoryIdData, GetBranchesByRepositoryIdErrors, GetBranchesByRepositoryIdResponses, GetBucketedIncidentsData, GetBucketedIncidentsErrors, GetBucketedIncidentsResponses, GetBucketedStatusData, GetBucketedStatusErrors, GetBucketedStatusResponses, GetChallengeTokenData, GetChallengeTokenErrors, GetChallengeTokenResponses, GetChatReadinessData, GetChatReadinessErrors, GetChatReadinessResponses, GetCliStatusData, GetCliStatusErrors, GetCliStatusResponses, GetCloudCapabilityData, GetCloudCapabilityResponses, GetCloudStatusData, GetCloudStatusResponses, GetClusterHealthData, GetClusterHealthErrors, GetClusterHealthResponses, GetClusterMemberData, GetClusterMemberErrors, GetClusterMemberResponses, GetCmdData, GetCmdErrors, GetCmdResponses, GetContainerDetailData, GetContainerDetailErrors, GetContainerDetailResponses, GetContainerEnvironmentVariableData, GetContainerEnvironmentVariableErrors, GetContainerEnvironmentVariableResponses, GetContainerLogsByIdData, GetContainerLogsByIdErrors, GetContainerLogsData, GetContainerLogsErrors, GetContainerMetricsData, GetContainerMetricsErrors, GetContainerMetricsResponses, GetConversationData, GetConversationDetailData, GetConversationDetailErrors, GetConversationDetailResponses, GetConversationErrors, GetConversationResponses, GetConversationsData, GetConversationsErrors, GetConversationsResponses, GetCronByIdData, GetCronByIdErrors, GetCronByIdResponses, GetCronExecutionsData, GetCronExecutionsErrors, GetCronExecutionsResponses, GetCrossProjectTraceSiblingsData, GetCrossProjectTraceSiblingsErrors, GetCrossProjectTraceSiblingsResponses, GetCurrentMonitorStatusData, GetCurrentMonitorStatusErrors, GetCurrentMonitorStatusResponses, GetCurrentUserData, GetCurrentUserErrors, GetCurrentUserResponses, GetCustomDomainData, GetCustomDomainErrors, GetCustomDomainResponses, GetDashboardData, GetDashboardErrors, GetDashboardProjectsAnalyticsData, GetDashboardProjectsAnalyticsErrors, GetDashboardProjectsAnalyticsResponses, GetDashboardResponses, GetDeliveryData, GetDeliveryErrors, GetDeliveryResponses, GetDeploymentContainerLogContentData, GetDeploymentContainerLogContentErrors, GetDeploymentContainerLogContentResponses, GetDeploymentData, GetDeploymentErrors, GetDeploymentJobLogsData, GetDeploymentJobLogsErrors, GetDeploymentJobLogsResponses, GetDeploymentJobsData, GetDeploymentJobsErrors, GetDeploymentJobsResponses, GetDeploymentOperationsData, GetDeploymentOperationsErrors, GetDeploymentOperationsResponses, GetDeploymentOperationStatusData, GetDeploymentOperationStatusErrors, GetDeploymentOperationStatusResponses, GetDeploymentResponses, GetDeploymentTokenData, GetDeploymentTokenErrors, GetDeploymentTokenResponses, GetDiskStatusData, GetDiskStatusErrors, GetDiskStatusResponses, GetDnsChangesData, GetDnsChangesErrors, GetDnsChangesResponses, GetDnsProviderData, GetDnsProviderErrors, GetDnsProviderResponses, GetDomainByHostData, GetDomainByHostErrors, GetDomainByHostResponses, GetDomainByIdData, GetDomainByIdErrors, GetDomainByIdResponses, GetDomainByNameData, GetDomainByNameErrors, GetDomainByNameResponses, GetDomainData, GetDomainDnsRecordsData, GetDomainDnsRecordsErrors, GetDomainDnsRecordsResponses, GetDomainErrors, GetDomainOrderData, GetDomainOrderErrors, GetDomainOrderResponses, GetDomainResponses, GetEmailData, GetEmailErrors, GetEmailEventsData, GetEmailEventsErrors, GetEmailEventsResponses, GetEmailLinksData, GetEmailLinksErrors, GetEmailLinksResponses, GetEmailProviderData, GetEmailProviderErrors, GetEmailProviderResponses, GetEmailResponses, GetEmailStatsData, GetEmailStatsErrors, GetEmailStatsResponses, GetEmailTrackingData, GetEmailTrackingErrors, GetEmailTrackingResponses, GetEmailTrackingStatusData, GetEmailTrackingStatusErrors, GetEmailTrackingStatusResponses, GetEntityInfoData, GetEntityInfoErrors, GetEntityInfoResponses, GetEnvironmentCronsData, GetEnvironmentCronsErrors, GetEnvironmentCronsResponses, GetEnvironmentData, GetEnvironmentDomainsData, GetEnvironmentDomainsErrors, GetEnvironmentDomainsResponses, GetEnvironmentErrors, GetEnvironmentResponses, GetEnvironmentsData, GetEnvironmentsErrors, GetEnvironmentsResponses, GetEnvironmentVariablesData, GetEnvironmentVariablesErrors, GetEnvironmentVariablesResponses, GetEnvironmentVariableValueData, GetEnvironmentVariableValueErrors, GetEnvironmentVariableValueResponses, GetErrorDashboardStatsData, GetErrorDashboardStatsErrors, GetErrorDashboardStatsResponses, GetErrorEventData, GetErrorEventErrors, GetErrorEventResponses, GetErrorGroupData, GetErrorGroupErrors, GetErrorGroupResponses, GetErrorStatsData, GetErrorStatsErrors, GetErrorStatsResponses, GetErrorTimeSeriesData, GetErrorTimeSeriesErrors, GetErrorTimeSeriesResponses, GetEventDetailData, GetEventDetailErrors, GetEventDetailResponses, GetEventEntriesData, GetEventEntriesErrors, GetEventEntriesResponses, GetEventsCountData, GetEventsCountErrors, GetEventsCountResponses, GetEventsTimelineData, GetEventsTimelineErrors, GetEventsTimelineResponses, GetEventTypeBreakdownData, GetEventTypeBreakdownErrors, GetEventTypeBreakdownResponses, GetEventVisitorsData, GetEventVisitorsErrors, GetEventVisitorsResponses, GetExternalImageData, GetExternalImageErrors, GetExternalImageResponses, GetFileData, GetFileErrors, GetFileResponses, GetFlagData, GetFlagErrors, GetFlagResponses, GetFlagSnapshotData, GetFlagSnapshotErrors, GetFlagSnapshotResponses, GetFunnelMetricsData, GetFunnelMetricsErrors, GetFunnelMetricsResponses, GetGenaiTraceData, GetGenaiTraceErrors, GetGenaiTraceResponses, GetGeneralStatsData, GetGeneralStatsErrors, GetGeneralStatsResponses, GetGitProviderData, GetGitProviderErrors, GetGitProviderResponses, GetGlobalEventsData, GetGlobalEventsErrors, GetGlobalEventsResponses, GetGlobalEventStatsData, GetGlobalEventStatsErrors, GetGlobalEventStatsResponses, GetGlobalMcpData, GetGlobalMcpErrors, GetGlobalMcpResponses, GetGlobalSandboxStatusData, GetGlobalSandboxStatusErrors, GetGlobalSandboxStatusResponses, GetGlobalSkillData, GetGlobalSkillErrors, GetGlobalSkillResponses, GetGroupedPageMetricsData, GetGroupedPageMetricsErrors, GetGroupedPageMetricsResponses, GetHealthData, GetHealthErrors, GetHealthResponses, GetHourlyVisitsData, GetHourlyVisitsErrors, GetHourlyVisitsResponses, GetHttpChallengeDebugData, GetHttpChallengeDebugErrors, GetHttpChallengeDebugResponses, GetImportStatusData, GetImportStatusErrors, GetImportStatusResponses, GetIncidentData, GetIncidentErrors, GetIncidentResponses, GetIncidentUpdatesData, GetIncidentUpdatesErrors, GetIncidentUpdatesResponses, GetIpAccessControlData, GetIpAccessControlErrors, GetIpAccessControlResponses, GetIpGeolocationData, GetIpGeolocationErrors, GetIpGeolocationResponses, GetJoinTokenStatusData, GetJoinTokenStatusErrors, GetJoinTokenStatusResponses, GetLastDeploymentData, GetLastDeploymentErrors, GetLastDeploymentResponses, GetLatestScanData, GetLatestScanErrors, GetLatestScanResponses, GetLatestScansPerEnvironmentData, GetLatestScansPerEnvironmentErrors, GetLatestScansPerEnvironmentResponses, GetLiveVisitorsListData, GetLiveVisitorsListErrors, GetLiveVisitorsListResponses, GetLogContextData, GetLogContextErrors, GetLogContextResponses, GetMcpData, GetMcpErrors, GetMcpResponses, GetMetricsOverTimeData, GetMetricsOverTimeErrors, GetMetricsOverTimeResponses, GetMonitorData, GetMonitorErrors, GetMonitorResponses, GetNotificationProviderData, GetNotificationProviderErrors, GetNotificationProviderResponses, GetOnDemandCertStatusData, GetOnDemandCertStatusErrors, GetOnDemandCertStatusResponses, GetOrCreateDsnData, GetOrCreateDsnErrors, GetOrCreateDsnResponses, GetPageFlowData, GetPageFlowErrors, GetPageFlowResponses, GetPageHourlySessionsData, GetPageHourlySessionsErrors, GetPageHourlySessionsResponses, GetPagePathDetailData, GetPagePathDetailErrors, GetPagePathDetailResponses, GetPagePathsData, GetPagePathsErrors, GetPagePathsResponses, GetPagePathsSparklinesData, GetPagePathsSparklinesErrors, GetPagePathsSparklinesResponses, GetPagePathVisitorsData, GetPagePathVisitorsErrors, GetPagePathVisitorsResponses, GetPendingActionData, GetPendingActionErrors, GetPendingActionResponses, GetPerformanceMetricsData, GetPerformanceMetricsErrors, GetPerformanceMetricsResponses, GetPgUpgradeData, GetPgUpgradeErrors, GetPgUpgradeLogsData, GetPgUpgradeLogsErrors, GetPgUpgradeLogsResponses, GetPgUpgradeResponses, GetPipelineStatsData, GetPipelineStatsErrors, GetPipelineStatsResponses, GetPlatformInfoData, GetPlatformInfoErrors, GetPlatformInfoResponses, GetPostgresWalHealthData, GetPostgresWalHealthErrors, GetPostgresWalHealthResponses, GetPreferencesData, GetPreferencesErrors, GetPreferencesResponses, GetPreviewGatewayLogsData, GetPreviewGatewayLogsResponses, GetPreviewGatewaySettingsData, GetPreviewGatewaySettingsResponses, GetPreviewGatewayStatusData, GetPreviewGatewayStatusResponses, GetPricingData, GetPricingErrors, GetPricingResponses, GetPrivateIpData, GetPrivateIpErrors, GetPrivateIpResponses, GetProjectAlarmsSummaryData, GetProjectAlarmsSummaryErrors, GetProjectAlarmsSummaryResponses, GetProjectBySlugData, GetProjectBySlugErrors, GetProjectBySlugResponses, GetProjectData, GetProjectDeploymentsData, GetProjectDeploymentsErrors, GetProjectDeploymentsResponses, GetProjectErrors, GetProjectResponses, GetProjectsData, GetProjectsErrors, GetProjectServiceEnvironmentVariablesData, GetProjectServiceEnvironmentVariablesErrors, GetProjectServiceEnvironmentVariablesResponses, GetProjectSessionReplaysData, GetProjectSessionReplaysErrors, GetProjectSessionReplaysResponses, GetProjectsHealthData, GetProjectsHealthErrors, GetProjectsHealthResponses, GetProjectsMonitorHealthData, GetProjectsMonitorHealthErrors, GetProjectsMonitorHealthResponses, GetProjectsResponses, GetProjectStatisticsData, GetProjectStatisticsErrors, GetProjectStatisticsResponses, GetProjectTemplateData, GetProjectTemplateErrors, GetProjectTemplateResponses, GetPropertyBreakdownData, GetPropertyBreakdownErrors, GetPropertyBreakdownResponses, GetPropertyTimelineData, GetPropertyTimelineErrors, GetPropertyTimelineResponses, GetProviderConnectionsData, GetProviderConnectionsErrors, GetProviderConnectionsResponses, GetProviderMetadataData, GetProviderMetadataErrors, GetProviderMetadataResponses, GetProvidersMetadataData, GetProvidersMetadataErrors, GetProvidersMetadataResponses, GetProxyLogByIdData, GetProxyLogByIdErrors, GetProxyLogByIdResponses, GetProxyLogByRequestIdData, GetProxyLogByRequestIdErrors, GetProxyLogByRequestIdResponses, GetProxyLogsData, GetProxyLogsErrors, GetProxyLogsResponses, GetPublicBranchesData, GetPublicBranchesErrors, GetPublicBranchesResponses, GetPublicIpData, GetPublicIpErrors, GetPublicIpResponses, GetPublicRepositoryData, GetPublicRepositoryErrors, GetPublicRepositoryResponses, GetQueryContainerInfoData, GetQueryContainerInfoErrors, GetQueryContainerInfoResponses, GetQuotaData, GetQuotaErrors, GetQuotaResponses, GetRecentActivityData, GetRecentActivityErrors, GetRecentActivityResponses, GetRemoteExternalImageData, GetRemoteExternalImageErrors, GetRemoteExternalImageResponses, GetRepositoryBranchesData, GetRepositoryBranchesErrors, GetRepositoryBranchesResponses, GetRepositoryByIdData, GetRepositoryByIdErrors, GetRepositoryByIdResponses, GetRepositoryByNameData, GetRepositoryByNameErrors, GetRepositoryByNameResponses, GetRepositoryPresetByNameData, GetRepositoryPresetByNameErrors, GetRepositoryPresetByNameResponses, GetRepositoryPresetLiveData, GetRepositoryPresetLiveErrors, GetRepositoryPresetLiveResponses, GetRepositoryTagsData, GetRepositoryTagsErrors, GetRepositoryTagsResponses, GetResolvedEnvironmentVariablesData, GetResolvedEnvironmentVariablesErrors, GetResolvedEnvironmentVariablesResponses, GetResolvedEnvironmentVariableValueData, GetResolvedEnvironmentVariableValueErrors, GetResolvedEnvironmentVariableValueResponses, GetRestoreCapabilitiesData, GetRestoreCapabilitiesErrors, GetRestoreCapabilitiesResponses, GetRestoreRunData, GetRestoreRunErrors, GetRestoreRunResponses, GetRouteData, GetRouteErrors, GetRouteResponses, GetRunData, GetRunErrors, GetRunResponses, GetRunWithLogsData, GetRunWithLogsErrors, GetRunWithLogsResponses, GetS3CredentialsData, GetS3CredentialsErrors, GetS3CredentialsResponses, GetS3SourceData, GetS3SourceErrors, GetS3SourceResponses, GetSandboxData, GetSandboxErrors, GetSandboxResponses, GetSandboxStatusData, GetSandboxStatusErrors, GetSandboxStatusResponses, GetScanByDeploymentData, GetScanByDeploymentErrors, GetScanByDeploymentResponses, GetScanData, GetScanErrors, GetScanResponses, GetScanVulnerabilitiesData, GetScanVulnerabilitiesErrors, GetScanVulnerabilitiesResponses, GetServiceBySlugData, GetServiceBySlugErrors, GetServiceBySlugResponses, GetServiceData, GetServiceEnvironmentVariableData, GetServiceEnvironmentVariableErrors, GetServiceEnvironmentVariableResponses, GetServiceEnvironmentVariablesData, GetServiceEnvironmentVariablesErrors, GetServiceEnvironmentVariablesResponses, GetServiceErrors, GetServiceHealthStatusData, GetServiceHealthStatusErrors, GetServiceHealthStatusResponses, GetServicePreviewEnvironmentVariableNamesData, GetServicePreviewEnvironmentVariableNamesErrors, GetServicePreviewEnvironmentVariableNamesResponses, GetServicePreviewEnvironmentVariablesMaskedData, GetServicePreviewEnvironmentVariablesMaskedErrors, GetServicePreviewEnvironmentVariablesMaskedResponses, GetServiceResponses, GetServiceRuntimeData, GetServiceRuntimeErrors, GetServiceRuntimeResponses, GetServiceStatsData, GetServiceStatsErrors, GetServiceStatsResponses, GetServiceTypeParametersData, GetServiceTypeParametersErrors, GetServiceTypeParametersResponses, GetServiceTypesData, GetServiceTypesErrors, GetServiceTypesResponses, GetSessionDetailsData, GetSessionDetailsErrors, GetSessionDetailsResponses, GetSessionEventsData, GetSessionEventsErrors, GetSessionEventsResponses, GetSessionLogsData, GetSessionLogsErrors, GetSessionLogsResponses, GetSessionReplayData, GetSessionReplayErrors, GetSessionReplayEventsData, GetSessionReplayEventsErrors, GetSessionReplayEventsResponses, GetSessionReplayResponses, GetSettingsData, GetSettingsErrors, GetSettingsResponses, GetSkillData, GetSkillErrors, GetSkillResponses, GetSlowQueriesData, GetSlowQueriesErrors, GetSlowQueriesResponses, GetStaticBundleData, GetStaticBundleErrors, GetStaticBundleResponses, GetStatusOverviewData, GetStatusOverviewErrors, GetStatusOverviewResponses, GetTagsByRepositoryIdData, GetTagsByRepositoryIdErrors, GetTagsByRepositoryIdResponses, GetTeamData, GetTeamErrors, GetTeamResponses, GetTimeBucketStatsData, GetTimeBucketStatsErrors, GetTimeBucketStatsResponses, GetTodayStatsData, GetTodayStatsErrors, GetTodayStatsResponses, GetTraceData, GetTraceErrors, GetTraceResponses, GetUnifiedTraceData, GetUnifiedTraceErrors, GetUnifiedTraceResponses, GetUniqueCountsData, GetUniqueCountsErrors, GetUniqueCountsResponses, GetUniqueEventsData, GetUniqueEventsErrors, GetUniqueEventsResponses, GetUpdateStatusData, GetUpdateStatusErrors, GetUpdateStatusResponses, GetUptimeHistoryData, GetUptimeHistoryErrors, GetUptimeHistoryResponses, GetUsageByProviderData, GetUsageByProviderErrors, GetUsageByProviderResponses, GetUsageRecentData, GetUsageRecentErrors, GetUsageRecentResponses, GetUsageSummaryData, GetUsageSummaryErrors, GetUsageSummaryResponses, GetUsageTimeseriesData, GetUsageTimeseriesErrors, GetUsageTimeseriesResponses, GetUsageTopModelsData, GetUsageTopModelsErrors, GetUsageTopModelsResponses, GetVisitorByGuidData, GetVisitorByGuidErrors, GetVisitorByGuidResponses, GetVisitorByIdData, GetVisitorByIdErrors, GetVisitorByIdResponses, GetVisitorDetailsData, GetVisitorDetailsErrors, GetVisitorDetailsResponses, GetVisitorFacetsData, GetVisitorFacetsErrors, GetVisitorFacetsResponses, GetVisitorInfoData, GetVisitorInfoErrors, GetVisitorInfoResponses, GetVisitorJourneyData, GetVisitorJourneyErrors, GetVisitorJourneyResponses, GetVisitorsData, GetVisitorsErrors, GetVisitorSessionsData, GetVisitorSessionsErrors, GetVisitorSessionsResponses, GetVisitorsResponses, GetVisitorStatsData, GetVisitorStatsErrors, GetVisitorStatsResponses, GetWebhookData, GetWebhookErrors, GetWebhookResponses, GrantProjectAccessData, GrantProjectAccessErrors, GrantProjectAccessResponses, HandleGitProviderOauthCallbackData, HandleGitProviderOauthCallbackErrors, HasAnalyticsEventsData, HasAnalyticsEventsErrors, HasAnalyticsEventsResponses, HasErrorGroupsData, HasErrorGroupsErrors, HasErrorGroupsResponses, HasPerformanceMetricsData, HasPerformanceMetricsErrors, HasPerformanceMetricsResponses, ImportExternalServiceData, ImportExternalServiceErrors, ImportExternalServiceResponses, IngestLogsByPathData, IngestLogsByPathErrors, IngestLogsByPathResponses, IngestLogsData, IngestLogsErrors, IngestLogsResponses, IngestMetricsByPathData, IngestMetricsByPathErrors, IngestMetricsByPathResponses, IngestMetricsData, IngestMetricsErrors, IngestMetricsResponses, IngestSentryEnvelopeData, IngestSentryEnvelopeErrors, IngestSentryEnvelopeResponses, IngestSentryEventData, IngestSentryEventErrors, IngestSentryEventResponses, IngestTracesByPathData, IngestTracesByPathErrors, IngestTracesByPathResponses, IngestTracesData, IngestTracesErrors, IngestTracesResponses, InitSessionReplayData, InitSessionReplayErrors, InitSessionReplayResponses, InspectDropArchiveData, InspectDropArchiveErrors, InspectDropArchiveResponses, JobLogsData, JobLogsErrors, JobLogsResponses, JobStatusData, JobStatusErrors, JobStatusResponses, KillJobData, KillJobErrors, KillJobResponses, KvDelData, KvDelErrors, KvDelResponses, KvDisableData, KvDisableErrors, KvDisableResponses, KvEnableData, KvEnableErrors, KvEnableResponses, KvExpireData, KvExpireErrors, KvExpireResponses, KvGetData, KvGetErrors, KvGetResponses, KvIncrData, KvIncrErrors, KvIncrResponses, KvKeysData, KvKeysErrors, KvKeysResponses, KvSetData, KvSetErrors, KvSetResponses, KvStatusData, KvStatusErrors, KvStatusResponses, KvTtlData, KvTtlErrors, KvTtlResponses, KvUpdateData, KvUpdateErrors, KvUpdateResponses, LatestRunForSourceData, LatestRunForSourceErrors, LatestRunForSourceResponses, LinkCustomDomainToCertificateData, LinkCustomDomainToCertificateErrors, LinkCustomDomainToCertificateResponses, LinkServiceToProjectData, LinkServiceToProjectErrors, LinkServiceToProjectResponses, ListAgentRunsData, ListAgentRunsErrors, ListAgentRunsResponses, ListAgentsData, ListAgentsErrors, ListAgentsResponses, ListAiProvidersData, ListAiProvidersErrors, ListAiProvidersResponses, ListAlertRulesData, ListAlertRulesErrors, ListAlertRulesResponses, ListAlertsData, ListAlertsErrors, ListAlertsResponses, ListAllConversationsData, ListAllConversationsErrors, ListAllConversationsResponses, ListAllRunsData, ListAllRunsErrors, ListAllRunsResponses, ListApiKeysData, ListApiKeysErrors, ListApiKeysResponses, ListAuditLogsData, ListAuditLogsErrors, ListAuditLogsResponses, ListAvailableContainersData, ListAvailableContainersErrors, ListAvailableContainersResponses, ListBackupAlertsData, ListBackupAlertsErrors, ListBackupAlertsResponses, ListBackupChildrenData, ListBackupChildrenErrors, ListBackupChildrenResponses, ListBackupSchedulesData, ListBackupSchedulesErrors, ListBackupSchedulesResponses, ListBackupsForScheduleData, ListBackupsForScheduleErrors, ListBackupsForScheduleResponses, ListCommitsByRepositoryIdData, ListCommitsByRepositoryIdErrors, ListCommitsByRepositoryIdResponses, ListConnectionsData, ListConnectionsErrors, ListConnectionsResponses, ListContainersAtPathData, ListContainersAtPathErrors, ListContainersAtPathResponses, ListContainersData, ListContainersErrors, ListContainersResponses, ListConversationsData, ListConversationsErrors, ListConversationsResponses, ListCustomDomainsForProjectData, ListCustomDomainsForProjectErrors, ListCustomDomainsForProjectResponses, ListDashboardsData, ListDashboardsErrors, ListDashboardsResponses, ListDeliveriesData, ListDeliveriesErrors, ListDeliveriesResponses, ListDeploymentContainerLogsData, ListDeploymentContainerLogsErrors, ListDeploymentContainerLogsResponses, ListDeploymentTokensData, ListDeploymentTokensErrors, ListDeploymentTokensResponses, ListDnsProvidersData, ListDnsProvidersErrors, ListDnsProvidersResponses, ListDomainsData, ListDomainsErrors, ListDomainsResponses, ListDsnsData, ListDsnsErrors, ListDsnsResponses, ListEmailDomainsData, ListEmailDomainsErrors, ListEmailDomainsResponses, ListEmailProvidersData, ListEmailProvidersErrors, ListEmailProvidersResponses, ListEmailsData, ListEmailsErrors, ListEmailsResponses, ListEnrollmentTokensData, ListEnrollmentTokensErrors, ListEnrollmentTokensResponses, ListEntitiesData, ListEntitiesErrors, ListEntitiesResponses, ListErrorEventsData, ListErrorEventsErrors, ListErrorEventsResponses, ListErrorGroupsData, ListErrorGroupsErrors, ListErrorGroupsResponses, ListEventsData, ListEventsResponses, ListEventTypesData, ListEventTypesResponses, ListExternalImagesData, ListExternalImagesErrors, ListExternalImagesResponses, ListExternalPluginsData, ListExternalPluginsErrors, ListExternalPluginsResponses, ListExternalServiceBackupsData, ListExternalServiceBackupsErrors, ListExternalServiceBackupsResponses, ListFlagsData, ListFlagsErrors, ListFlagsResponses, ListFunnelsData, ListFunnelsErrors, ListFunnelsResponses, ListGitProvidersData, ListGitProvidersErrors, ListGitProvidersResponses, ListGlobalMcpsData, ListGlobalMcpsErrors, ListGlobalMcpsResponses, ListGlobalSkillsData, ListGlobalSkillsErrors, ListGlobalSkillsResponses, ListIncidentsData, ListIncidentsErrors, ListIncidentsResponses, ListInsightsData, ListInsightsErrors, ListInsightsResponses, ListIpAccessControlData, ListIpAccessControlErrors, ListIpAccessControlResponses, ListJobsData, ListJobsErrors, ListJobsResponses, ListKnownAiAgentsData, ListKnownAiAgentsErrors, ListKnownAiAgentsResponses, ListManagedDomainsData, ListManagedDomainsErrors, ListManagedDomainsResponses, ListMcpsData, ListMcpsErrors, ListMcpsResponses, ListMetricLabelKeysData, ListMetricLabelKeysErrors, ListMetricLabelKeysResponses, ListMetricLabelValuesData, ListMetricLabelValuesErrors, ListMetricLabelValuesResponses, ListMetricNamesData, ListMetricNamesErrors, ListMetricNamesResponses, ListModelsData, ListModelsErrors, ListModelsResponses, ListMonitorsData, ListMonitorsErrors, ListMonitorsResponses, ListNotificationProvidersData, ListNotificationProvidersErrors, ListNotificationProvidersResponses, ListOidcProvidersData, ListOidcProvidersResponses, ListOidcProviderUsersData, ListOidcProviderUsersErrors, ListOidcProviderUsersResponses, ListOidcRoleMappingsData, ListOidcRoleMappingsResponses, ListOnDemandCertsData, ListOnDemandCertsErrors, ListOnDemandCertsResponses, ListOrdersData, ListOrdersErrors, ListOrdersResponses, ListPeersData, ListPeersErrors, ListPeersResponses, ListPendingActionsData, ListPendingActionsErrors, ListPendingActionsResponses, ListPgUpgradesData, ListPgUpgradesErrors, ListPgUpgradesResponses, ListPresetsData, ListPresetsErrors, ListPresetsResponses, ListProjectAccessData, ListProjectAccessErrors, ListProjectAccessResponses, ListProjectAlarmsData, ListProjectAlarmsErrors, ListProjectAlarmsResponses, ListProjectScansData, ListProjectScansErrors, ListProjectScansResponses, ListProjectSecretsData, ListProjectSecretsErrors, ListProjectSecretsResponses, ListProjectServicesData, ListProjectServicesErrors, ListProjectServicesResponses, ListProjectTemplatesData, ListProjectTemplatesErrors, ListProjectTemplatesResponses, ListProjectTemplateTagsData, ListProjectTemplateTagsErrors, ListProjectTemplateTagsResponses, ListProviderKeysData, ListProviderKeysErrors, ListProviderKeysResponses, ListProviderZonesData, ListProviderZonesErrors, ListProviderZonesResponses, ListPublicProvidersData, ListPublicProvidersResponses, ListReleaseFilesData, ListReleaseFilesErrors, ListReleaseFilesResponses, ListReleasesData, ListReleasesErrors, ListReleasesResponses, ListRemoteExternalImagesData, ListRemoteExternalImagesErrors, ListRemoteExternalImagesResponses, ListRepositoriesByConnectionData, ListRepositoriesByConnectionErrors, ListRepositoriesByConnectionResponses, ListRepositoriesByProviderData, ListRepositoriesByProviderErrors, ListRepositoriesByProviderResponses, ListRestoreRunsForServiceData, ListRestoreRunsForServiceResponses, ListRootContainersData, ListRootContainersErrors, ListRootContainersResponses, ListRoutesData, ListRoutesErrors, ListRoutesResponses, ListS3SourcesData, ListS3SourcesErrors, ListS3SourcesResponses, ListSandboxesData, ListSandboxesResponses, ListScheduleRunJobsData, ListScheduleRunJobsErrors, ListScheduleRunJobsResponses, ListScheduleRunsData, ListScheduleRunsErrors, ListScheduleRunsResponses, ListScheduleServicesData, ListScheduleServicesErrors, ListScheduleServicesResponses, ListSecretsData, ListSecretsErrors, ListSecretsResponses, ListServiceHealthStatusesData, ListServiceHealthStatusesErrors, ListServiceHealthStatusesResponses, ListServiceProjectsData, ListServiceProjectsErrors, ListServiceProjectsResponses, ListServiceSchedulesData, ListServiceSchedulesErrors, ListServiceSchedulesResponses, ListServicesData, ListServicesErrors, ListServicesResponses, ListSkillsData, ListSkillsErrors, ListSkillsResponses, ListSourceBackupsData, ListSourceBackupsErrors, ListSourceBackupsResponses, ListSourceFilesData, ListSourceFilesErrors, ListSourceFilesResponses, ListSourceMapsData, ListSourceMapsErrors, ListSourceMapsResponses, ListSourcesData, ListSourcesErrors, ListSourcesResponses, ListStaticBundlesData, ListStaticBundlesErrors, ListStaticBundlesResponses, ListSyncedRepositoriesData, ListSyncedRepositoriesErrors, ListSyncedRepositoriesResponses, ListTeamMembersData, ListTeamMembersErrors, ListTeamMembersResponses, ListTeamProjectsData, ListTeamProjectsErrors, ListTeamProjectsResponses, ListTeamsData, ListTeamsErrors, ListTeamsResponses, ListUsersData, ListUsersErrors, ListUsersResponses, ListWebhooksData, ListWebhooksErrors, ListWebhooksResponses, LoginData, LoginErrors, LoginResponses, LogoutData, LogoutErrors, LogoutResponses, LookupDnsARecordsData, LookupDnsARecordsErrors, LookupDnsARecordsResponses, MintEnrollmentTokenData, MintEnrollmentTokenErrors, MintEnrollmentTokenResponses, MkdirData, MkdirErrors, MkdirResponses, NodeHeartbeatData, NodeHeartbeatErrors, NodeHeartbeatResponses, NodeMetricsGetRangeData, NodeMetricsGetRangeErrors, NodeMetricsGetRangeResponses, ObservabilityFullEventData, ObservabilityFullEventErrors, ObservabilityFullEventResponses, ObservabilityListEventsData, ObservabilityListEventsErrors, ObservabilityListEventsResponses, OidcCallbackData, PatchAdminGateData, PatchAdminGateErrors, PatchAdminGateResponses, PatchPreviewGatewaySettingsData, PatchPreviewGatewaySettingsResponses, PauseDeploymentData, PauseDeploymentErrors, PauseDeploymentResponses, PauseSandboxData, PauseSandboxErrors, PauseSandboxResponses, PlanRestoreData, PlanRestoreErrors, PlanRestoreResponses, PostDnsAckData, PostDnsAckErrors, PostDnsAckResponses, PreviewAlertData, PreviewAlertErrors, PreviewAlertResponses, PreviewFunnelMetricsData, PreviewFunnelMetricsErrors, PreviewFunnelMetricsResponses, PreviewHostnameModeData, PreviewHostnameModeErrors, PreviewHostnameModeResponses, PromoteClusterMemberData, PromoteClusterMemberErrors, PromoteClusterMemberResponses, PromoteDeploymentData, PromoteDeploymentErrors, PromoteDeploymentResponses, ProvisionDomainData, ProvisionDomainErrors, ProvisionDomainResponses, PurgeProjectLogsData, PurgeProjectLogsErrors, PurgeProjectLogsResponses, PushExternalImageData, PushExternalImageErrors, PushExternalImageResponses, QueryDataData, QueryDataErrors, QueryDataResponses, QueryGenaiTracesData, QueryGenaiTracesErrors, QueryGenaiTracesResponses, QueryLogsData, QueryLogsErrors, QueryLogsResponses, QueryMetricsData, QueryMetricsErrors, QueryMetricsResponses, QueryTracesData, QueryTracesErrors, QueryTracesResponses, QueryTraceSummariesData, QueryTraceSummariesErrors, QueryTraceSummariesResponses, ReadEntityRowsData, ReadEntityRowsErrors, ReadEntityRowsResponses, ReadFileData, ReadFileErrors, ReadFileResponses, ReAnalyzeData, ReAnalyzeErrors, ReAnalyzeResponses, RebuildSandboxImageData, RebuildSandboxImageErrors, RebuildSandboxImageResponses, RecordConsoleEventData, RecordConsoleEventErrors, RecordConsoleEventResponses, RecordEventMetricsData, RecordEventMetricsErrors, RecordEventMetricsResponses, RecordFlagExposureData, RecordFlagExposureErrors, RecordFlagExposureResponses, RecordSpeedMetricsData, RecordSpeedMetricsErrors, RecordSpeedMetricsResponses, RefreshRouteTableData, RefreshRouteTableErrors, RefreshRouteTableResponses, RegenerateDsnData, RegenerateDsnErrors, RegenerateDsnResponses, RegisterExternalImageData, RegisterExternalImageErrors, RegisterExternalImageResponses, RegisterNodeData, RegisterNodeErrors, RegisterNodeResponses, ReinstallGitlabWebhookData, ReinstallGitlabWebhookErrors, ReinstallGitlabWebhookResponses, RejectPendingActionData, RejectPendingActionErrors, RejectPendingActionResponses, ReloadPluginsData, ReloadPluginsErrors, ReloadPluginsResponses, RemoveClusterMemberData, RemoveClusterMemberErrors, RemoveClusterMemberResponses, RemoveManagedDomainData, RemoveManagedDomainErrors, RemoveManagedDomainResponses, RemoveRoleData, RemoveRoleErrors, RemoveRoleResponses, RemoveTeamMemberData, RemoveTeamMemberErrors, RemoveTeamMemberResponses, RenameConversationData, RenameConversationErrors, RenameConversationResponses, RenewDomainData, RenewDomainErrors, RenewDomainResponses, RequestPasswordResetData, RequestPasswordResetErrors, RequestPasswordResetResponses, ResetPasswordData, ResetPasswordErrors, ResetPasswordResponses, ResizeSandboxData, ResizeSandboxErrors, ResizeSandboxResponses, ResolveAlarmData, ResolveAlarmErrors, ResolveAlarmResponses, RestartContainerData, RestartContainerErrors, RestartContainerResponses, RestartPreviewGatewayData, RestartPreviewGatewayResponses, RestartSandboxData, RestartSandboxErrors, RestartSandboxResponses, RestoreFlagData, RestoreFlagErrors, RestoreFlagResponses, RestoreUserData, RestoreUserErrors, RestoreUserResponses, ResumeDeploymentData, ResumeDeploymentErrors, ResumeDeploymentResponses, ResumeSandboxData, ResumeSandboxErrors, ResumeSandboxResponses, RetryClusterData, RetryClusterErrors, RetryClusterResponses, RetryDeliveryData, RetryDeliveryErrors, RetryDeliveryResponses, RetryPgUpgradeData, RetryPgUpgradeErrors, RetryPgUpgradeResponses, RetryRunData, RetryRunErrors, RetryRunResponses, RevealGlobalMcpConfigData, RevealGlobalMcpConfigErrors, RevealGlobalMcpConfigResponses, RevealMcpConfigData, RevealMcpConfigErrors, RevealMcpConfigResponses, RevealNotificationProviderConfigData, RevealNotificationProviderConfigErrors, RevealNotificationProviderConfigResponses, RevealServiceParameterData, RevealServiceParameterErrors, RevealServiceParameterResponses, RevenueCreateIntegrationData, RevenueCreateIntegrationErrors, RevenueCreateIntegrationResponses, RevenueDeleteIntegrationData, RevenueDeleteIntegrationResponses, RevenueGlobalEventsData, RevenueGlobalEventsResponses, RevenueImportInvoicesCsvData, RevenueImportInvoicesCsvErrors, RevenueImportInvoicesCsvResponses, RevenueImportSubscriptionsCsvData, RevenueImportSubscriptionsCsvErrors, RevenueImportSubscriptionsCsvResponses, RevenueListIntegrationsData, RevenueListIntegrationsResponses, RevenueListProvidersData, RevenueListProvidersResponses, RevenueMetricsCustomersData, RevenueMetricsCustomersResponses, RevenueMetricsGlobalMrrData, RevenueMetricsGlobalMrrResponses, RevenueMetricsGlobalSummaryData, RevenueMetricsGlobalSummaryResponses, RevenueMetricsMrrData, RevenueMetricsMrrResponses, RevenueMetricsSummaryData, RevenueMetricsSummaryResponses, RevenueRecentEventsData, RevenueRecentEventsResponses, RevenueRotateTokenData, RevenueRotateTokenResponses, RevenueUpdateConfigData, RevenueUpdateConfigErrors, RevenueUpdateConfigResponses, RevenueUpdateSecretData, RevenueUpdateSecretErrors, RevenueUpdateSecretResponses, RevokeDsnData, RevokeDsnErrors, RevokeDsnResponses, RevokeEnrollmentTokenData, RevokeEnrollmentTokenErrors, RevokeEnrollmentTokenResponses, RevokeJoinTokenData, RevokeJoinTokenErrors, RevokeJoinTokenResponses, RevokeProjectAccessData, RevokeProjectAccessErrors, RevokeProjectAccessResponses, RollbackPgUpgradeData, RollbackPgUpgradeErrors, RollbackPgUpgradeResponses, RollbackToDeploymentData, RollbackToDeploymentErrors, RollbackToDeploymentResponses, RootfsGcData, RootfsGcResponses, RootfsReportData, RootfsReportResponses, RotateApiKeyData, RotateApiKeyErrors, RotateApiKeyResponses, RotateDeploymentTokenData, RotateDeploymentTokenErrors, RotateDeploymentTokenResponses, RunBackupForSourceData, RunBackupForSourceErrors, RunBackupForSourceResponses, RunConnectionHealthCheckData, RunConnectionHealthCheckErrors, RunConnectionHealthCheckResponses, RunExternalServiceBackupData, RunExternalServiceBackupErrors, RunExternalServiceBackupResponses, RunScheduleNowData, RunScheduleNowErrors, RunScheduleNowResponses, SandboxCreatePreviewLinkData, SandboxCreatePreviewLinkErrors, SandboxCreatePreviewLinkResponses, SaveAgentTokenData, SaveAgentTokenErrors, SaveAgentTokenResponses, SaveAiProviderCredentialData, SaveAiProviderCredentialErrors, SaveAiProviderCredentialResponses, SearchLogsData, SearchLogsErrors, SearchLogsResponses, SendEmailData, SendEmailErrors, SendEmailResponses, SendMessageData, SendMessageErrors, SendMessageResponses, SetAiDataAccessData, SetAiDataAccessErrors, SetAiDataAccessResponses, SetDefaultS3SourceData, SetDefaultS3SourceErrors, SetDefaultS3SourceResponses, SetFlagEnvironmentData, SetFlagEnvironmentErrors, SetFlagEnvironmentResponses, SetPreviewPasswordData, SetPreviewPasswordErrors, SetPreviewPasswordResponses, SetupDnsChallengeData, SetupDnsChallengeErrors, SetupDnsChallengeResponses, SetupDnsData, SetupDnsErrors, SetupDnsResponses, SetupEmailTrackingData, SetupEmailTrackingErrors, SetupEmailTrackingResponses, SetupMfaData, SetupMfaErrors, SetupMfaResponses, SleepEnvironmentData, SleepEnvironmentErrors, SleepEnvironmentResponses, SmokeTestAgentData, SmokeTestAgentErrors, SmokeTestAgentResponses, SourceSandboxData, SourceSandboxErrors, SourceSandboxResponses, StartAnalysisData, StartAnalysisErrors, StartAnalysisResponses, StartContainerData, StartContainerErrors, StartContainerResponses, StartFixData, StartFixErrors, StartFixResponses, StartGitProviderOauthData, StartGitProviderOauthErrors, StartOidcLoginBySlugData, StartOidcLoginBySlugErrors, StartPgUpgradeData, StartPgUpgradeErrors, StartPgUpgradeResponses, StartRestoreData, StartRestoreErrors, StartRestoreResponses, StartServiceData, StartServiceErrors, StartServiceResponses, StatPathData, StatPathErrors, StatPathResponses, StopContainerData, StopContainerErrors, StopContainerResponses, StopSandboxData, StopSandboxErrors, StopSandboxResponses, StopServiceData, StopServiceErrors, StopServiceResponses, StreamContainerMetricsData, StreamContainerMetricsErrors, StreamContainerMetricsResponses, StreamEventsData, StreamEventsErrors, StreamEventsResponses, StreamRunEventsData, StreamRunEventsErrors, StreamRunEventsResponses, SyncRepositoriesData, SyncRepositoriesErrors, SyncRepositoriesResponses, TailDeploymentJobLogsData, TailDeploymentJobLogsErrors, TailLogsData, TailLogsErrors, TailLogsResponses, TeardownDeploymentData, TeardownDeploymentErrors, TeardownDeploymentResponses, TeardownEnvironmentData, TeardownEnvironmentErrors, TeardownEnvironmentResponses, TestNotificationProviderData, TestNotificationProviderErrors, TestNotificationProviderResponses, TestOidcProviderData, TestOidcProviderResponses, TestProviderConnectionData, TestProviderConnectionErrors, TestProviderConnectionResponses, TestProviderData, TestProviderErrors, TestProviderKeyByIdData, TestProviderKeyByIdErrors, TestProviderKeyByIdResponses, TestProviderKeyInlineData, TestProviderKeyInlineErrors, TestProviderKeyInlineResponses, TestProviderResponses, TestS3ConnectionPreviewData, TestS3ConnectionPreviewErrors, TestS3ConnectionPreviewResponses, TestS3SourceConnectionData, TestS3SourceConnectionErrors, TestS3SourceConnectionResponses, TrackClickData, TrackClickErrors, TrackOpenData, TrackOpenErrors, TrackOpenResponses, TriggerAgentData, TriggerAgentErrors, TriggerAgentResponses, TriggerProjectPipelineData, TriggerProjectPipelineErrors, TriggerProjectPipelineResponses, TriggerScanData, TriggerScanErrors, TriggerScanResponses, TriggerServiceHealthCheckData, TriggerServiceHealthCheckErrors, TriggerServiceHealthCheckResponses, TriggerWeeklyDigestData, TriggerWeeklyDigestErrors, TriggerWeeklyDigestResponses, UnlinkServiceFromProjectData, UnlinkServiceFromProjectErrors, UnlinkServiceFromProjectResponses, UpdateAgentData, UpdateAgentErrors, UpdateAgentResponses, UpdateAiProviderData, UpdateAiProviderErrors, UpdateAiProviderResponses, UpdateAlertData, UpdateAlertErrors, UpdateAlertResponses, UpdateAlertRuleData, UpdateAlertRuleErrors, UpdateAlertRuleResponses, UpdateApiKeyData, UpdateApiKeyErrors, UpdateApiKeyResponses, UpdateAutomaticDeployData, UpdateAutomaticDeployErrors, UpdateAutomaticDeployResponses, UpdateBackupScheduleData, UpdateBackupScheduleErrors, UpdateBackupScheduleResponses, UpdateCloudflareProviderData, UpdateCloudflareProviderErrors, UpdateCloudflareProviderResponses, UpdateConnectionTokenData, UpdateConnectionTokenErrors, UpdateConnectionTokenResponses, UpdateCustomDomainData, UpdateCustomDomainErrors, UpdateCustomDomainResponses, UpdateDashboardData, UpdateDashboardErrors, UpdateDashboardResponses, UpdateDeploymentTokenData, UpdateDeploymentTokenErrors, UpdateDeploymentTokenResponses, UpdateEmailProviderData, UpdateEmailProviderErrors, UpdateEmailProviderResponses, UpdateEnvironmentSettingsData, UpdateEnvironmentSettingsErrors, UpdateEnvironmentSettingsResponses, UpdateEnvironmentSubdomainData, UpdateEnvironmentSubdomainErrors, UpdateEnvironmentSubdomainResponses, UpdateEnvironmentVariableData, UpdateEnvironmentVariableErrors, UpdateEnvironmentVariableResponses, UpdateErrorGroupData, UpdateErrorGroupErrors, UpdateErrorGroupResponses, UpdateFlagData, UpdateFlagErrors, UpdateFlagResponses, UpdateFunnelData, UpdateFunnelErrors, UpdateFunnelResponses, UpdateGitProviderCredentialsData, UpdateGitProviderCredentialsErrors, UpdateGitProviderCredentialsResponses, UpdateGitSettingsData, UpdateGitSettingsErrors, UpdateGitSettingsResponses, UpdateGlobalMcpData, UpdateGlobalMcpErrors, UpdateGlobalMcpResponses, UpdateGlobalSkillData, UpdateGlobalSkillErrors, UpdateGlobalSkillResponses, UpdateIncidentStatusData, UpdateIncidentStatusErrors, UpdateIncidentStatusResponses, UpdateIpAccessControlData, UpdateIpAccessControlErrors, UpdateIpAccessControlResponses, UpdateManagedDomainData, UpdateManagedDomainErrors, UpdateManagedDomainResponses, UpdateMcpData, UpdateMcpErrors, UpdateMcpResponses, UpdateNotificationEmailProviderData, UpdateNotificationEmailProviderErrors, UpdateNotificationEmailProviderResponses, UpdateNotificationProviderData, UpdateNotificationProviderErrors, UpdateNotificationProviderResponses, UpdateOidcProviderData, UpdateOidcProviderResponses, UpdatePreferencesData, UpdatePreferencesErrors, UpdatePreferencesResponses, UpdateProjectData, UpdateProjectDeploymentConfigData, UpdateProjectDeploymentConfigErrors, UpdateProjectDeploymentConfigResponses, UpdateProjectErrors, UpdateProjectResponses, UpdateProjectSecretData, UpdateProjectSecretErrors, UpdateProjectSecretResponses, UpdateProjectSettingsData, UpdateProjectSettingsErrors, UpdateProjectSettingsResponses, UpdateProviderData, UpdateProviderErrors, UpdateProviderKeyData, UpdateProviderKeyErrors, UpdateProviderKeyResponses, UpdateProviderResponses, UpdateRouteData, UpdateRouteErrors, UpdateRouteResponses, UpdateS3SourceData, UpdateS3SourceErrors, UpdateS3SourceResponses, UpdateSelfData, UpdateSelfErrors, UpdateSelfResponses, UpdateServiceData, UpdateServiceErrors, UpdateServiceResourcesData, UpdateServiceResourcesErrors, UpdateServiceResourcesResponses, UpdateServiceResponses, UpdateSessionDurationData, UpdateSessionDurationErrors, UpdateSessionDurationResponses, UpdateSettingsData, UpdateSettingsErrors, UpdateSettingsResponses, UpdateSkillData, UpdateSkillErrors, UpdateSkillResponses, UpdateSlackProviderData, UpdateSlackProviderErrors, UpdateSlackProviderResponses, UpdateSpeedMetricsData, UpdateSpeedMetricsErrors, UpdateSpeedMetricsResponses, UpdateTeamData, UpdateTeamErrors, UpdateTeamMemberRoleData, UpdateTeamMemberRoleErrors, UpdateTeamMemberRoleResponses, UpdateTeamResponses, UpdateUserData, UpdateUserErrors, UpdateUserResponses, UpdateWebhookData, UpdateWebhookErrors, UpdateWebhookProviderData, UpdateWebhookProviderErrors, UpdateWebhookProviderResponses, UpdateWebhookResponses, UpgradePreviewGatewayData, UpgradePreviewGatewayResponses, UpgradeServiceData, UpgradeServiceErrors, UpgradeServiceResponses, UploadGlobalSkillData, UploadGlobalSkillErrors, UploadGlobalSkillResponses, UploadReleaseFileData, UploadReleaseFileErrors, UploadReleaseFileResponses, UploadSkillData, UploadSkillErrors, UploadSkillResponses, UploadSourceFileData, UploadSourceFileErrors, UploadSourceFileResponses, UploadSourceMapData, UploadSourceMapErrors, UploadSourceMapResponses, UploadStaticBundleData, UploadStaticBundleErrors, UploadStaticBundleResponses, UpsertSecretData, UpsertSecretErrors, UpsertSecretResponses, ValidateConnectionData, ValidateConnectionErrors, ValidateConnectionResponses, ValidateEmailData, ValidateEmailErrors, ValidateEmailResponses, VerifyAndEnableMfaData, VerifyAndEnableMfaErrors, VerifyAndEnableMfaResponses, VerifyDomainData, VerifyDomainErrors, VerifyDomainResponses, VerifyEmailData, VerifyEmailErrors, VerifyEmailResponses, VerifyManagedDomainData, VerifyManagedDomainErrors, VerifyManagedDomainResponses, VerifyMfaChallengeData, VerifyMfaChallengeErrors, VerifyMfaChallengeResponses, VerifyStepUpData, VerifyStepUpErrors, VerifyStepUpResponses, WakeEnvironmentData, WakeEnvironmentErrors, WakeEnvironmentResponses, WebhookTriggerData, WebhookTriggerErrors, WebhookTriggerResponses, WorkflowDryRunData, WorkflowDryRunErrors, WorkflowDryRunResponses, WriteFileData, WriteFileErrors, WriteFileResponses, WriteFilesData, WriteFilesErrors, WriteFilesResponses } from './types.gen'; +import type { AcknowledgeAlarmData, AcknowledgeAlarmErrors, AcknowledgeAlarmResponses, ActivateAiProviderData, ActivateAiProviderErrors, ActivateAiProviderResponses, ActivateApiKeyData, ActivateApiKeyErrors, ActivateApiKeyResponses, ActivateConnectionData, ActivateConnectionErrors, ActivateConnectionResponses, ActivateProviderData, ActivateProviderErrors, ActivateProviderResponses, AddClusterMemberData, AddClusterMemberErrors, AddClusterMemberResponses, AddContextData, AddContextErrors, AddContextResponses, AddEnvironmentDomainData, AddEnvironmentDomainErrors, AddEnvironmentDomainResponses, AddEventsData, AddEventsErrors, AddEventsResponses, AddManagedDomainData, AddManagedDomainErrors, AddManagedDomainResponses, AddSessionReplayEventsData, AddSessionReplayEventsErrors, AddSessionReplayEventsResponses, AddTeamMemberData, AddTeamMemberErrors, AddTeamMemberResponses, AdminDrainNodeData, AdminDrainNodeErrors, AdminDrainNodeResponses, AdminDrainStatusData, AdminDrainStatusErrors, AdminDrainStatusResponses, AdminGetNodeData, AdminGetNodeErrors, AdminGetNodeResponses, AdminListNodeContainersData, AdminListNodeContainersErrors, AdminListNodeContainersResponses, AdminListNodesData, AdminListNodesErrors, AdminListNodesResponses, AdminRemoveNodeData, AdminRemoveNodeErrors, AdminRemoveNodeResponses, AdminUndrainNodeData, AdminUndrainNodeErrors, AdminUndrainNodeResponses, ApplyHostnameModeData, ApplyHostnameModeErrors, ApplyHostnameModeResponses, ArchiveConversationData, ArchiveConversationErrors, ArchiveConversationResponses, ArchiveFlagData, ArchiveFlagErrors, ArchiveFlagResponses, AssignRoleData, AssignRoleErrors, AssignRoleResponses, AttachScheduleServicesData, AttachScheduleServicesErrors, AttachScheduleServicesResponses, BlobCopyData, BlobCopyErrors, BlobCopyResponses, BlobDeleteData, BlobDeleteErrors, BlobDeleteResponses, BlobDisableData, BlobDisableErrors, BlobDisableResponses, BlobDownloadData, BlobDownloadErrors, BlobDownloadResponses, BlobEnableData, BlobEnableErrors, BlobEnableResponses, BlobHeadData, BlobHeadErrors, BlobHeadResponses, BlobListData, BlobListErrors, BlobListResponses, BlobPutData, BlobPutErrors, BlobPutResponses, BlobStatusData, BlobStatusErrors, BlobStatusResponses, BlobUpdateData, BlobUpdateErrors, BlobUpdateResponses, CancelBackupData, CancelBackupErrors, CancelBackupResponses, CancelData, CancelDeploymentData, CancelDeploymentErrors, CancelDeploymentResponses, CancelDomainOrderData, CancelDomainOrderErrors, CancelDomainOrderResponses, CancelErrors, CancelPgUpgradeData, CancelPgUpgradeErrors, CancelPgUpgradeResponses, CancelResponses, CancelRunData, CancelRunErrors, CancelRunResponses, CancelScheduleRunData, CancelScheduleRunErrors, CancelScheduleRunResponses, ChangePasswordSelfData, ChangePasswordSelfErrors, ChangePasswordSelfResponses, ChangeProjectSourceData, ChangeProjectSourceErrors, ChangeProjectSourceResponses, ChatCompletionsData, ChatCompletionsErrors, ChatCompletionsResponses, CheckAnalyticsHasEventsData, CheckAnalyticsHasEventsErrors, CheckAnalyticsHasEventsResponses, CheckCommitExistsData, CheckCommitExistsErrors, CheckCommitExistsResponses, CheckDomainStatusData, CheckDomainStatusErrors, CheckDomainStatusResponses, CheckExplorerSupportData, CheckExplorerSupportErrors, CheckExplorerSupportResponses, CheckIpBlockedData, CheckIpBlockedErrors, CheckIpBlockedResponses, CheckProviderDeletionSafetyData, CheckProviderDeletionSafetyErrors, CheckProviderDeletionSafetyResponses, ChunkUploadOptionsData, ChunkUploadOptionsResponses, CleanupExpiredBackupsData, CleanupExpiredBackupsErrors, CleanupExpiredBackupsResponses, ClearPreviewPasswordData, ClearPreviewPasswordErrors, ClearPreviewPasswordResponses, CliDeviceApproveData, CliDeviceApproveErrors, CliDeviceApproveResponses, CliDeviceDenyData, CliDeviceDenyErrors, CliDeviceDenyResponses, CliDeviceLookupData, CliDeviceLookupErrors, CliDeviceLookupResponses, CliDevicePollData, CliDevicePollErrors, CliDevicePollResponses, CliDeviceStartData, CliDeviceStartErrors, CliDeviceStartResponses, CliLogoutData, CliLogoutErrors, CliLogoutResponses, CmdData, CmdErrors, CmdKillData, CmdKillErrors, CmdKillResponses, CmdLogsData, CmdLogsErrors, CmdLogsResponses, CmdResponses, ConfirmPendingActionData, ConfirmPendingActionErrors, ConfirmPendingActionResponses, ContainerMetricsGetHistoryData, ContainerMetricsGetHistoryErrors, ContainerMetricsGetHistoryResponses, CreateAgentData, CreateAgentErrors, CreateAgentResponses, CreateAlertData, CreateAlertErrors, CreateAlertResponses, CreateAlertRuleData, CreateAlertRuleErrors, CreateAlertRuleResponses, CreateApiKeyData, CreateApiKeyErrors, CreateApiKeyResponses, CreateBackupScheduleData, CreateBackupScheduleErrors, CreateBackupScheduleResponses, CreateBitbucketProviderData, CreateBitbucketProviderErrors, CreateBitbucketProviderResponses, CreateCloudflareProviderData, CreateCloudflareProviderErrors, CreateCloudflareProviderResponses, CreateConversationData, CreateConversationErrors, CreateConversationResponses, CreateCustomDomainData, CreateCustomDomainErrors, CreateCustomDomainResponses, CreateDashboardData, CreateDashboardErrors, CreateDashboardResponses, CreateDeploymentTokenData, CreateDeploymentTokenErrors, CreateDeploymentTokenResponses, CreateDnsProviderData, CreateDnsProviderErrors, CreateDnsProviderResponses, CreateDomainData, CreateDomainErrors, CreateDomainResponses, CreateDsnData, CreateDsnErrors, CreateDsnResponses, CreateEmailDomainData, CreateEmailDomainErrors, CreateEmailDomainResponses, CreateEmailProviderData, CreateEmailProviderErrors, CreateEmailProviderResponses, CreateEnvironmentData, CreateEnvironmentErrors, CreateEnvironmentResponses, CreateEnvironmentVariableData, CreateEnvironmentVariableErrors, CreateEnvironmentVariableResponses, CreateFlagData, CreateFlagErrors, CreateFlagResponses, CreateFunnelData, CreateFunnelErrors, CreateFunnelResponses, CreateGenericProviderData, CreateGenericProviderErrors, CreateGenericProviderResponses, CreateGiteaPatProviderData, CreateGiteaPatProviderErrors, CreateGiteaPatProviderResponses, CreateGithubPatProviderData, CreateGithubPatProviderErrors, CreateGithubPatProviderResponses, CreateGitlabOauthProviderData, CreateGitlabOauthProviderErrors, CreateGitlabOauthProviderResponses, CreateGitlabPatProviderData, CreateGitlabPatProviderErrors, CreateGitlabPatProviderResponses, CreateGitProviderData, CreateGitProviderErrors, CreateGitProviderResponses, CreateGlobalMcpData, CreateGlobalMcpErrors, CreateGlobalMcpResponses, CreateGlobalSkillData, CreateGlobalSkillErrors, CreateGlobalSkillResponses, CreateIncidentData, CreateIncidentErrors, CreateIncidentResponses, CreateIpAccessControlData, CreateIpAccessControlErrors, CreateIpAccessControlResponses, CreateMcpData, CreateMcpErrors, CreateMcpResponses, CreateMonitorData, CreateMonitorErrors, CreateMonitorResponses, CreateNotificationEmailProviderData, CreateNotificationEmailProviderErrors, CreateNotificationEmailProviderResponses, CreateNotificationProviderData, CreateNotificationProviderErrors, CreateNotificationProviderResponses, CreateOidcProviderData, CreateOidcProviderErrors, CreateOidcProviderResponses, CreateOidcRoleMappingData, CreateOidcRoleMappingResponses, CreateOrRecreateOrderData, CreateOrRecreateOrderErrors, CreateOrRecreateOrderResponses, CreatePlanData, CreatePlanErrors, CreatePlanResponses, CreatePrData, CreatePrErrors, CreateProjectData, CreateProjectErrors, CreateProjectFromTemplateData, CreateProjectFromTemplateErrors, CreateProjectFromTemplateResponses, CreateProjectReleaseData, CreateProjectReleaseErrors, CreateProjectReleaseResponses, CreateProjectResponses, CreateProjectSecretData, CreateProjectSecretErrors, CreateProjectSecretResponses, CreateProviderKeyData, CreateProviderKeyErrors, CreateProviderKeyResponses, CreatePrResponses, CreateReleaseData, CreateReleaseErrors, CreateReleaseResponses, CreateRouteData, CreateRouteErrors, CreateRouteResponses, CreateS3SourceData, CreateS3SourceErrors, CreateS3SourceResponses, CreateSandboxData, CreateSandboxErrors, CreateSandboxResponses, CreateServiceData, CreateServiceErrors, CreateServiceResponses, CreateSkillData, CreateSkillErrors, CreateSkillResponses, CreateSlackProviderData, CreateSlackProviderErrors, CreateSlackProviderResponses, CreateTeamData, CreateTeamErrors, CreateTeamResponses, CreateUserData, CreateUserErrors, CreateUserResponses, CreateWebhookData, CreateWebhookErrors, CreateWebhookProviderData, CreateWebhookProviderErrors, CreateWebhookProviderResponses, CreateWebhookResponses, DeactivateApiKeyData, DeactivateApiKeyErrors, DeactivateApiKeyResponses, DeactivateConnectionData, DeactivateConnectionErrors, DeactivateConnectionResponses, DeactivateProviderData, DeactivateProviderErrors, DeactivateProviderResponses, DeleteAgentData, DeleteAgentErrors, DeleteAgentResponses, DeleteAlertData, DeleteAlertErrors, DeleteAlertResponses, DeleteAlertRuleData, DeleteAlertRuleErrors, DeleteAlertRuleResponses, DeleteApiKeyData, DeleteApiKeyErrors, DeleteApiKeyResponses, DeleteBackupData, DeleteBackupErrors, DeleteBackupResponses, DeleteBackupScheduleData, DeleteBackupScheduleErrors, DeleteBackupScheduleResponses, DeleteConnectionData, DeleteConnectionErrors, DeleteConnectionResponses, DeleteCustomDomainData, DeleteCustomDomainErrors, DeleteCustomDomainResponses, DeleteDashboardData, DeleteDashboardErrors, DeleteDashboardResponses, DeleteDeploymentTokenData, DeleteDeploymentTokenErrors, DeleteDeploymentTokenResponses, DeleteDnsProviderData, DeleteDnsProviderErrors, DeleteDnsProviderResponses, DeleteDomainData, DeleteDomainErrors, DeleteDomainResponses, DeleteEmailDomainData, DeleteEmailDomainErrors, DeleteEmailDomainResponses, DeleteEmailProviderData, DeleteEmailProviderErrors, DeleteEmailProviderResponses, DeleteEnvironmentData, DeleteEnvironmentDomainData, DeleteEnvironmentDomainErrors, DeleteEnvironmentDomainResponses, DeleteEnvironmentErrors, DeleteEnvironmentResponses, DeleteEnvironmentVariableData, DeleteEnvironmentVariableErrors, DeleteEnvironmentVariableResponses, DeleteExternalImageData, DeleteExternalImageErrors, DeleteExternalImageResponses, DeleteFunnelData, DeleteFunnelErrors, DeleteFunnelResponses, DeleteGitProviderData, DeleteGitProviderErrors, DeleteGitProviderResponses, DeleteGlobalMcpData, DeleteGlobalMcpErrors, DeleteGlobalMcpResponses, DeleteGlobalSkillData, DeleteGlobalSkillErrors, DeleteGlobalSkillResponses, DeleteIpAccessControlData, DeleteIpAccessControlErrors, DeleteIpAccessControlResponses, DeleteMcpData, DeleteMcpErrors, DeleteMcpResponses, DeleteMonitorData, DeleteMonitorErrors, DeleteMonitorResponses, DeleteNotificationProviderData, DeleteNotificationProviderErrors, DeleteNotificationProviderResponses, DeleteOidcProviderData, DeleteOidcProviderResponses, DeleteOidcRoleMappingData, DeleteOidcRoleMappingResponses, DeletePreferencesData, DeletePreferencesErrors, DeletePreferencesResponses, DeleteProjectData, DeleteProjectErrors, DeleteProjectResponses, DeleteProjectSecretData, DeleteProjectSecretErrors, DeleteProjectSecretResponses, DeleteProviderKeyData, DeleteProviderKeyErrors, DeleteProviderKeyResponses, DeleteProviderSafelyData, DeleteProviderSafelyErrors, DeleteProviderSafelyResponses, DeleteReleaseSourceFilesData, DeleteReleaseSourceFilesErrors, DeleteReleaseSourceFilesResponses, DeleteReleaseSourceMapsData, DeleteReleaseSourceMapsErrors, DeleteReleaseSourceMapsResponses, DeleteRouteData, DeleteRouteErrors, DeleteRouteResponses, DeleteS3SourceData, DeleteS3SourceErrors, DeleteS3SourceResponses, DeleteScanData, DeleteScanErrors, DeleteScanResponses, DeleteSecretData, DeleteSecretErrors, DeleteSecretResponses, DeleteServiceData, DeleteServiceErrors, DeleteServiceResponses, DeleteSessionReplayData, DeleteSessionReplayErrors, DeleteSessionReplayResponses, DeleteSkillData, DeleteSkillErrors, DeleteSkillResponses, DeleteSourceMapData, DeleteSourceMapErrors, DeleteSourceMapResponses, DeleteStaticBundleData, DeleteStaticBundleErrors, DeleteStaticBundleResponses, DeleteTeamData, DeleteTeamErrors, DeleteTeamResponses, DeleteUserData, DeleteUserErrors, DeleteUserResponses, DeleteWebhookData, DeleteWebhookErrors, DeleteWebhookResponses, DeployFromImageData, DeployFromImageErrors, DeployFromImageResponses, DeployFromImageUploadData, DeployFromImageUploadErrors, DeployFromImageUploadResponses, DeployFromStaticData, DeployFromStaticErrors, DeployFromStaticResponses, DeployFromUploadedSourceData, DeployFromUploadedSourceErrors, DeployFromUploadedSourceResponses, DeploymentMetricsGetLatestData, DeploymentMetricsGetLatestErrors, DeploymentMetricsGetLatestResponses, DeploymentMetricsGetRangeData, DeploymentMetricsGetRangeErrors, DeploymentMetricsGetRangeResponses, DeploymentMetricsToggleData, DeploymentMetricsToggleErrors, DeploymentMetricsToggleResponses, DestroySandboxData, DestroySandboxErrors, DestroySandboxResponses, DetachScheduleServiceData, DetachScheduleServiceErrors, DetachScheduleServiceResponses, DetectPublicPresetsData, DetectPublicPresetsErrors, DetectPublicPresetsResponses, DisableBackupScheduleData, DisableBackupScheduleErrors, DisableBackupScheduleResponses, DisableMfaData, DisableMfaErrors, DisableMfaResponses, DisconnectCloudData, DisconnectCloudResponses, DiscoverWorkloadsData, DiscoverWorkloadsErrors, DiscoverWorkloadsResponses, DomainData, DomainErrors, DomainResponses, DownloadGlobalSkillArchiveData, DownloadGlobalSkillArchiveErrors, DownloadGlobalSkillArchiveResponses, DownloadObjectData, DownloadObjectErrors, DownloadObjectResponses, DownloadSkillArchiveData, DownloadSkillArchiveErrors, DownloadSkillArchiveResponses, EmailStatusData, EmailStatusErrors, EmailStatusResponses, EmbeddingsData, EmbeddingsErrors, EmbeddingsResponses, EnableBackupScheduleData, EnableBackupScheduleErrors, EnableBackupScheduleResponses, EnrichVisitorData, EnrichVisitorErrors, EnrichVisitorResponses, EnrollCloudData, EnrollCloudResponses, ExecData, ExecDetachedData, ExecDetachedErrors, ExecDetachedResponses, ExecErrors, ExecResponses, ExecuteDeploymentOperationData, ExecuteDeploymentOperationErrors, ExecuteDeploymentOperationResponses, ExecuteImportData, ExecuteImportErrors, ExecuteImportResponses, ExtendTimeoutData, ExtendTimeoutErrors, ExtendTimeoutResponses, ExternalServiceEnablePgStatStatementsData, ExternalServiceEnablePgStatStatementsErrors, ExternalServiceEnablePgStatStatementsResponses, ExternalServiceMetricsByDatabaseData, ExternalServiceMetricsByDatabaseErrors, ExternalServiceMetricsByDatabaseResponses, ExternalServiceMetricsCreateAlertRuleData, ExternalServiceMetricsCreateAlertRuleErrors, ExternalServiceMetricsCreateAlertRuleResponses, ExternalServiceMetricsDeleteAlertRuleData, ExternalServiceMetricsDeleteAlertRuleErrors, ExternalServiceMetricsDeleteAlertRuleResponses, ExternalServiceMetricsGetAlertRulesData, ExternalServiceMetricsGetAlertRulesErrors, ExternalServiceMetricsGetAlertRulesResponses, ExternalServiceMetricsGetLatestData, ExternalServiceMetricsGetLatestErrors, ExternalServiceMetricsGetLatestResponses, ExternalServiceMetricsGetRangeData, ExternalServiceMetricsGetRangeErrors, ExternalServiceMetricsGetRangeResponses, ExternalServiceMetricsStatusData, ExternalServiceMetricsStatusErrors, ExternalServiceMetricsStatusResponses, ExternalServiceMetricsToggleData, ExternalServiceMetricsToggleErrors, ExternalServiceMetricsToggleResponses, ExternalServiceMetricsUpdateAlertRuleData, ExternalServiceMetricsUpdateAlertRuleErrors, ExternalServiceMetricsUpdateAlertRuleResponses, ExternalServiceResetPgStatStatementsData, ExternalServiceResetPgStatStatementsErrors, ExternalServiceResetPgStatStatementsResponses, FinalizeOrderData, FinalizeOrderErrors, FinalizeOrderResponses, FinalizeProjectReleaseData, FinalizeProjectReleaseErrors, FinalizeProjectReleaseResponses, FindConversationData, FindConversationErrors, FindConversationResponses, GenerateJoinTokenData, GenerateJoinTokenErrors, GenerateJoinTokenResponses, GeneratePresetDockerfileData, GeneratePresetDockerfileErrors, GeneratePresetDockerfileResponses, GetAccessInfoData, GetAccessInfoErrors, GetAccessInfoResponses, GetActiveVisitorsData, GetActiveVisitorsErrors, GetActiveVisitorsResponses, GetActivityGraphData, GetActivityGraphErrors, GetActivityGraphResponses, GetAdminGateData, GetAdminGateErrors, GetAdminGateResponses, GetAgentData, GetAgentErrors, GetAgentResponses, GetAggregatedBucketsData, GetAggregatedBucketsErrors, GetAggregatedBucketsResponses, GetAiAgentBreakdownData, GetAiAgentBreakdownErrors, GetAiAgentBreakdownResponses, GetAiAgentPagesData, GetAiAgentPagesErrors, GetAiAgentPagesResponses, GetAiAgentTimelineData, GetAiAgentTimelineErrors, GetAiAgentTimelineResponses, GetAiDataAccessData, GetAiDataAccessErrors, GetAiDataAccessResponses, GetAiPageBreakdownData, GetAiPageBreakdownErrors, GetAiPageBreakdownResponses, GetAiStatusBreakdownData, GetAiStatusBreakdownErrors, GetAiStatusBreakdownResponses, GetAlertData, GetAlertErrors, GetAlertResponses, GetAlertRuleData, GetAlertRuleErrors, GetAlertRuleResponses, GetAllRepositoriesByNameData, GetAllRepositoriesByNameErrors, GetAllRepositoriesByNameResponses, GetAnalyticsActiveVisitorsData, GetAnalyticsActiveVisitorsErrors, GetAnalyticsActiveVisitorsResponses, GetAnalyticsEventsCountData, GetAnalyticsEventsCountErrors, GetAnalyticsEventsCountResponses, GetAnalyticsSessionEventsData, GetAnalyticsSessionEventsErrors, GetAnalyticsSessionEventsResponses, GetAnalyticsVisitorSessionsData, GetAnalyticsVisitorSessionsErrors, GetAnalyticsVisitorSessionsResponses, GetApiKeyData, GetApiKeyErrors, GetApiKeyPermissionsData, GetApiKeyPermissionsErrors, GetApiKeyPermissionsResponses, GetApiKeyResponses, GetAuditLogData, GetAuditLogErrors, GetAuditLogResponses, GetBackupData, GetBackupErrors, GetBackupResponses, GetBackupScheduleData, GetBackupScheduleErrors, GetBackupScheduleResponses, GetBranchesByRepositoryIdData, GetBranchesByRepositoryIdErrors, GetBranchesByRepositoryIdResponses, GetBucketedIncidentsData, GetBucketedIncidentsErrors, GetBucketedIncidentsResponses, GetBucketedStatusData, GetBucketedStatusErrors, GetBucketedStatusResponses, GetChallengeTokenData, GetChallengeTokenErrors, GetChallengeTokenResponses, GetChatReadinessData, GetChatReadinessErrors, GetChatReadinessResponses, GetCliStatusData, GetCliStatusErrors, GetCliStatusResponses, GetCloudCapabilityData, GetCloudCapabilityResponses, GetCloudStatusData, GetCloudStatusResponses, GetClusterHealthData, GetClusterHealthErrors, GetClusterHealthResponses, GetClusterMemberData, GetClusterMemberErrors, GetClusterMemberResponses, GetCmdData, GetCmdErrors, GetCmdResponses, GetContainerDetailData, GetContainerDetailErrors, GetContainerDetailResponses, GetContainerEnvironmentVariableData, GetContainerEnvironmentVariableErrors, GetContainerEnvironmentVariableResponses, GetContainerLogsByIdData, GetContainerLogsByIdErrors, GetContainerLogsData, GetContainerLogsErrors, GetContainerMetricsData, GetContainerMetricsErrors, GetContainerMetricsResponses, GetConversationData, GetConversationDetailData, GetConversationDetailErrors, GetConversationDetailResponses, GetConversationErrors, GetConversationResponses, GetConversationsData, GetConversationsErrors, GetConversationsResponses, GetCronByIdData, GetCronByIdErrors, GetCronByIdResponses, GetCronExecutionsData, GetCronExecutionsErrors, GetCronExecutionsResponses, GetCrossProjectTraceSiblingsData, GetCrossProjectTraceSiblingsErrors, GetCrossProjectTraceSiblingsResponses, GetCurrentMonitorStatusData, GetCurrentMonitorStatusErrors, GetCurrentMonitorStatusResponses, GetCurrentUserData, GetCurrentUserErrors, GetCurrentUserResponses, GetCustomDomainData, GetCustomDomainErrors, GetCustomDomainResponses, GetDashboardData, GetDashboardErrors, GetDashboardProjectsAnalyticsData, GetDashboardProjectsAnalyticsErrors, GetDashboardProjectsAnalyticsResponses, GetDashboardResponses, GetDeliveryData, GetDeliveryErrors, GetDeliveryResponses, GetDeploymentContainerLogContentData, GetDeploymentContainerLogContentErrors, GetDeploymentContainerLogContentResponses, GetDeploymentData, GetDeploymentErrors, GetDeploymentJobLogsData, GetDeploymentJobLogsErrors, GetDeploymentJobLogsResponses, GetDeploymentJobsData, GetDeploymentJobsErrors, GetDeploymentJobsResponses, GetDeploymentOperationsData, GetDeploymentOperationsErrors, GetDeploymentOperationsResponses, GetDeploymentOperationStatusData, GetDeploymentOperationStatusErrors, GetDeploymentOperationStatusResponses, GetDeploymentResponses, GetDeploymentTokenData, GetDeploymentTokenErrors, GetDeploymentTokenResponses, GetDiskStatusData, GetDiskStatusErrors, GetDiskStatusResponses, GetDnsChangesData, GetDnsChangesErrors, GetDnsChangesResponses, GetDnsProviderData, GetDnsProviderErrors, GetDnsProviderResponses, GetDomainByHostData, GetDomainByHostErrors, GetDomainByHostResponses, GetDomainByIdData, GetDomainByIdErrors, GetDomainByIdResponses, GetDomainByNameData, GetDomainByNameErrors, GetDomainByNameResponses, GetDomainData, GetDomainDnsRecordsData, GetDomainDnsRecordsErrors, GetDomainDnsRecordsResponses, GetDomainErrors, GetDomainOrderData, GetDomainOrderErrors, GetDomainOrderResponses, GetDomainResponses, GetEmailData, GetEmailErrors, GetEmailEventsData, GetEmailEventsErrors, GetEmailEventsResponses, GetEmailLinksData, GetEmailLinksErrors, GetEmailLinksResponses, GetEmailProviderData, GetEmailProviderErrors, GetEmailProviderResponses, GetEmailResponses, GetEmailStatsData, GetEmailStatsErrors, GetEmailStatsResponses, GetEmailTrackingData, GetEmailTrackingErrors, GetEmailTrackingResponses, GetEmailTrackingStatusData, GetEmailTrackingStatusErrors, GetEmailTrackingStatusResponses, GetEntityInfoData, GetEntityInfoErrors, GetEntityInfoResponses, GetEnvironmentCronsData, GetEnvironmentCronsErrors, GetEnvironmentCronsResponses, GetEnvironmentData, GetEnvironmentDomainsData, GetEnvironmentDomainsErrors, GetEnvironmentDomainsResponses, GetEnvironmentErrors, GetEnvironmentResponses, GetEnvironmentsData, GetEnvironmentsErrors, GetEnvironmentsResponses, GetEnvironmentVariablesData, GetEnvironmentVariablesErrors, GetEnvironmentVariablesResponses, GetEnvironmentVariableValueData, GetEnvironmentVariableValueErrors, GetEnvironmentVariableValueResponses, GetErrorDashboardStatsData, GetErrorDashboardStatsErrors, GetErrorDashboardStatsResponses, GetErrorEventData, GetErrorEventErrors, GetErrorEventResponses, GetErrorGroupData, GetErrorGroupErrors, GetErrorGroupResponses, GetErrorStatsData, GetErrorStatsErrors, GetErrorStatsResponses, GetErrorTimeSeriesData, GetErrorTimeSeriesErrors, GetErrorTimeSeriesResponses, GetEventDetailData, GetEventDetailErrors, GetEventDetailResponses, GetEventEntriesData, GetEventEntriesErrors, GetEventEntriesResponses, GetEventsCountData, GetEventsCountErrors, GetEventsCountResponses, GetEventsTimelineData, GetEventsTimelineErrors, GetEventsTimelineResponses, GetEventTypeBreakdownData, GetEventTypeBreakdownErrors, GetEventTypeBreakdownResponses, GetEventVisitorsData, GetEventVisitorsErrors, GetEventVisitorsResponses, GetExternalImageData, GetExternalImageErrors, GetExternalImageResponses, GetFileData, GetFileErrors, GetFileResponses, GetFlagData, GetFlagErrors, GetFlagResponses, GetFlagSnapshotData, GetFlagSnapshotErrors, GetFlagSnapshotResponses, GetFunnelMetricsData, GetFunnelMetricsErrors, GetFunnelMetricsResponses, GetGenaiTraceData, GetGenaiTraceErrors, GetGenaiTraceResponses, GetGeneralStatsData, GetGeneralStatsErrors, GetGeneralStatsResponses, GetGitProviderData, GetGitProviderErrors, GetGitProviderResponses, GetGlobalEventsData, GetGlobalEventsErrors, GetGlobalEventsResponses, GetGlobalEventStatsData, GetGlobalEventStatsErrors, GetGlobalEventStatsResponses, GetGlobalMcpData, GetGlobalMcpErrors, GetGlobalMcpResponses, GetGlobalSandboxStatusData, GetGlobalSandboxStatusErrors, GetGlobalSandboxStatusResponses, GetGlobalSkillData, GetGlobalSkillErrors, GetGlobalSkillResponses, GetGroupedPageMetricsData, GetGroupedPageMetricsErrors, GetGroupedPageMetricsResponses, GetHealthData, GetHealthErrors, GetHealthResponses, GetHourlyVisitsData, GetHourlyVisitsErrors, GetHourlyVisitsResponses, GetHttpChallengeDebugData, GetHttpChallengeDebugErrors, GetHttpChallengeDebugResponses, GetImportStatusData, GetImportStatusErrors, GetImportStatusResponses, GetIncidentData, GetIncidentErrors, GetIncidentResponses, GetIncidentUpdatesData, GetIncidentUpdatesErrors, GetIncidentUpdatesResponses, GetIpAccessControlData, GetIpAccessControlErrors, GetIpAccessControlResponses, GetIpGeolocationData, GetIpGeolocationErrors, GetIpGeolocationResponses, GetJoinTokenStatusData, GetJoinTokenStatusErrors, GetJoinTokenStatusResponses, GetLastDeploymentData, GetLastDeploymentErrors, GetLastDeploymentResponses, GetLatestScanData, GetLatestScanErrors, GetLatestScanResponses, GetLatestScansPerEnvironmentData, GetLatestScansPerEnvironmentErrors, GetLatestScansPerEnvironmentResponses, GetLiveVisitorsListData, GetLiveVisitorsListErrors, GetLiveVisitorsListResponses, GetLogContextData, GetLogContextErrors, GetLogContextResponses, GetMcpData, GetMcpErrors, GetMcpResponses, GetMetricsOverTimeData, GetMetricsOverTimeErrors, GetMetricsOverTimeResponses, GetMonitorData, GetMonitorErrors, GetMonitorResponses, GetNotificationProviderData, GetNotificationProviderErrors, GetNotificationProviderResponses, GetOnDemandCertStatusData, GetOnDemandCertStatusErrors, GetOnDemandCertStatusResponses, GetOrCreateDsnData, GetOrCreateDsnErrors, GetOrCreateDsnResponses, GetPageFlowData, GetPageFlowErrors, GetPageFlowResponses, GetPageHourlySessionsData, GetPageHourlySessionsErrors, GetPageHourlySessionsResponses, GetPagePathDetailData, GetPagePathDetailErrors, GetPagePathDetailResponses, GetPagePathsData, GetPagePathsErrors, GetPagePathsResponses, GetPagePathsSparklinesData, GetPagePathsSparklinesErrors, GetPagePathsSparklinesResponses, GetPagePathVisitorsData, GetPagePathVisitorsErrors, GetPagePathVisitorsResponses, GetPendingActionData, GetPendingActionErrors, GetPendingActionResponses, GetPerformanceMetricsData, GetPerformanceMetricsErrors, GetPerformanceMetricsResponses, GetPgUpgradeData, GetPgUpgradeErrors, GetPgUpgradeLogsData, GetPgUpgradeLogsErrors, GetPgUpgradeLogsResponses, GetPgUpgradeResponses, GetPipelineStatsData, GetPipelineStatsErrors, GetPipelineStatsResponses, GetPlatformInfoData, GetPlatformInfoErrors, GetPlatformInfoResponses, GetPostgresWalHealthData, GetPostgresWalHealthErrors, GetPostgresWalHealthResponses, GetPreferencesData, GetPreferencesErrors, GetPreferencesResponses, GetPreviewGatewayLogsData, GetPreviewGatewayLogsResponses, GetPreviewGatewaySettingsData, GetPreviewGatewaySettingsResponses, GetPreviewGatewayStatusData, GetPreviewGatewayStatusResponses, GetPricingData, GetPricingErrors, GetPricingResponses, GetPrivateIpData, GetPrivateIpErrors, GetPrivateIpResponses, GetProjectAlarmsSummaryData, GetProjectAlarmsSummaryErrors, GetProjectAlarmsSummaryResponses, GetProjectBySlugData, GetProjectBySlugErrors, GetProjectBySlugResponses, GetProjectData, GetProjectDeploymentsData, GetProjectDeploymentsErrors, GetProjectDeploymentsResponses, GetProjectErrors, GetProjectResponses, GetProjectsData, GetProjectsErrors, GetProjectServiceEnvironmentVariablesData, GetProjectServiceEnvironmentVariablesErrors, GetProjectServiceEnvironmentVariablesResponses, GetProjectSessionReplaysData, GetProjectSessionReplaysErrors, GetProjectSessionReplaysResponses, GetProjectsHealthData, GetProjectsHealthErrors, GetProjectsHealthResponses, GetProjectsMonitorHealthData, GetProjectsMonitorHealthErrors, GetProjectsMonitorHealthResponses, GetProjectsResponses, GetProjectStatisticsData, GetProjectStatisticsErrors, GetProjectStatisticsResponses, GetProjectTemplateData, GetProjectTemplateErrors, GetProjectTemplateResponses, GetPropertyBreakdownData, GetPropertyBreakdownErrors, GetPropertyBreakdownResponses, GetPropertyTimelineData, GetPropertyTimelineErrors, GetPropertyTimelineResponses, GetProviderConnectionsData, GetProviderConnectionsErrors, GetProviderConnectionsResponses, GetProviderMetadataData, GetProviderMetadataErrors, GetProviderMetadataResponses, GetProvidersMetadataData, GetProvidersMetadataErrors, GetProvidersMetadataResponses, GetProxyLogByIdData, GetProxyLogByIdErrors, GetProxyLogByIdResponses, GetProxyLogByRequestIdData, GetProxyLogByRequestIdErrors, GetProxyLogByRequestIdResponses, GetProxyLogsData, GetProxyLogsErrors, GetProxyLogsResponses, GetPublicBranchesData, GetPublicBranchesErrors, GetPublicBranchesResponses, GetPublicIpData, GetPublicIpErrors, GetPublicIpResponses, GetPublicRepositoryData, GetPublicRepositoryErrors, GetPublicRepositoryResponses, GetQueryContainerInfoData, GetQueryContainerInfoErrors, GetQueryContainerInfoResponses, GetQuotaData, GetQuotaErrors, GetQuotaResponses, GetRecentActivityData, GetRecentActivityErrors, GetRecentActivityResponses, GetRemoteExternalImageData, GetRemoteExternalImageErrors, GetRemoteExternalImageResponses, GetRepositoryBranchesData, GetRepositoryBranchesErrors, GetRepositoryBranchesResponses, GetRepositoryByIdData, GetRepositoryByIdErrors, GetRepositoryByIdResponses, GetRepositoryByNameData, GetRepositoryByNameErrors, GetRepositoryByNameResponses, GetRepositoryPresetByNameData, GetRepositoryPresetByNameErrors, GetRepositoryPresetByNameResponses, GetRepositoryPresetLiveData, GetRepositoryPresetLiveErrors, GetRepositoryPresetLiveResponses, GetRepositoryTagsData, GetRepositoryTagsErrors, GetRepositoryTagsResponses, GetResolvedEnvironmentVariablesData, GetResolvedEnvironmentVariablesErrors, GetResolvedEnvironmentVariablesResponses, GetResolvedEnvironmentVariableValueData, GetResolvedEnvironmentVariableValueErrors, GetResolvedEnvironmentVariableValueResponses, GetRestoreCapabilitiesData, GetRestoreCapabilitiesErrors, GetRestoreCapabilitiesResponses, GetRestoreRunData, GetRestoreRunErrors, GetRestoreRunResponses, GetRouteData, GetRouteErrors, GetRouteResponses, GetRunData, GetRunErrors, GetRunResponses, GetRunWithLogsData, GetRunWithLogsErrors, GetRunWithLogsResponses, GetS3CredentialsData, GetS3CredentialsErrors, GetS3CredentialsResponses, GetS3SourceData, GetS3SourceErrors, GetS3SourceResponses, GetSandboxData, GetSandboxErrors, GetSandboxResponses, GetSandboxStatusData, GetSandboxStatusErrors, GetSandboxStatusResponses, GetScanByDeploymentData, GetScanByDeploymentErrors, GetScanByDeploymentResponses, GetScanData, GetScanErrors, GetScanResponses, GetScanVulnerabilitiesData, GetScanVulnerabilitiesErrors, GetScanVulnerabilitiesResponses, GetServiceBySlugData, GetServiceBySlugErrors, GetServiceBySlugResponses, GetServiceData, GetServiceEnvironmentVariableData, GetServiceEnvironmentVariableErrors, GetServiceEnvironmentVariableResponses, GetServiceEnvironmentVariablesData, GetServiceEnvironmentVariablesErrors, GetServiceEnvironmentVariablesResponses, GetServiceErrors, GetServiceHealthStatusData, GetServiceHealthStatusErrors, GetServiceHealthStatusResponses, GetServicePreviewEnvironmentVariableNamesData, GetServicePreviewEnvironmentVariableNamesErrors, GetServicePreviewEnvironmentVariableNamesResponses, GetServicePreviewEnvironmentVariablesMaskedData, GetServicePreviewEnvironmentVariablesMaskedErrors, GetServicePreviewEnvironmentVariablesMaskedResponses, GetServiceResponses, GetServiceRuntimeData, GetServiceRuntimeErrors, GetServiceRuntimeResponses, GetServiceStatsData, GetServiceStatsErrors, GetServiceStatsResponses, GetServiceTypeParametersData, GetServiceTypeParametersErrors, GetServiceTypeParametersResponses, GetServiceTypesData, GetServiceTypesErrors, GetServiceTypesResponses, GetSessionDetailsData, GetSessionDetailsErrors, GetSessionDetailsResponses, GetSessionEventsData, GetSessionEventsErrors, GetSessionEventsResponses, GetSessionLogsData, GetSessionLogsErrors, GetSessionLogsResponses, GetSessionReplayData, GetSessionReplayErrors, GetSessionReplayEventsData, GetSessionReplayEventsErrors, GetSessionReplayEventsResponses, GetSessionReplayResponses, GetSettingsData, GetSettingsErrors, GetSettingsResponses, GetSkillData, GetSkillErrors, GetSkillResponses, GetSlowQueriesData, GetSlowQueriesErrors, GetSlowQueriesResponses, GetStaticBundleData, GetStaticBundleErrors, GetStaticBundleResponses, GetStatusOverviewData, GetStatusOverviewErrors, GetStatusOverviewResponses, GetTagsByRepositoryIdData, GetTagsByRepositoryIdErrors, GetTagsByRepositoryIdResponses, GetTeamData, GetTeamErrors, GetTeamResponses, GetTimeBucketStatsData, GetTimeBucketStatsErrors, GetTimeBucketStatsResponses, GetTodayStatsData, GetTodayStatsErrors, GetTodayStatsResponses, GetTraceData, GetTraceErrors, GetTraceResponses, GetUnifiedTraceData, GetUnifiedTraceErrors, GetUnifiedTraceResponses, GetUniqueCountsData, GetUniqueCountsErrors, GetUniqueCountsResponses, GetUniqueEventsData, GetUniqueEventsErrors, GetUniqueEventsResponses, GetUpdateStatusData, GetUpdateStatusErrors, GetUpdateStatusResponses, GetUptimeHistoryData, GetUptimeHistoryErrors, GetUptimeHistoryResponses, GetUsageByProviderData, GetUsageByProviderErrors, GetUsageByProviderResponses, GetUsageRecentData, GetUsageRecentErrors, GetUsageRecentResponses, GetUsageSummaryData, GetUsageSummaryErrors, GetUsageSummaryResponses, GetUsageTimeseriesData, GetUsageTimeseriesErrors, GetUsageTimeseriesResponses, GetUsageTopModelsData, GetUsageTopModelsErrors, GetUsageTopModelsResponses, GetVisitorByGuidData, GetVisitorByGuidErrors, GetVisitorByGuidResponses, GetVisitorByIdData, GetVisitorByIdErrors, GetVisitorByIdResponses, GetVisitorDetailsData, GetVisitorDetailsErrors, GetVisitorDetailsResponses, GetVisitorFacetsData, GetVisitorFacetsErrors, GetVisitorFacetsResponses, GetVisitorInfoData, GetVisitorInfoErrors, GetVisitorInfoResponses, GetVisitorJourneyData, GetVisitorJourneyErrors, GetVisitorJourneyResponses, GetVisitorsData, GetVisitorsErrors, GetVisitorSessionsData, GetVisitorSessionsErrors, GetVisitorSessionsResponses, GetVisitorsResponses, GetVisitorStatsData, GetVisitorStatsErrors, GetVisitorStatsResponses, GetWebhookData, GetWebhookErrors, GetWebhookResponses, GrantProjectAccessData, GrantProjectAccessErrors, GrantProjectAccessResponses, HandleGitProviderOauthCallbackData, HandleGitProviderOauthCallbackErrors, HasAnalyticsEventsData, HasAnalyticsEventsErrors, HasAnalyticsEventsResponses, HasErrorGroupsData, HasErrorGroupsErrors, HasErrorGroupsResponses, HasPerformanceMetricsData, HasPerformanceMetricsErrors, HasPerformanceMetricsResponses, ImportExternalServiceData, ImportExternalServiceErrors, ImportExternalServiceResponses, IngestLogsByPathData, IngestLogsByPathErrors, IngestLogsByPathResponses, IngestLogsData, IngestLogsErrors, IngestLogsResponses, IngestMetricsByPathData, IngestMetricsByPathErrors, IngestMetricsByPathResponses, IngestMetricsData, IngestMetricsErrors, IngestMetricsResponses, IngestSentryEnvelopeData, IngestSentryEnvelopeErrors, IngestSentryEnvelopeResponses, IngestSentryEventData, IngestSentryEventErrors, IngestSentryEventResponses, IngestTracesByPathData, IngestTracesByPathErrors, IngestTracesByPathResponses, IngestTracesData, IngestTracesErrors, IngestTracesResponses, InitSessionReplayData, InitSessionReplayErrors, InitSessionReplayResponses, InspectDropArchiveData, InspectDropArchiveErrors, InspectDropArchiveResponses, JobLogsData, JobLogsErrors, JobLogsResponses, JobStatusData, JobStatusErrors, JobStatusResponses, KillJobData, KillJobErrors, KillJobResponses, KvDelData, KvDelErrors, KvDelResponses, KvDisableData, KvDisableErrors, KvDisableResponses, KvEnableData, KvEnableErrors, KvEnableResponses, KvExpireData, KvExpireErrors, KvExpireResponses, KvGetData, KvGetErrors, KvGetResponses, KvIncrData, KvIncrErrors, KvIncrResponses, KvKeysData, KvKeysErrors, KvKeysResponses, KvSetData, KvSetErrors, KvSetResponses, KvStatusData, KvStatusErrors, KvStatusResponses, KvTtlData, KvTtlErrors, KvTtlResponses, KvUpdateData, KvUpdateErrors, KvUpdateResponses, LatestRunForSourceData, LatestRunForSourceErrors, LatestRunForSourceResponses, LinkCustomDomainToCertificateData, LinkCustomDomainToCertificateErrors, LinkCustomDomainToCertificateResponses, LinkServiceToProjectData, LinkServiceToProjectErrors, LinkServiceToProjectResponses, ListAgentRunsData, ListAgentRunsErrors, ListAgentRunsResponses, ListAgentsData, ListAgentsErrors, ListAgentsResponses, ListAiProvidersData, ListAiProvidersErrors, ListAiProvidersResponses, ListAlertRulesData, ListAlertRulesErrors, ListAlertRulesResponses, ListAlertsData, ListAlertsErrors, ListAlertsResponses, ListAllConversationsData, ListAllConversationsErrors, ListAllConversationsResponses, ListAllRunsData, ListAllRunsErrors, ListAllRunsResponses, ListApiKeysData, ListApiKeysErrors, ListApiKeysResponses, ListAuditLogsData, ListAuditLogsErrors, ListAuditLogsResponses, ListAvailableContainersData, ListAvailableContainersErrors, ListAvailableContainersResponses, ListBackupAlertsData, ListBackupAlertsErrors, ListBackupAlertsResponses, ListBackupChildrenData, ListBackupChildrenErrors, ListBackupChildrenResponses, ListBackupSchedulesData, ListBackupSchedulesErrors, ListBackupSchedulesResponses, ListBackupsForScheduleData, ListBackupsForScheduleErrors, ListBackupsForScheduleResponses, ListCommitsByRepositoryIdData, ListCommitsByRepositoryIdErrors, ListCommitsByRepositoryIdResponses, ListConnectionsData, ListConnectionsErrors, ListConnectionsResponses, ListContainersAtPathData, ListContainersAtPathErrors, ListContainersAtPathResponses, ListContainersData, ListContainersErrors, ListContainersResponses, ListConversationsData, ListConversationsErrors, ListConversationsResponses, ListCustomDomainsForProjectData, ListCustomDomainsForProjectErrors, ListCustomDomainsForProjectResponses, ListDashboardsData, ListDashboardsErrors, ListDashboardsResponses, ListDeliveriesData, ListDeliveriesErrors, ListDeliveriesResponses, ListDeploymentContainerLogsData, ListDeploymentContainerLogsErrors, ListDeploymentContainerLogsResponses, ListDeploymentTokensData, ListDeploymentTokensErrors, ListDeploymentTokensResponses, ListDnsProvidersData, ListDnsProvidersErrors, ListDnsProvidersResponses, ListDomainsData, ListDomainsErrors, ListDomainsResponses, ListDsnsData, ListDsnsErrors, ListDsnsResponses, ListEmailDomainsData, ListEmailDomainsErrors, ListEmailDomainsResponses, ListEmailProvidersData, ListEmailProvidersErrors, ListEmailProvidersResponses, ListEmailsData, ListEmailsErrors, ListEmailsResponses, ListEnrollmentTokensData, ListEnrollmentTokensErrors, ListEnrollmentTokensResponses, ListEntitiesData, ListEntitiesErrors, ListEntitiesResponses, ListErrorEventsData, ListErrorEventsErrors, ListErrorEventsResponses, ListErrorGroupsData, ListErrorGroupsErrors, ListErrorGroupsResponses, ListEventsData, ListEventsResponses, ListEventTypesData, ListEventTypesResponses, ListExternalImagesData, ListExternalImagesErrors, ListExternalImagesResponses, ListExternalPluginsData, ListExternalPluginsErrors, ListExternalPluginsResponses, ListExternalServiceBackupsData, ListExternalServiceBackupsErrors, ListExternalServiceBackupsResponses, ListFlagsData, ListFlagsErrors, ListFlagsResponses, ListFunnelsData, ListFunnelsErrors, ListFunnelsResponses, ListGitProvidersData, ListGitProvidersErrors, ListGitProvidersResponses, ListGlobalMcpsData, ListGlobalMcpsErrors, ListGlobalMcpsResponses, ListGlobalSkillsData, ListGlobalSkillsErrors, ListGlobalSkillsResponses, ListIncidentsData, ListIncidentsErrors, ListIncidentsResponses, ListInsightsData, ListInsightsErrors, ListInsightsResponses, ListIpAccessControlData, ListIpAccessControlErrors, ListIpAccessControlResponses, ListJobsData, ListJobsErrors, ListJobsResponses, ListKnownAiAgentsData, ListKnownAiAgentsErrors, ListKnownAiAgentsResponses, ListManagedDomainsData, ListManagedDomainsErrors, ListManagedDomainsResponses, ListMcpsData, ListMcpsErrors, ListMcpsResponses, ListMetricLabelKeysData, ListMetricLabelKeysErrors, ListMetricLabelKeysResponses, ListMetricLabelValuesData, ListMetricLabelValuesErrors, ListMetricLabelValuesResponses, ListMetricNamesData, ListMetricNamesErrors, ListMetricNamesResponses, ListModelsData, ListModelsErrors, ListModelsResponses, ListMonitorsData, ListMonitorsErrors, ListMonitorsResponses, ListNotificationProvidersData, ListNotificationProvidersErrors, ListNotificationProvidersResponses, ListOidcProvidersData, ListOidcProvidersResponses, ListOidcProviderUsersData, ListOidcProviderUsersErrors, ListOidcProviderUsersResponses, ListOidcRoleMappingsData, ListOidcRoleMappingsResponses, ListOnDemandCertsData, ListOnDemandCertsErrors, ListOnDemandCertsResponses, ListOrdersData, ListOrdersErrors, ListOrdersResponses, ListPeersData, ListPeersErrors, ListPeersResponses, ListPendingActionsData, ListPendingActionsErrors, ListPendingActionsResponses, ListPgUpgradesData, ListPgUpgradesErrors, ListPgUpgradesResponses, ListPresetsData, ListPresetsErrors, ListPresetsResponses, ListProjectAccessData, ListProjectAccessErrors, ListProjectAccessResponses, ListProjectAlarmsData, ListProjectAlarmsErrors, ListProjectAlarmsResponses, ListProjectScansData, ListProjectScansErrors, ListProjectScansResponses, ListProjectSecretsData, ListProjectSecretsErrors, ListProjectSecretsResponses, ListProjectServicesData, ListProjectServicesErrors, ListProjectServicesResponses, ListProjectTemplatesData, ListProjectTemplatesErrors, ListProjectTemplatesResponses, ListProjectTemplateTagsData, ListProjectTemplateTagsErrors, ListProjectTemplateTagsResponses, ListProviderKeysData, ListProviderKeysErrors, ListProviderKeysResponses, ListProviderZonesData, ListProviderZonesErrors, ListProviderZonesResponses, ListPublicProvidersData, ListPublicProvidersResponses, ListReleaseFilesData, ListReleaseFilesErrors, ListReleaseFilesResponses, ListReleasesData, ListReleasesErrors, ListReleasesResponses, ListRemoteExternalImagesData, ListRemoteExternalImagesErrors, ListRemoteExternalImagesResponses, ListRepositoriesByConnectionData, ListRepositoriesByConnectionErrors, ListRepositoriesByConnectionResponses, ListRepositoriesByProviderData, ListRepositoriesByProviderErrors, ListRepositoriesByProviderResponses, ListRestoreRunsForServiceData, ListRestoreRunsForServiceResponses, ListRootContainersData, ListRootContainersErrors, ListRootContainersResponses, ListRoutesData, ListRoutesErrors, ListRoutesResponses, ListS3SourcesData, ListS3SourcesErrors, ListS3SourcesResponses, ListSandboxesData, ListSandboxesResponses, ListScheduleRunJobsData, ListScheduleRunJobsErrors, ListScheduleRunJobsResponses, ListScheduleRunsData, ListScheduleRunsErrors, ListScheduleRunsResponses, ListScheduleServicesData, ListScheduleServicesErrors, ListScheduleServicesResponses, ListSecretsData, ListSecretsErrors, ListSecretsResponses, ListServiceHealthStatusesData, ListServiceHealthStatusesErrors, ListServiceHealthStatusesResponses, ListServiceProjectsData, ListServiceProjectsErrors, ListServiceProjectsResponses, ListServiceSchedulesData, ListServiceSchedulesErrors, ListServiceSchedulesResponses, ListServicesData, ListServicesErrors, ListServicesResponses, ListSkillsData, ListSkillsErrors, ListSkillsResponses, ListSourceBackupsData, ListSourceBackupsErrors, ListSourceBackupsResponses, ListSourceFilesData, ListSourceFilesErrors, ListSourceFilesResponses, ListSourceMapsData, ListSourceMapsErrors, ListSourceMapsResponses, ListSourcesData, ListSourcesErrors, ListSourcesResponses, ListStaticBundlesData, ListStaticBundlesErrors, ListStaticBundlesResponses, ListSyncedRepositoriesData, ListSyncedRepositoriesErrors, ListSyncedRepositoriesResponses, ListTeamMembersData, ListTeamMembersErrors, ListTeamMembersResponses, ListTeamProjectsData, ListTeamProjectsErrors, ListTeamProjectsResponses, ListTeamsData, ListTeamsErrors, ListTeamsResponses, ListUsersData, ListUsersErrors, ListUsersResponses, ListWebhooksData, ListWebhooksErrors, ListWebhooksResponses, LoginData, LoginErrors, LoginResponses, LogoutData, LogoutErrors, LogoutResponses, LookupDnsARecordsData, LookupDnsARecordsErrors, LookupDnsARecordsResponses, MintEnrollmentTokenData, MintEnrollmentTokenErrors, MintEnrollmentTokenResponses, MkdirData, MkdirErrors, MkdirResponses, NodeHeartbeatData, NodeHeartbeatErrors, NodeHeartbeatResponses, NodeMetricsGetRangeData, NodeMetricsGetRangeErrors, NodeMetricsGetRangeResponses, ObservabilityFullEventData, ObservabilityFullEventErrors, ObservabilityFullEventResponses, ObservabilityListEventsData, ObservabilityListEventsErrors, ObservabilityListEventsResponses, OidcCallbackData, PatchAdminGateData, PatchAdminGateErrors, PatchAdminGateResponses, PatchPreviewGatewaySettingsData, PatchPreviewGatewaySettingsResponses, PauseDeploymentData, PauseDeploymentErrors, PauseDeploymentResponses, PauseSandboxData, PauseSandboxErrors, PauseSandboxResponses, PlanRestoreData, PlanRestoreErrors, PlanRestoreResponses, PostDnsAckData, PostDnsAckErrors, PostDnsAckResponses, PreviewAlertData, PreviewAlertErrors, PreviewAlertResponses, PreviewFunnelMetricsData, PreviewFunnelMetricsErrors, PreviewFunnelMetricsResponses, PreviewHostnameModeData, PreviewHostnameModeErrors, PreviewHostnameModeResponses, PromoteClusterMemberData, PromoteClusterMemberErrors, PromoteClusterMemberResponses, PromoteDeploymentData, PromoteDeploymentErrors, PromoteDeploymentResponses, ProvisionDomainData, ProvisionDomainErrors, ProvisionDomainResponses, PurgeProjectLogsData, PurgeProjectLogsErrors, PurgeProjectLogsResponses, PushExternalImageData, PushExternalImageErrors, PushExternalImageResponses, QueryDataData, QueryDataErrors, QueryDataResponses, QueryGenaiTracesData, QueryGenaiTracesErrors, QueryGenaiTracesResponses, QueryLogsData, QueryLogsErrors, QueryLogsResponses, QueryMetricsData, QueryMetricsErrors, QueryMetricsResponses, QueryTracesData, QueryTracesErrors, QueryTracesResponses, QueryTraceSummariesData, QueryTraceSummariesErrors, QueryTraceSummariesResponses, ReadEntityRowsData, ReadEntityRowsErrors, ReadEntityRowsResponses, ReadFileData, ReadFileErrors, ReadFileResponses, ReAnalyzeData, ReAnalyzeErrors, ReAnalyzeResponses, RebuildSandboxImageData, RebuildSandboxImageErrors, RebuildSandboxImageResponses, RecordConsoleEventData, RecordConsoleEventErrors, RecordConsoleEventResponses, RecordEventMetricsData, RecordEventMetricsErrors, RecordEventMetricsResponses, RecordFlagExposureData, RecordFlagExposureErrors, RecordFlagExposureResponses, RecordSpeedMetricsData, RecordSpeedMetricsErrors, RecordSpeedMetricsResponses, RefreshRouteTableData, RefreshRouteTableErrors, RefreshRouteTableResponses, RegenerateDsnData, RegenerateDsnErrors, RegenerateDsnResponses, RegisterExternalImageData, RegisterExternalImageErrors, RegisterExternalImageResponses, RegisterNodeData, RegisterNodeErrors, RegisterNodeResponses, ReinstallGitlabWebhookData, ReinstallGitlabWebhookErrors, ReinstallGitlabWebhookResponses, RejectPendingActionData, RejectPendingActionErrors, RejectPendingActionResponses, ReloadPluginsData, ReloadPluginsErrors, ReloadPluginsResponses, RemoveClusterMemberData, RemoveClusterMemberErrors, RemoveClusterMemberResponses, RemoveManagedDomainData, RemoveManagedDomainErrors, RemoveManagedDomainResponses, RemoveRoleData, RemoveRoleErrors, RemoveRoleResponses, RemoveTeamMemberData, RemoveTeamMemberErrors, RemoveTeamMemberResponses, RenameConversationData, RenameConversationErrors, RenameConversationResponses, RenewDomainData, RenewDomainErrors, RenewDomainResponses, RequestPasswordResetData, RequestPasswordResetErrors, RequestPasswordResetResponses, ResetPasswordData, ResetPasswordErrors, ResetPasswordResponses, ResizeSandboxData, ResizeSandboxErrors, ResizeSandboxResponses, ResolveAlarmData, ResolveAlarmErrors, ResolveAlarmResponses, RestartContainerData, RestartContainerErrors, RestartContainerResponses, RestartPreviewGatewayData, RestartPreviewGatewayResponses, RestartSandboxData, RestartSandboxErrors, RestartSandboxResponses, RestoreFlagData, RestoreFlagErrors, RestoreFlagResponses, RestoreUserData, RestoreUserErrors, RestoreUserResponses, ResumeDeploymentData, ResumeDeploymentErrors, ResumeDeploymentResponses, ResumeSandboxData, ResumeSandboxErrors, ResumeSandboxResponses, RetryClusterData, RetryClusterErrors, RetryClusterResponses, RetryDeliveryData, RetryDeliveryErrors, RetryDeliveryResponses, RetryPgUpgradeData, RetryPgUpgradeErrors, RetryPgUpgradeResponses, RetryRunData, RetryRunErrors, RetryRunResponses, RevealGlobalMcpConfigData, RevealGlobalMcpConfigErrors, RevealGlobalMcpConfigResponses, RevealMcpConfigData, RevealMcpConfigErrors, RevealMcpConfigResponses, RevealNotificationProviderConfigData, RevealNotificationProviderConfigErrors, RevealNotificationProviderConfigResponses, RevealServiceParameterData, RevealServiceParameterErrors, RevealServiceParameterResponses, RevenueCreateIntegrationData, RevenueCreateIntegrationErrors, RevenueCreateIntegrationResponses, RevenueDeleteIntegrationData, RevenueDeleteIntegrationResponses, RevenueGlobalEventsData, RevenueGlobalEventsResponses, RevenueImportInvoicesCsvData, RevenueImportInvoicesCsvErrors, RevenueImportInvoicesCsvResponses, RevenueImportSubscriptionsCsvData, RevenueImportSubscriptionsCsvErrors, RevenueImportSubscriptionsCsvResponses, RevenueListIntegrationsData, RevenueListIntegrationsResponses, RevenueListProvidersData, RevenueListProvidersResponses, RevenueMetricsCustomersData, RevenueMetricsCustomersResponses, RevenueMetricsGlobalMrrData, RevenueMetricsGlobalMrrResponses, RevenueMetricsGlobalSummaryData, RevenueMetricsGlobalSummaryResponses, RevenueMetricsMrrData, RevenueMetricsMrrResponses, RevenueMetricsSummaryData, RevenueMetricsSummaryResponses, RevenueRecentEventsData, RevenueRecentEventsResponses, RevenueRotateTokenData, RevenueRotateTokenResponses, RevenueUpdateConfigData, RevenueUpdateConfigErrors, RevenueUpdateConfigResponses, RevenueUpdateSecretData, RevenueUpdateSecretErrors, RevenueUpdateSecretResponses, RevokeDsnData, RevokeDsnErrors, RevokeDsnResponses, RevokeEnrollmentTokenData, RevokeEnrollmentTokenErrors, RevokeEnrollmentTokenResponses, RevokeJoinTokenData, RevokeJoinTokenErrors, RevokeJoinTokenResponses, RevokeProjectAccessData, RevokeProjectAccessErrors, RevokeProjectAccessResponses, RollbackPgUpgradeData, RollbackPgUpgradeErrors, RollbackPgUpgradeResponses, RollbackToDeploymentData, RollbackToDeploymentErrors, RollbackToDeploymentResponses, RootfsGcData, RootfsGcResponses, RootfsReportData, RootfsReportResponses, RotateApiKeyData, RotateApiKeyErrors, RotateApiKeyResponses, RotateDeploymentTokenData, RotateDeploymentTokenErrors, RotateDeploymentTokenResponses, RunBackupForSourceData, RunBackupForSourceErrors, RunBackupForSourceResponses, RunConnectionHealthCheckData, RunConnectionHealthCheckErrors, RunConnectionHealthCheckResponses, RunExternalServiceBackupData, RunExternalServiceBackupErrors, RunExternalServiceBackupResponses, RunScheduleNowData, RunScheduleNowErrors, RunScheduleNowResponses, SandboxCreatePreviewLinkData, SandboxCreatePreviewLinkErrors, SandboxCreatePreviewLinkResponses, SaveAgentTokenData, SaveAgentTokenErrors, SaveAgentTokenResponses, SaveAiProviderCredentialData, SaveAiProviderCredentialErrors, SaveAiProviderCredentialResponses, SearchLogsData, SearchLogsErrors, SearchLogsResponses, SendEmailData, SendEmailErrors, SendEmailResponses, SendMessageData, SendMessageErrors, SendMessageResponses, SetAiDataAccessData, SetAiDataAccessErrors, SetAiDataAccessResponses, SetDefaultS3SourceData, SetDefaultS3SourceErrors, SetDefaultS3SourceResponses, SetFlagEnvironmentData, SetFlagEnvironmentErrors, SetFlagEnvironmentResponses, SetPreviewPasswordData, SetPreviewPasswordErrors, SetPreviewPasswordResponses, SetupDnsChallengeData, SetupDnsChallengeErrors, SetupDnsChallengeResponses, SetupDnsData, SetupDnsErrors, SetupDnsResponses, SetupEmailTrackingData, SetupEmailTrackingErrors, SetupEmailTrackingResponses, SetupMfaData, SetupMfaErrors, SetupMfaResponses, SleepEnvironmentData, SleepEnvironmentErrors, SleepEnvironmentResponses, SmokeTestAgentData, SmokeTestAgentErrors, SmokeTestAgentResponses, SourceSandboxData, SourceSandboxErrors, SourceSandboxResponses, StartAnalysisData, StartAnalysisErrors, StartAnalysisResponses, StartContainerData, StartContainerErrors, StartContainerResponses, StartFixData, StartFixErrors, StartFixResponses, StartGitProviderOauthData, StartGitProviderOauthErrors, StartOidcLoginBySlugData, StartOidcLoginBySlugErrors, StartPgUpgradeData, StartPgUpgradeErrors, StartPgUpgradeResponses, StartRestoreData, StartRestoreErrors, StartRestoreResponses, StartServiceData, StartServiceErrors, StartServiceResponses, StatPathData, StatPathErrors, StatPathResponses, StopContainerData, StopContainerErrors, StopContainerResponses, StopSandboxData, StopSandboxErrors, StopSandboxResponses, StopServiceData, StopServiceErrors, StopServiceResponses, StreamContainerMetricsData, StreamContainerMetricsErrors, StreamContainerMetricsResponses, StreamEventsData, StreamEventsErrors, StreamEventsResponses, StreamRunEventsData, StreamRunEventsErrors, StreamRunEventsResponses, SyncRepositoriesData, SyncRepositoriesErrors, SyncRepositoriesResponses, TailDeploymentJobLogsData, TailDeploymentJobLogsErrors, TailLogsData, TailLogsErrors, TailLogsResponses, TeardownDeploymentData, TeardownDeploymentErrors, TeardownDeploymentResponses, TeardownEnvironmentData, TeardownEnvironmentErrors, TeardownEnvironmentResponses, TestNotificationProviderData, TestNotificationProviderErrors, TestNotificationProviderResponses, TestOidcProviderData, TestOidcProviderResponses, TestProviderConnectionData, TestProviderConnectionErrors, TestProviderConnectionResponses, TestProviderData, TestProviderErrors, TestProviderKeyByIdData, TestProviderKeyByIdErrors, TestProviderKeyByIdResponses, TestProviderKeyInlineData, TestProviderKeyInlineErrors, TestProviderKeyInlineResponses, TestProviderResponses, TestS3ConnectionPreviewData, TestS3ConnectionPreviewErrors, TestS3ConnectionPreviewResponses, TestS3SourceConnectionData, TestS3SourceConnectionErrors, TestS3SourceConnectionResponses, TrackClickData, TrackClickErrors, TrackOpenData, TrackOpenErrors, TrackOpenResponses, TriggerAgentData, TriggerAgentErrors, TriggerAgentResponses, TriggerProjectPipelineData, TriggerProjectPipelineErrors, TriggerProjectPipelineResponses, TriggerScanData, TriggerScanErrors, TriggerScanResponses, TriggerServiceHealthCheckData, TriggerServiceHealthCheckErrors, TriggerServiceHealthCheckResponses, TriggerWeeklyDigestData, TriggerWeeklyDigestErrors, TriggerWeeklyDigestResponses, UnlinkServiceFromProjectData, UnlinkServiceFromProjectErrors, UnlinkServiceFromProjectResponses, UpdateAgentData, UpdateAgentErrors, UpdateAgentResponses, UpdateAiProviderData, UpdateAiProviderErrors, UpdateAiProviderResponses, UpdateAlertData, UpdateAlertErrors, UpdateAlertResponses, UpdateAlertRuleData, UpdateAlertRuleErrors, UpdateAlertRuleResponses, UpdateApiKeyData, UpdateApiKeyErrors, UpdateApiKeyResponses, UpdateAutomaticDeployData, UpdateAutomaticDeployErrors, UpdateAutomaticDeployResponses, UpdateBackupScheduleData, UpdateBackupScheduleErrors, UpdateBackupScheduleResponses, UpdateCloudflareProviderData, UpdateCloudflareProviderErrors, UpdateCloudflareProviderResponses, UpdateConnectionTokenData, UpdateConnectionTokenErrors, UpdateConnectionTokenResponses, UpdateCustomDomainData, UpdateCustomDomainErrors, UpdateCustomDomainResponses, UpdateDashboardData, UpdateDashboardErrors, UpdateDashboardResponses, UpdateDeploymentTokenData, UpdateDeploymentTokenErrors, UpdateDeploymentTokenResponses, UpdateEmailProviderData, UpdateEmailProviderErrors, UpdateEmailProviderResponses, UpdateEnvironmentSettingsData, UpdateEnvironmentSettingsErrors, UpdateEnvironmentSettingsResponses, UpdateEnvironmentSubdomainData, UpdateEnvironmentSubdomainErrors, UpdateEnvironmentSubdomainResponses, UpdateEnvironmentVariableData, UpdateEnvironmentVariableErrors, UpdateEnvironmentVariableResponses, UpdateErrorGroupData, UpdateErrorGroupErrors, UpdateErrorGroupResponses, UpdateFlagData, UpdateFlagErrors, UpdateFlagResponses, UpdateFunnelData, UpdateFunnelErrors, UpdateFunnelResponses, UpdateGitProviderCredentialsData, UpdateGitProviderCredentialsErrors, UpdateGitProviderCredentialsResponses, UpdateGitSettingsData, UpdateGitSettingsErrors, UpdateGitSettingsResponses, UpdateGlobalMcpData, UpdateGlobalMcpErrors, UpdateGlobalMcpResponses, UpdateGlobalSkillData, UpdateGlobalSkillErrors, UpdateGlobalSkillResponses, UpdateIncidentStatusData, UpdateIncidentStatusErrors, UpdateIncidentStatusResponses, UpdateIpAccessControlData, UpdateIpAccessControlErrors, UpdateIpAccessControlResponses, UpdateManagedDomainData, UpdateManagedDomainErrors, UpdateManagedDomainResponses, UpdateMcpData, UpdateMcpErrors, UpdateMcpResponses, UpdateNotificationEmailProviderData, UpdateNotificationEmailProviderErrors, UpdateNotificationEmailProviderResponses, UpdateNotificationProviderData, UpdateNotificationProviderErrors, UpdateNotificationProviderResponses, UpdateOidcProviderData, UpdateOidcProviderResponses, UpdatePreferencesData, UpdatePreferencesErrors, UpdatePreferencesResponses, UpdateProjectData, UpdateProjectDeploymentConfigData, UpdateProjectDeploymentConfigErrors, UpdateProjectDeploymentConfigResponses, UpdateProjectErrors, UpdateProjectResponses, UpdateProjectSecretData, UpdateProjectSecretErrors, UpdateProjectSecretResponses, UpdateProjectSettingsData, UpdateProjectSettingsErrors, UpdateProjectSettingsResponses, UpdateProviderData, UpdateProviderErrors, UpdateProviderKeyData, UpdateProviderKeyErrors, UpdateProviderKeyResponses, UpdateProviderResponses, UpdateRouteData, UpdateRouteErrors, UpdateRouteResponses, UpdateS3SourceData, UpdateS3SourceErrors, UpdateS3SourceResponses, UpdateSelfData, UpdateSelfErrors, UpdateSelfResponses, UpdateServiceData, UpdateServiceErrors, UpdateServiceResourcesData, UpdateServiceResourcesErrors, UpdateServiceResourcesResponses, UpdateServiceResponses, UpdateSessionDurationData, UpdateSessionDurationErrors, UpdateSessionDurationResponses, UpdateSettingsData, UpdateSettingsErrors, UpdateSettingsResponses, UpdateSkillData, UpdateSkillErrors, UpdateSkillResponses, UpdateSlackProviderData, UpdateSlackProviderErrors, UpdateSlackProviderResponses, UpdateSpeedMetricsData, UpdateSpeedMetricsErrors, UpdateSpeedMetricsResponses, UpdateTeamData, UpdateTeamErrors, UpdateTeamMemberRoleData, UpdateTeamMemberRoleErrors, UpdateTeamMemberRoleResponses, UpdateTeamResponses, UpdateUserData, UpdateUserErrors, UpdateUserResponses, UpdateWebhookData, UpdateWebhookErrors, UpdateWebhookProviderData, UpdateWebhookProviderErrors, UpdateWebhookProviderResponses, UpdateWebhookResponses, UpgradePreviewGatewayData, UpgradePreviewGatewayResponses, UpgradeServiceData, UpgradeServiceErrors, UpgradeServiceResponses, UploadGlobalSkillData, UploadGlobalSkillErrors, UploadGlobalSkillResponses, UploadReleaseFileData, UploadReleaseFileErrors, UploadReleaseFileResponses, UploadSkillData, UploadSkillErrors, UploadSkillResponses, UploadSourceFileData, UploadSourceFileErrors, UploadSourceFileResponses, UploadSourceMapData, UploadSourceMapErrors, UploadSourceMapResponses, UploadStaticBundleData, UploadStaticBundleErrors, UploadStaticBundleResponses, UpsertSecretData, UpsertSecretErrors, UpsertSecretResponses, ValidateConnectionData, ValidateConnectionErrors, ValidateConnectionResponses, ValidateEmailData, ValidateEmailErrors, ValidateEmailResponses, VerifyAndEnableMfaData, VerifyAndEnableMfaErrors, VerifyAndEnableMfaResponses, VerifyDomainData, VerifyDomainErrors, VerifyDomainResponses, VerifyEmailData, VerifyEmailErrors, VerifyEmailResponses, VerifyManagedDomainData, VerifyManagedDomainErrors, VerifyManagedDomainResponses, VerifyMfaChallengeData, VerifyMfaChallengeErrors, VerifyMfaChallengeResponses, VerifyStepUpData, VerifyStepUpErrors, VerifyStepUpResponses, WakeEnvironmentData, WakeEnvironmentErrors, WakeEnvironmentResponses, WebhookTriggerData, WebhookTriggerErrors, WebhookTriggerResponses, WorkflowDryRunData, WorkflowDryRunErrors, WorkflowDryRunResponses, WriteFileData, WriteFileErrors, WriteFileResponses, WriteFilesData, WriteFilesErrors, WriteFilesResponses } from './types.gen'; -export type Options = Options2 & { +export type Options = Options2 & { /** * You can provide a client instance returned by `createClient()` instead of * individual options. This might be also useful if you want to implement a @@ -15,13 +15,13 @@ export type Options; + meta?: keyof ClientMeta extends never ? Record : ClientMeta; }; /** * Get platform information */ -export const getPlatformInfo = (options?: Options) => (options?.client ?? client).get({ +export const getPlatformInfo = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/.well-known/temps.json', ...options @@ -34,7 +34,7 @@ export const getPlatformInfo = (options?: * We return a response indicating that chunk upload is NOT supported, which forces * sentry-cli to fall back to the standard file-by-file upload. */ -export const chunkUploadOptions = (options: Options) => (options.client ?? client).get({ url: '/0/organizations/{org_slug}/chunk-upload/', ...options }); +export const chunkUploadOptions = (options: Options): RequestResult => (options.client ?? client).get({ url: '/0/organizations/{org_slug}/chunk-upload/', ...options }); /** * Create a release (stub for sentry-cli compatibility). @@ -43,7 +43,7 @@ export const chunkUploadOptions = (options * releases when source maps are uploaded, this is a no-op that returns the * expected response format. */ -export const createRelease = (options: Options) => (options.client ?? client).post({ +export const createRelease = (options: Options): RequestResult => (options.client ?? client).post({ url: '/0/organizations/{org_slug}/releases/', ...options, headers: { @@ -59,7 +59,7 @@ export const createRelease = (options: Opt * both SENTRY_ORG and SENTRY_PROJECT env vars are set. Behaves identically to * the organizations endpoint but validates the project slug. */ -export const createProjectRelease = (options: Options) => (options.client ?? client).post({ +export const createProjectRelease = (options: Options): RequestResult => (options.client ?? client).post({ url: '/0/projects/{org_slug}/{project_slug}/releases/', ...options, headers: { @@ -75,14 +75,14 @@ export const createProjectRelease = (optio * the dateReleased on the release. Since Temps stores source maps independently * of releases, this is a no-op that returns the expected response. */ -export const finalizeProjectRelease = (options: Options) => (options.client ?? client).put({ url: '/0/projects/{org_slug}/{project_slug}/releases/{version}/', ...options }); +export const finalizeProjectRelease = (options: Options): RequestResult => (options.client ?? client).put({ url: '/0/projects/{org_slug}/{project_slug}/releases/{version}/', ...options }); /** * List files for a release. * * Returns all source maps stored for a specific release in sentry-cli compatible format. */ -export const listReleaseFiles = (options: Options) => (options.client ?? client).get({ url: '/0/projects/{org_slug}/{project_slug}/releases/{version}/files/', ...options }); +export const listReleaseFiles = (options: Options): RequestResult => (options.client ?? client).get({ url: '/0/projects/{org_slug}/{project_slug}/releases/{version}/files/', ...options }); /** * Upload a source map file for a release. @@ -93,12 +93,12 @@ export const listReleaseFiles = (options: * The route has a 50 MiB body limit applied at the router level (Fix #4). * A per-field size check provides an additional defense-in-depth layer. */ -export const uploadReleaseFile = (options: Options) => (options.client ?? client).post({ url: '/0/projects/{org_slug}/{project_slug}/releases/{version}/files/', ...options }); +export const uploadReleaseFile = (options: Options): RequestResult => (options.client ?? client).post({ url: '/0/projects/{org_slug}/{project_slug}/releases/{version}/files/', ...options }); /** * Record analytics event */ -export const recordEventMetrics = (options: Options) => (options.client ?? client).post({ +export const recordEventMetrics = (options: Options): RequestResult => (options.client ?? client).post({ url: '/_temps/event', ...options, headers: { @@ -110,7 +110,7 @@ export const recordEventMetrics = (options /** * Add events to existing session replay */ -export const addSessionReplayEvents = (options: Options) => (options.client ?? client).post({ +export const addSessionReplayEvents = (options: Options): RequestResult => (options.client ?? client).post({ url: '/_temps/session-replay/events', ...options, headers: { @@ -122,7 +122,7 @@ export const addSessionReplayEvents = (opt /** * Initialize session replay with metadata */ -export const initSessionReplay = (options: Options) => (options.client ?? client).post({ +export const initSessionReplay = (options: Options): RequestResult => (options.client ?? client).post({ url: '/_temps/session-replay/init', ...options, headers: { @@ -134,7 +134,7 @@ export const initSessionReplay = (options: /** * Record performance metrics from client */ -export const recordSpeedMetrics = (options: Options) => (options.client ?? client).post({ +export const recordSpeedMetrics = (options: Options): RequestResult => (options.client ?? client).post({ url: '/_temps/speed', ...options, headers: { @@ -146,7 +146,7 @@ export const recordSpeedMetrics = (options /** * Update late performance metrics */ -export const updateSpeedMetrics = (options: Options) => (options.client ?? client).post({ +export const updateSpeedMetrics = (options: Options): RequestResult => (options.client ?? client).post({ url: '/_temps/speed/update', ...options, headers: { @@ -155,13 +155,13 @@ export const updateSpeedMetrics = (options } }); -export const getAdminGate = (options?: Options) => (options?.client ?? client).get({ +export const getAdminGate = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/admin/gate-settings', ...options }); -export const patchAdminGate = (options: Options) => (options.client ?? client).patch({ +export const patchAdminGate = (options: Options): RequestResult => (options.client ?? client).patch({ security: [{ scheme: 'bearer', type: 'http' }], url: '/admin/gate-settings', ...options, @@ -171,13 +171,13 @@ export const patchAdminGate = (options: Op } }); -export const listOidcProviders = (options?: Options) => (options?.client ?? client).get({ +export const listOidcProviders = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/admin/oidc/providers', ...options }); -export const createOidcProvider = (options: Options) => (options.client ?? client).post({ +export const createOidcProvider = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/admin/oidc/providers', ...options, @@ -187,13 +187,13 @@ export const createOidcProvider = (options } }); -export const deleteOidcProvider = (options: Options) => (options.client ?? client).delete({ +export const deleteOidcProvider = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/admin/oidc/providers/{provider_id}', ...options }); -export const updateOidcProvider = (options: Options) => (options.client ?? client).patch({ +export const updateOidcProvider = (options: Options): RequestResult => (options.client ?? client).patch({ security: [{ scheme: 'bearer', type: 'http' }], url: '/admin/oidc/providers/{provider_id}', ...options, @@ -203,13 +203,13 @@ export const updateOidcProvider = (options } }); -export const listOidcRoleMappings = (options: Options) => (options.client ?? client).get({ +export const listOidcRoleMappings = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/admin/oidc/providers/{provider_id}/role-mappings', ...options }); -export const createOidcRoleMapping = (options: Options) => (options.client ?? client).post({ +export const createOidcRoleMapping = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/admin/oidc/providers/{provider_id}/role-mappings', ...options, @@ -219,19 +219,19 @@ export const createOidcRoleMapping = (opti } }); -export const testOidcProvider = (options: Options) => (options.client ?? client).post({ +export const testOidcProvider = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/admin/oidc/providers/{provider_id}/test', ...options }); -export const listOidcProviderUsers = (options: Options) => (options.client ?? client).get({ +export const listOidcProviderUsers = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/admin/oidc/providers/{provider_id}/users', ...options }); -export const deleteOidcRoleMapping = (options: Options) => (options.client ?? client).delete({ +export const deleteOidcRoleMapping = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/admin/oidc/role-mappings/{mapping_id}', ...options @@ -248,7 +248,7 @@ export const deleteOidcRoleMapping = (opti * * Accepts any JSON body, which is passed as `user_context` to the agent run. */ -export const webhookTrigger = (options: Options) => (options.client ?? client).post({ +export const webhookTrigger = (options: Options): RequestResult => (options.client ?? client).post({ url: '/agents/webhook/{webhook_id}', ...options, headers: { @@ -262,25 +262,25 @@ export const webhookTrigger = (options: Op * first, annotated with project name/slug. Powers the unified "all chats" * switcher in the AI assistant dock. */ -export const listAllConversations = (options?: Options) => (options?.client ?? client).get({ +export const listAllConversations = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/ai/conversations', ...options }); -export const getPricing = (options?: Options) => (options?.client ?? client).get({ +export const getPricing = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/ai/pricing', ...options }); -export const listProviderKeys = (options?: Options) => (options?.client ?? client).get({ +export const listProviderKeys = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/ai/providers', ...options }); -export const createProviderKey = (options: Options) => (options.client ?? client).post({ +export const createProviderKey = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/ai/providers', ...options, @@ -290,7 +290,7 @@ export const createProviderKey = (options: } }); -export const testProviderKeyInline = (options: Options) => (options.client ?? client).post({ +export const testProviderKeyInline = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/ai/providers/test', ...options, @@ -300,13 +300,13 @@ export const testProviderKeyInline = (opti } }); -export const deleteProviderKey = (options: Options) => (options.client ?? client).delete({ +export const deleteProviderKey = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/ai/providers/{id}', ...options }); -export const updateProviderKey = (options: Options) => (options.client ?? client).patch({ +export const updateProviderKey = (options: Options): RequestResult => (options.client ?? client).patch({ security: [{ scheme: 'bearer', type: 'http' }], url: '/ai/providers/{id}', ...options, @@ -316,55 +316,55 @@ export const updateProviderKey = (options: } }); -export const testProviderKeyById = (options: Options) => (options.client ?? client).post({ +export const testProviderKeyById = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/ai/providers/{id}/test', ...options }); -export const getUsageByProvider = (options?: Options) => (options?.client ?? client).get({ +export const getUsageByProvider = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/ai/usage/by-provider', ...options }); -export const getConversations = (options?: Options) => (options?.client ?? client).get({ +export const getConversations = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/ai/usage/conversations', ...options }); -export const getConversationDetail = (options: Options) => (options.client ?? client).get({ +export const getConversationDetail = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/ai/usage/conversations/{conversation_id}', ...options }); -export const getUsageRecent = (options?: Options) => (options?.client ?? client).get({ +export const getUsageRecent = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/ai/usage/recent', ...options }); -export const getUsageSummary = (options?: Options) => (options?.client ?? client).get({ +export const getUsageSummary = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/ai/usage/summary', ...options }); -export const getUsageTimeseries = (options?: Options) => (options?.client ?? client).get({ +export const getUsageTimeseries = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/ai/usage/timeseries', ...options }); -export const getUsageTopModels = (options?: Options) => (options?.client ?? client).get({ +export const getUsageTopModels = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/ai/usage/top-models', ...options }); -export const chatCompletions = (options: Options) => (options.client ?? client).post({ +export const chatCompletions = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/ai/v1/chat/completions', ...options, @@ -374,7 +374,7 @@ export const chatCompletions = (options: O } }); -export const embeddings = (options: Options) => (options.client ?? client).post({ +export const embeddings = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/ai/v1/embeddings', ...options, @@ -384,7 +384,7 @@ export const embeddings = (options: Option } }); -export const listModels = (options?: Options) => (options?.client ?? client).get({ +export const listModels = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/ai/v1/models', ...options @@ -393,7 +393,7 @@ export const listModels = (options?: Optio /** * Get detailed active visitors */ -export const getAnalyticsActiveVisitors = (options: Options) => (options.client ?? client).get({ +export const getAnalyticsActiveVisitors = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/analytics/active-visitors', ...options @@ -402,7 +402,7 @@ export const getAnalyticsActiveVisitors = /** * Get detailed analytics for a specific event */ -export const getEventDetail = (options: Options) => (options.client ?? client).get({ +export const getEventDetail = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/analytics/event-detail', ...options @@ -411,7 +411,7 @@ export const getEventDetail = (options: Op /** * Get paginated list of raw occurrences of a specific event, including custom JSON properties */ -export const getEventEntries = (options: Options) => (options.client ?? client).get({ +export const getEventEntries = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/analytics/event-entries', ...options @@ -420,13 +420,13 @@ export const getEventEntries = (options: O /** * Get paginated list of visitors who triggered a specific event */ -export const getEventVisitors = (options: Options) => (options.client ?? client).get({ +export const getEventVisitors = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/analytics/event-visitors', ...options }); -export const getAnalyticsEventsCount = (options: Options) => (options.client ?? client).get({ +export const getAnalyticsEventsCount = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/analytics/events', ...options @@ -435,13 +435,13 @@ export const getAnalyticsEventsCount = (op /** * Get general statistics across all projects for a time frame */ -export const getGeneralStats = (options: Options) => (options.client ?? client).get({ +export const getGeneralStats = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/analytics/general-stats', ...options }); -export const checkAnalyticsHasEvents = (options: Options) => (options.client ?? client).get({ +export const checkAnalyticsHasEvents = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/analytics/has-events', ...options @@ -450,7 +450,7 @@ export const checkAnalyticsHasEvents = (op /** * Get list of currently live visitors from visitor table */ -export const getLiveVisitorsList = (options: Options) => (options.client ?? client).get({ +export const getLiveVisitorsList = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/analytics/live-visitors', ...options @@ -459,13 +459,13 @@ export const getLiveVisitorsList = (option /** * Get page flow analytics: entry pages, exit pages, drop-off points, and page transitions */ -export const getPageFlow = (options: Options) => (options.client ?? client).get({ +export const getPageFlow = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/analytics/page-flow', ...options }); -export const getPageHourlySessions = (options: Options) => (options.client ?? client).get({ +export const getPageHourlySessions = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/analytics/page-hourly-sessions', ...options @@ -475,7 +475,7 @@ export const getPageHourlySessions = (opti * Get detailed analytics for a specific page path * Returns visitors, page views, activity over time, geographic distribution, and referrers */ -export const getPagePathDetail = (options: Options) => (options.client ?? client).get({ +export const getPagePathDetail = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/analytics/page-path-detail', ...options @@ -484,19 +484,19 @@ export const getPagePathDetail = (options: /** * Get individual visitor sessions for a specific page path */ -export const getPagePathVisitors = (options: Options) => (options.client ?? client).get({ +export const getPagePathVisitors = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/analytics/page-path-visitors', ...options }); -export const getPagePaths = (options: Options) => (options.client ?? client).get({ +export const getPagePaths = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/analytics/page-paths', ...options }); -export const getPagePathsSparklines = (options: Options) => (options.client ?? client).get({ +export const getPagePathsSparklines = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/analytics/page-paths-sparklines', ...options @@ -505,7 +505,7 @@ export const getPagePathsSparklines = (opt /** * Get recent activity events for real-time activity feed */ -export const getRecentActivity = (options: Options) => (options.client ?? client).get({ +export const getRecentActivity = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/analytics/recent-activity', ...options @@ -514,19 +514,19 @@ export const getRecentActivity = (options: /** * Get detailed information about a specific session including events and request logs */ -export const getSessionDetails = (options: Options) => (options.client ?? client).get({ +export const getSessionDetails = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/analytics/sessions/{session_id}', ...options }); -export const getAnalyticsSessionEvents = (options: Options) => (options.client ?? client).get({ +export const getAnalyticsSessionEvents = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/analytics/sessions/{session_id}/events', ...options }); -export const getSessionLogs = (options: Options) => (options.client ?? client).get({ +export const getSessionLogs = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/analytics/sessions/{session_id}/logs', ...options @@ -539,7 +539,7 @@ export const getSessionLogs = (options: Op * segment minus its own filter, so a selected value never collapses its * own dropdown. */ -export const getVisitorFacets = (options: Options) => (options.client ?? client).get({ +export const getVisitorFacets = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/analytics/visitor-facets', ...options @@ -548,7 +548,7 @@ export const getVisitorFacets = (options: /** * Get list of visitors with summary information */ -export const getVisitors = (options: Options) => (options.client ?? client).get({ +export const getVisitors = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/analytics/visitors', ...options @@ -557,7 +557,7 @@ export const getVisitors = (options: Optio /** * Get visitor by GUID with geolocation data */ -export const getVisitorByGuid = (options: Options) => (options.client ?? client).get({ +export const getVisitorByGuid = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/analytics/visitors/guid/{visitor_id}', ...options @@ -566,7 +566,7 @@ export const getVisitorByGuid = (options: /** * Get visitor by numeric ID with geolocation data */ -export const getVisitorById = (options: Options) => (options.client ?? client).get({ +export const getVisitorById = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/analytics/visitors/id/{id}', ...options @@ -575,13 +575,13 @@ export const getVisitorById = (options: Op /** * Get detailed information about a specific visitor by numeric ID */ -export const getVisitorDetails = (options: Options) => (options.client ?? client).get({ +export const getVisitorDetails = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/analytics/visitors/{visitor_id}', ...options }); -export const enrichVisitor = (options: Options) => (options.client ?? client).put({ +export const enrichVisitor = (options: Options): RequestResult => (options.client ?? client).put({ security: [{ scheme: 'bearer', type: 'http' }], url: '/analytics/visitors/{visitor_id}/enrich', ...options, @@ -594,7 +594,7 @@ export const enrichVisitor = (options: Opt /** * Get visitor record from database */ -export const getVisitorInfo = (options: Options) => (options.client ?? client).get({ +export const getVisitorInfo = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/analytics/visitors/{visitor_id}/info', ...options @@ -603,7 +603,7 @@ export const getVisitorInfo = (options: Op /** * Get the complete visitor journey: all events across all sessions, grouped by session */ -export const getVisitorJourney = (options: Options) => (options.client ?? client).get({ +export const getVisitorJourney = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/analytics/visitors/{visitor_id}/journey', ...options @@ -612,7 +612,7 @@ export const getVisitorJourney = (options: /** * Get all sessions for a specific visitor by numeric ID */ -export const getAnalyticsVisitorSessions = (options: Options) => (options.client ?? client).get({ +export const getAnalyticsVisitorSessions = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/analytics/visitors/{visitor_id}/sessions', ...options @@ -621,19 +621,19 @@ export const getAnalyticsVisitorSessions = (options: Options) => (options.client ?? client).get({ +export const getVisitorStats = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/analytics/visitors/{visitor_id}/stats', ...options }); -export const listApiKeys = (options?: Options) => (options?.client ?? client).get({ +export const listApiKeys = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/api-keys', ...options }); -export const createApiKey = (options: Options) => (options.client ?? client).post({ +export const createApiKey = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/api-keys', ...options, @@ -643,25 +643,25 @@ export const createApiKey = (options: Opti } }); -export const getApiKeyPermissions = (options?: Options) => (options?.client ?? client).get({ +export const getApiKeyPermissions = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/api-keys/permissions', ...options }); -export const deleteApiKey = (options: Options) => (options.client ?? client).delete({ +export const deleteApiKey = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/api-keys/{id}', ...options }); -export const getApiKey = (options: Options) => (options.client ?? client).get({ +export const getApiKey = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/api-keys/{id}', ...options }); -export const updateApiKey = (options: Options) => (options.client ?? client).put({ +export const updateApiKey = (options: Options): RequestResult => (options.client ?? client).put({ security: [{ scheme: 'bearer', type: 'http' }], url: '/api-keys/{id}', ...options, @@ -671,25 +671,25 @@ export const updateApiKey = (options: Opti } }); -export const activateApiKey = (options: Options) => (options.client ?? client).post({ +export const activateApiKey = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/api-keys/{id}/activate', ...options }); -export const deactivateApiKey = (options: Options) => (options.client ?? client).post({ +export const deactivateApiKey = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/api-keys/{id}/deactivate', ...options }); -export const rotateApiKey = (options: Options) => (options.client ?? client).post({ +export const rotateApiKey = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/api-keys/{id}/rotate', ...options }); -export const cliDeviceApprove = (options: Options) => (options.client ?? client).post({ +export const cliDeviceApprove = (options: Options): RequestResult => (options.client ?? client).post({ url: '/auth/cli/device/approve', ...options, headers: { @@ -698,7 +698,7 @@ export const cliDeviceApprove = (options: } }); -export const cliDeviceDeny = (options: Options) => (options.client ?? client).post({ +export const cliDeviceDeny = (options: Options): RequestResult => (options.client ?? client).post({ url: '/auth/cli/device/deny', ...options, headers: { @@ -707,9 +707,9 @@ export const cliDeviceDeny = (options: Opt } }); -export const cliDeviceLookup = (options: Options) => (options.client ?? client).get({ url: '/auth/cli/device/lookup', ...options }); +export const cliDeviceLookup = (options: Options): RequestResult => (options.client ?? client).get({ url: '/auth/cli/device/lookup', ...options }); -export const cliDevicePoll = (options: Options) => (options.client ?? client).post({ +export const cliDevicePoll = (options: Options): RequestResult => (options.client ?? client).post({ url: '/auth/cli/device/poll', ...options, headers: { @@ -718,7 +718,7 @@ export const cliDevicePoll = (options: Opt } }); -export const cliDeviceStart = (options: Options) => (options.client ?? client).post({ +export const cliDeviceStart = (options: Options): RequestResult => (options.client ?? client).post({ url: '/auth/cli/device/start', ...options, headers: { @@ -727,15 +727,15 @@ export const cliDeviceStart = (options: Op } }); -export const cliLogout = (options?: Options) => (options?.client ?? client).post({ +export const cliLogout = (options?: Options): RequestResult => (options?.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/auth/cli/logout', ...options }); -export const emailStatus = (options?: Options) => (options?.client ?? client).get({ url: '/auth/email-status', ...options }); +export const emailStatus = (options?: Options): RequestResult => (options?.client ?? client).get({ url: '/auth/email-status', ...options }); -export const login = (options: Options) => (options.client ?? client).post({ +export const login = (options: Options): RequestResult => (options.client ?? client).post({ url: '/auth/login', ...options, headers: { @@ -744,22 +744,13 @@ export const login = (options: Options(options?: Options) => (options?.client ?? client).get({ url: '/auth/oidc/callback', ...options }); +export const oidcCallback = (options?: Options): RequestResult => (options?.client ?? client).get({ url: '/auth/oidc/callback', ...options }); -export const startOidcLoginBySlug = (options: Options) => (options.client ?? client).get({ url: '/auth/oidc/login/{slug}', ...options }); +export const startOidcLoginBySlug = (options: Options): RequestResult => (options.client ?? client).get({ url: '/auth/oidc/login/{slug}', ...options }); -export const listPublicProviders = (options?: Options) => (options?.client ?? client).get({ url: '/auth/oidc/providers', ...options }); +export const listPublicProviders = (options?: Options): RequestResult => (options?.client ?? client).get({ url: '/auth/oidc/providers', ...options }); -export const changeRequiredPassword = (options: Options) => (options.client ?? client).post({ - url: '/auth/password-change-required', - ...options, - headers: { - 'Content-Type': 'application/json', - ...options.headers - } -}); - -export const requestPasswordReset = (options: Options) => (options.client ?? client).post({ +export const requestPasswordReset = (options: Options): RequestResult => (options.client ?? client).post({ url: '/auth/password-reset/request', ...options, headers: { @@ -768,7 +759,7 @@ export const requestPasswordReset = (optio } }); -export const resetPassword = (options: Options) => (options.client ?? client).post({ +export const resetPassword = (options: Options): RequestResult => (options.client ?? client).post({ url: '/auth/password-reset/verify', ...options, headers: { @@ -777,7 +768,7 @@ export const resetPassword = (options: Opt } }); -export const verifyStepUp = (options: Options) => (options.client ?? client).post({ +export const verifyStepUp = (options: Options): RequestResult => (options.client ?? client).post({ url: '/auth/step-up', ...options, headers: { @@ -786,9 +777,9 @@ export const verifyStepUp = (options: Opti } }); -export const verifyEmail = (options: Options) => (options.client ?? client).get({ url: '/auth/verify-email', ...options }); +export const verifyEmail = (options: Options): RequestResult => (options.client ?? client).get({ url: '/auth/verify-email', ...options }); -export const verifyMfaChallenge = (options: Options) => (options.client ?? client).post({ +export const verifyMfaChallenge = (options: Options): RequestResult => (options.client ?? client).post({ url: '/auth/verify-mfa', ...options, headers: { @@ -813,7 +804,7 @@ export const verifyMfaChallenge = (options * more than 1 hour. The runner never claimed the job. Usually means the * runner task is dead or the runner concurrency cap is too low. */ -export const listBackupAlerts = (options?: Options) => (options?.client ?? client).get({ +export const listBackupAlerts = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/backups/alerts', ...options @@ -822,7 +813,7 @@ export const listBackupAlerts = (options?: /** * Preview or run retention using each selected schedule's configured retention days. */ -export const cleanupExpiredBackups = (options: Options) => (options.client ?? client).post({ +export const cleanupExpiredBackups = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/backups/cleanup', ...options, @@ -840,7 +831,7 @@ export const cleanupExpiredBackups = (opti * rows are inserted, and a `backup_jobs` row is enqueued for the resolved * engine. Poll `GET /backups/{id}` to observe `pending → running → completed`. */ -export const runExternalServiceBackup = (options: Options) => (options.client ?? client).post({ +export const runExternalServiceBackup = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/backups/external-services/{id}/run', ...options, @@ -857,7 +848,7 @@ export const runExternalServiceBackup = (o * Completes in <100 ms regardless of S3 endpoint latency because it * never touches S3. */ -export const listExternalServiceBackups = (options: Options) => (options.client ?? client).get({ +export const listExternalServiceBackups = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/backups/external-services/{service_id}/backups', ...options @@ -867,7 +858,7 @@ export const listExternalServiceBackups = * List the schedules that target a specific external service. Useful for * the service detail page ("which schedules back this DB up?"). */ -export const listServiceSchedules = (options: Options) => (options.client ?? client).get({ +export const listServiceSchedules = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/backups/external-services/{service_id}/schedules', ...options @@ -876,7 +867,7 @@ export const listServiceSchedules = (optio /** * List all S3 sources */ -export const listS3Sources = (options?: Options) => (options?.client ?? client).get({ +export const listS3Sources = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/backups/s3-sources', ...options @@ -885,7 +876,7 @@ export const listS3Sources = (options?: Op /** * Create a new S3 source */ -export const createS3Source = (options: Options) => (options.client ?? client).post({ +export const createS3Source = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/backups/s3-sources', ...options, @@ -899,7 +890,7 @@ export const createS3Source = (options: Op * Test S3 connectivity against a prospective source configuration (before creating it). * The credentials are NOT persisted. Useful for validating the form in the UI. */ -export const testS3ConnectionPreview = (options: Options) => (options.client ?? client).post({ +export const testS3ConnectionPreview = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/backups/s3-sources/test', ...options, @@ -912,7 +903,7 @@ export const testS3ConnectionPreview = (op /** * Delete an S3 source */ -export const deleteS3Source = (options: Options) => (options.client ?? client).delete({ +export const deleteS3Source = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/backups/s3-sources/{id}', ...options @@ -921,7 +912,7 @@ export const deleteS3Source = (options: Op /** * Get an S3 source by ID */ -export const getS3Source = (options: Options) => (options.client ?? client).get({ +export const getS3Source = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/backups/s3-sources/{id}', ...options @@ -930,7 +921,7 @@ export const getS3Source = (options: Optio /** * Update an S3 source */ -export const updateS3Source = (options: Options) => (options.client ?? client).patch({ +export const updateS3Source = (options: Options): RequestResult => (options.client ?? client).patch({ security: [{ scheme: 'bearer', type: 'http' }], url: '/backups/s3-sources/{id}', ...options, @@ -943,7 +934,7 @@ export const updateS3Source = (options: Op /** * List all backups in an S3 source */ -export const listSourceBackups = (options: Options) => (options.client ?? client).get({ +export const listSourceBackups = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/backups/s3-sources/{id}/backups', ...options @@ -958,7 +949,7 @@ export const listSourceBackups = (options: * `ControlPlaneEngine`. Poll `GET /backups/{id}` to observe * `pending → running → completed`. */ -export const runBackupForSource = (options: Options) => (options.client ?? client).post({ +export const runBackupForSource = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/backups/s3-sources/{id}/run', ...options, @@ -972,7 +963,7 @@ export const runBackupForSource = (options * Mark an S3 source as the default. All new backups/schedules/services that do not * explicitly reference a source will use the default. Returns the updated source. */ -export const setDefaultS3Source = (options: Options) => (options.client ?? client).post({ +export const setDefaultS3Source = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/backups/s3-sources/{id}/set-default', ...options @@ -981,7 +972,7 @@ export const setDefaultS3Source = (options /** * Test connectivity to an existing S3 source using its stored credentials. */ -export const testS3SourceConnection = (options: Options) => (options.client ?? client).post({ +export const testS3SourceConnection = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/backups/s3-sources/{id}/test', ...options @@ -996,7 +987,7 @@ export const testS3SourceConnection = (opt * children remain. Idempotent: cancelling a run with no live children is * a 200 with `cancelled = 0`. */ -export const cancelScheduleRun = (options: Options) => (options.client ?? client).post({ +export const cancelScheduleRun = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/backups/schedule-runs/{id}/cancel', ...options @@ -1011,7 +1002,7 @@ export const cancelScheduleRun = (options: * * `page_size` defaults to 50 and is capped at 200. */ -export const listScheduleRunJobs = (options: Options) => (options.client ?? client).get({ +export const listScheduleRunJobs = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/backups/schedule-runs/{id}/jobs', ...options @@ -1020,7 +1011,7 @@ export const listScheduleRunJobs = (option /** * List all backup schedules */ -export const listBackupSchedules = (options?: Options) => (options?.client ?? client).get({ +export const listBackupSchedules = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/backups/schedules', ...options @@ -1029,7 +1020,7 @@ export const listBackupSchedules = (option /** * Create a new backup schedule */ -export const createBackupSchedule = (options: Options) => (options.client ?? client).post({ +export const createBackupSchedule = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/backups/schedules', ...options, @@ -1042,7 +1033,7 @@ export const createBackupSchedule = (optio /** * Delete a backup schedule */ -export const deleteBackupSchedule = (options: Options) => (options.client ?? client).delete({ +export const deleteBackupSchedule = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/backups/schedules/{id}', ...options @@ -1051,7 +1042,7 @@ export const deleteBackupSchedule = (optio /** * Get a backup schedule by ID */ -export const getBackupSchedule = (options: Options) => (options.client ?? client).get({ +export const getBackupSchedule = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/backups/schedules/{id}', ...options @@ -1065,7 +1056,7 @@ export const getBackupSchedule = (options: * unchanged. If `schedule_expression` is changed, `next_run` is * recomputed automatically. */ -export const updateBackupSchedule = (options: Options) => (options.client ?? client).patch({ +export const updateBackupSchedule = (options: Options): RequestResult => (options.client ?? client).patch({ security: [{ scheme: 'bearer', type: 'http' }], url: '/backups/schedules/{id}', ...options, @@ -1078,7 +1069,7 @@ export const updateBackupSchedule = (optio /** * List backups for a schedule */ -export const listBackupsForSchedule = (options: Options) => (options.client ?? client).get({ +export const listBackupsForSchedule = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/backups/schedules/{id}/backups', ...options @@ -1087,7 +1078,7 @@ export const listBackupsForSchedule = (opt /** * Disable a backup schedule */ -export const disableBackupSchedule = (options: Options) => (options.client ?? client).patch({ +export const disableBackupSchedule = (options: Options): RequestResult => (options.client ?? client).patch({ security: [{ scheme: 'bearer', type: 'http' }], url: '/backups/schedules/{id}/disable', ...options @@ -1096,7 +1087,7 @@ export const disableBackupSchedule = (opti /** * Enable a backup schedule */ -export const enableBackupSchedule = (options: Options) => (options.client ?? client).patch({ +export const enableBackupSchedule = (options: Options): RequestResult => (options.client ?? client).patch({ security: [{ scheme: 'bearer', type: 'http' }], url: '/backups/schedules/{id}/enable', ...options @@ -1111,7 +1102,7 @@ export const enableBackupSchedule = (optio * `schedule_run_id` and the list of enqueued jobs. Returns `409 Conflict` if * a run for this schedule is already in flight or if the schedule is disabled. */ -export const runScheduleNow = (options: Options) => (options.client ?? client).post({ +export const runScheduleNow = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/backups/schedules/{id}/run', ...options @@ -1127,7 +1118,7 @@ export const runScheduleNow = (options: Op * * Use `GET /backups/schedule-runs/{run_id}/jobs` to drill into a single run. */ -export const listScheduleRuns = (options: Options) => (options.client ?? client).get({ +export const listScheduleRuns = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/backups/schedules/{id}/runs', ...options @@ -1136,7 +1127,7 @@ export const listScheduleRuns = (options: /** * List the external services attached to a backup schedule. */ -export const listScheduleServices = (options: Options) => (options.client ?? client).get({ +export const listScheduleServices = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/backups/schedules/{id}/services', ...options @@ -1148,7 +1139,7 @@ export const listScheduleServices = (optio * DO NOTHING`). Returns the count of newly inserted rows + the total * membership after the operation. */ -export const attachScheduleServices = (options: Options) => (options.client ?? client).post({ +export const attachScheduleServices = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/backups/schedules/{id}/services', ...options, @@ -1162,7 +1153,7 @@ export const attachScheduleServices = (opt * Detach a single external service from a backup schedule. Idempotent — * returns `204` whether or not a row was actually removed. */ -export const detachScheduleService = (options: Options) => (options.client ?? client).delete({ +export const detachScheduleService = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/backups/schedules/{id}/services/{service_id}', ...options @@ -1171,7 +1162,7 @@ export const detachScheduleService = (opti /** * Permanently delete one terminal backup from object storage and the database. */ -export const deleteBackup = (options: Options) => (options.client ?? client).delete({ +export const deleteBackup = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/backups/{id}', ...options @@ -1180,7 +1171,7 @@ export const deleteBackup = (options: Opti /** * Get a backup by ID */ -export const getBackup = (options: Options) => (options.client ?? client).get({ +export const getBackup = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/backups/{id}', ...options @@ -1195,7 +1186,7 @@ export const getBackup = (options: Options * engine exits cleanly and rollback reaps the sidecar. Idempotent: cancelling * an already-terminal backup is a 200 with `cancelled = 0`. */ -export const cancelBackup = (options: Options) => (options.client ?? client).post({ +export const cancelBackup = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/backups/{id}/cancel', ...options @@ -1212,7 +1203,7 @@ export const cancelBackup = (options: Opti * backup exists but has no children (e.g. control-plane backups). * Returns 404 when the parent backup itself does not exist. */ -export const listBackupChildren = (options: Options) => (options.client ?? client).get({ +export const listBackupChildren = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/backups/{id}/children', ...options @@ -1221,7 +1212,7 @@ export const listBackupChildren = (options /** * Delete blobs */ -export const blobDelete = (options: Options) => (options.client ?? client).delete({ +export const blobDelete = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/blob', ...options, @@ -1234,7 +1225,7 @@ export const blobDelete = (options: Option /** * List blobs */ -export const blobList = (options?: Options) => (options?.client ?? client).get({ +export const blobList = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/blob', ...options @@ -1243,7 +1234,7 @@ export const blobList = (options?: Options /** * Upload a blob */ -export const blobPut = (options: Options) => (options.client ?? client).post({ +export const blobPut = (options: Options): RequestResult => (options.client ?? client).post({ bodySerializer: null, security: [{ scheme: 'bearer', type: 'http' }], url: '/blob', @@ -1257,7 +1248,7 @@ export const blobPut = (options: Options(options: Options) => (options.client ?? client).post({ +export const blobCopy = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/blob/copy', ...options, @@ -1270,7 +1261,7 @@ export const blobCopy = (options: Options< /** * Disable Blob service */ -export const blobDisable = (options?: Options) => (options?.client ?? client).delete({ +export const blobDisable = (options?: Options): RequestResult => (options?.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/blob/disable', ...options @@ -1279,7 +1270,7 @@ export const blobDisable = (options?: Opti /** * Enable Blob service */ -export const blobEnable = (options: Options) => (options.client ?? client).post({ +export const blobEnable = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/blob/enable', ...options, @@ -1292,7 +1283,7 @@ export const blobEnable = (options: Option /** * Get Blob service status */ -export const blobStatus = (options?: Options) => (options?.client ?? client).get({ +export const blobStatus = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/blob/status', ...options @@ -1301,7 +1292,7 @@ export const blobStatus = (options?: Optio /** * Update Blob service configuration */ -export const blobUpdate = (options: Options) => (options.client ?? client).patch({ +export const blobUpdate = (options: Options): RequestResult => (options.client ?? client).patch({ security: [{ scheme: 'bearer', type: 'http' }], url: '/blob/update', ...options, @@ -1314,7 +1305,7 @@ export const blobUpdate = (options: Option /** * Download a blob */ -export const blobDownload = (options: Options) => (options.client ?? client).get({ +export const blobDownload = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/blob/{project_id}/{path}', ...options @@ -1323,47 +1314,19 @@ export const blobDownload = (options: Opti /** * Get blob metadata */ -export const blobHead = (options: Options) => (options.client ?? client).head({ +export const blobHead = (options: Options): RequestResult => (options.client ?? client).head({ security: [{ scheme: 'bearer', type: 'http' }], url: '/blob/{project_id}/{path}', ...options }); -export const disconnectCloud = (options?: Options) => (options?.client ?? client).delete({ - security: [{ scheme: 'bearer', type: 'http' }], - url: '/cloud', - ...options -}); - -export const getCloudCapability = (options?: Options) => (options?.client ?? client).get({ - security: [{ scheme: 'bearer', type: 'http' }], - url: '/cloud/capability', - ...options -}); - -export const enrollCloud = (options: Options) => (options.client ?? client).post({ - security: [{ scheme: 'bearer', type: 'http' }], - url: '/cloud/enroll', - ...options, - headers: { - 'Content-Type': 'application/json', - ...options.headers - } -}); - -export const getCloudStatus = (options?: Options) => (options?.client ?? client).get({ - security: [{ scheme: 'bearer', type: 'http' }], - url: '/cloud/status', - ...options -}); - /** * Get dashboard analytics for multiple projects in a single batch request * * Returns unique visitor counts and hourly sparkline data for all requested projects * using only 2 SQL queries instead of 2×N per-project queries. */ -export const getDashboardProjectsAnalytics = (options: Options) => (options.client ?? client).get({ +export const getDashboardProjectsAnalytics = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/dashboard/projects-analytics', ...options @@ -1373,13 +1336,13 @@ export const getDashboardProjectsAnalytics = (options?: Options) => (options?.client ?? client).get({ +export const getActivityGraph = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/deployments/activity-graph', ...options }); -export const getScanByDeployment = (options: Options) => (options.client ?? client).get({ +export const getScanByDeployment = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/deployments/{deployment_id}/vulnerability-scan', ...options @@ -1388,7 +1351,7 @@ export const getScanByDeployment = (option /** * Fetch a time-series range for a single metric on a deployment. */ -export const deploymentMetricsGetRange = (options: Options) => (options.client ?? client).get({ +export const deploymentMetricsGetRange = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/deployments/{id}/metrics', ...options @@ -1400,7 +1363,7 @@ export const deploymentMetricsGetRange = ( * When `enabled=true`, seeds the default container alert rules for the * deployment via [`temps_monitoring::seed_default_container_rules`] (idempotent). */ -export const deploymentMetricsToggle = (options: Options) => (options.client ?? client).patch({ +export const deploymentMetricsToggle = (options: Options): RequestResult => (options.client ?? client).patch({ security: [{ scheme: 'bearer', type: 'http' }], url: '/deployments/{id}/metrics/enable', ...options, @@ -1413,7 +1376,7 @@ export const deploymentMetricsToggle = (op /** * Fetch the most-recent metric values for a deployment. */ -export const deploymentMetricsGetLatest = (options: Options) => (options.client ?? client).get({ +export const deploymentMetricsGetLatest = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/deployments/{id}/metrics/latest', ...options @@ -1422,7 +1385,7 @@ export const deploymentMetricsGetLatest = /** * List all DNS providers */ -export const listDnsProviders = (options?: Options) => (options?.client ?? client).get({ +export const listDnsProviders = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/dns-providers', ...options @@ -1434,7 +1397,7 @@ export const listDnsProviders = (options?: * The provider's credentials will be tested before creation. * If the connection test fails, the provider will not be created. */ -export const createDnsProvider = (options: Options) => (options.client ?? client).post({ +export const createDnsProvider = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/dns-providers', ...options, @@ -1447,7 +1410,7 @@ export const createDnsProvider = (options: /** * Delete a DNS provider */ -export const deleteDnsProvider = (options: Options) => (options.client ?? client).delete({ +export const deleteDnsProvider = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/dns-providers/{id}', ...options @@ -1456,7 +1419,7 @@ export const deleteDnsProvider = (options: /** * Get a DNS provider by ID */ -export const getDnsProvider = (options: Options) => (options.client ?? client).get({ +export const getDnsProvider = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/dns-providers/{id}', ...options @@ -1470,7 +1433,7 @@ export const getDnsProvider = (options: Op * for Pebble, its target URL) could be swapped for something invalid or * unsafe without ever going through validation. */ -export const updateProvider = (options: Options) => (options.client ?? client).put({ +export const updateProvider = (options: Options): RequestResult => (options.client ?? client).put({ security: [{ scheme: 'bearer', type: 'http' }], url: '/dns-providers/{id}', ...options, @@ -1483,7 +1446,7 @@ export const updateProvider = (options: Op /** * List managed domains for a provider */ -export const listManagedDomains = (options: Options) => (options.client ?? client).get({ +export const listManagedDomains = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/dns-providers/{id}/domains', ...options @@ -1492,7 +1455,7 @@ export const listManagedDomains = (options /** * Add a managed domain to a provider */ -export const addManagedDomain = (options: Options) => (options.client ?? client).post({ +export const addManagedDomain = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/dns-providers/{id}/domains', ...options, @@ -1505,7 +1468,7 @@ export const addManagedDomain = (options: /** * Test provider connection */ -export const testProviderConnection = (options: Options) => (options.client ?? client).post({ +export const testProviderConnection = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/dns-providers/{id}/test', ...options @@ -1514,7 +1477,7 @@ export const testProviderConnection = (opt /** * List zones available in a provider */ -export const listProviderZones = (options: Options) => (options.client ?? client).get({ +export const listProviderZones = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/dns-providers/{id}/zones', ...options @@ -1523,7 +1486,7 @@ export const listProviderZones = (options: /** * Remove a managed domain */ -export const removeManagedDomain = (options: Options) => (options.client ?? client).delete({ +export const removeManagedDomain = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/dns-providers/{provider_id}/domains/{domain}', ...options @@ -1532,7 +1495,7 @@ export const removeManagedDomain = (option /** * Update a managed domain's settings (hostname mode, sync opt-in, auto-manage). */ -export const updateManagedDomain = (options: Options) => (options.client ?? client).patch({ +export const updateManagedDomain = (options: Options): RequestResult => (options.client ?? client).patch({ security: [{ scheme: 'bearer', type: 'http' }], url: '/dns-providers/{provider_id}/domains/{domain}', ...options, @@ -1546,7 +1509,7 @@ export const updateManagedDomain = (option * Apply a hostname mode to a managed domain (persist + optional DNS sync + * route reload). */ -export const applyHostnameMode = (options: Options) => (options.client ?? client).post({ +export const applyHostnameMode = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/dns-providers/{provider_id}/domains/{domain}/apply-hostname-mode', ...options, @@ -1559,7 +1522,7 @@ export const applyHostnameMode = (options: /** * Preview the impact of switching a managed domain's hostname mode. */ -export const previewHostnameMode = (options: Options) => (options.client ?? client).get({ +export const previewHostnameMode = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/dns-providers/{provider_id}/domains/{domain}/hostname-preview', ...options @@ -1568,7 +1531,7 @@ export const previewHostnameMode = (option /** * Verify a managed domain */ -export const verifyManagedDomain = (options: Options) => (options.client ?? client).post({ +export const verifyManagedDomain = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/dns-providers/{provider_id}/domains/{domain}/verify', ...options @@ -1577,12 +1540,12 @@ export const verifyManagedDomain = (option /** * Lookup DNS A records for a domain */ -export const lookupDnsARecords = (options: Options) => (options.client ?? client).get({ url: '/dns/lookup', ...options }); +export const lookupDnsARecords = (options: Options): RequestResult => (options.client ?? client).get({ url: '/dns/lookup', ...options }); /** * List all domains */ -export const listDomains = (options?: Options) => (options?.client ?? client).get({ +export const listDomains = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/domains', ...options @@ -1597,7 +1560,7 @@ export const listDomains = (options?: Opti * - **HTTP-01**: Validates domain ownership by placing a file on your web server at `/.well-known/acme-challenge/` * - **DNS-01**: Validates domain ownership by adding a TXT record to your DNS (required for wildcard domains) */ -export const createDomain = (options: Options) => (options.client ?? client).post({ +export const createDomain = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/domains', ...options, @@ -1610,7 +1573,7 @@ export const createDomain = (options: Opti /** * Get domain details by hostname */ -export const getDomainByHost = (options: Options) => (options.client ?? client).get({ +export const getDomainByHost = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/domains/by-host/{hostname}', ...options @@ -1626,7 +1589,7 @@ export const getDomainByHost = (options: O * hostname with `None` fields when no on-demand activity exists for it (never a * 404, so the CLI can render "no attempts recorded"). */ -export const getOnDemandCertStatus = (options: Options) => (options.client ?? client).get({ +export const getOnDemandCertStatus = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/domains/by-host/{hostname}/cert-status', ...options @@ -1641,7 +1604,7 @@ export const getOnDemandCertStatus = (opti * This backs the console "Certificates" surface. No certificate or private-key * material is returned — only audit metadata. */ -export const listOnDemandCerts = (options?: Options) => (options?.client ?? client).get({ +export const listOnDemandCerts = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/domains/on-demand-certs', ...options @@ -1653,7 +1616,7 @@ export const listOnDemandCerts = (options? * Cancels the current ACME order for a domain and clears all challenge data. * This allows you to start over with a new order if the previous one failed or got stuck. */ -export const cancelDomainOrder = (options: Options) => (options.client ?? client).delete({ +export const cancelDomainOrder = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/domains/{domain_id}/order', ...options @@ -1662,7 +1625,7 @@ export const cancelDomainOrder = (options: /** * Get ACME order for a domain */ -export const getDomainOrder = (options: Options) => (options.client ?? client).get({ +export const getDomainOrder = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/domains/{domain_id}/order', ...options @@ -1675,7 +1638,7 @@ export const getDomainOrder = (options: Op * If an order already exists, you should cancel it first using the cancel-order endpoint. * Returns the challenge details that need to be fulfilled (DNS record or HTTP token). */ -export const createOrRecreateOrder = (options: Options) => (options.client ?? client).post({ +export const createOrRecreateOrder = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/domains/{domain_id}/order', ...options @@ -1687,7 +1650,7 @@ export const createOrRecreateOrder = (opti * Finalizes the ACME order by completing the challenge validation and requesting the certificate. * This should be called after the challenge has been set up (DNS record added or HTTP token served). */ -export const finalizeOrder = (options: Options) => (options.client ?? client).post({ +export const finalizeOrder = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/domains/{domain_id}/order/finalize', ...options @@ -1702,7 +1665,7 @@ export const finalizeOrder = (options: Opt * * This is similar to how email domain DNS records are auto-provisioned. */ -export const setupDnsChallenge = (options: Options) => (options.client ?? client).post({ +export const setupDnsChallenge = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/domains/{domain_id}/setup-dns', ...options, @@ -1715,7 +1678,7 @@ export const setupDnsChallenge = (options: /** * Delete a domain */ -export const deleteDomain = (options: Options) => (options.client ?? client).delete({ +export const deleteDomain = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/domains/{domain}', ...options @@ -1724,7 +1687,7 @@ export const deleteDomain = (options: Opti /** * Get domain by ID */ -export const getDomainById = (options: Options) => (options.client ?? client).get({ +export const getDomainById = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/domains/{domain}', ...options @@ -1733,7 +1696,7 @@ export const getDomainById = (options: Opt /** * Get challenge token for a domain (returns plain text token) */ -export const getChallengeToken = (options: Options) => (options.client ?? client).get({ +export const getChallengeToken = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/domains/{domain}/challenge-token', ...options @@ -1749,7 +1712,7 @@ export const getChallengeToken = (options: * * This is useful for debugging why HTTP-01 challenges fail. */ -export const getHttpChallengeDebug = (options: Options) => (options.client ?? client).get({ +export const getHttpChallengeDebug = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/domains/{domain}/http-challenge-debug', ...options @@ -1758,7 +1721,7 @@ export const getHttpChallengeDebug = (opti /** * Provision a domain certificate */ -export const provisionDomain = (options: Options) => (options.client ?? client).post({ +export const provisionDomain = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/domains/{domain}/provision', ...options @@ -1770,7 +1733,7 @@ export const provisionDomain = (options: O * For HTTP-01 domains: Automatically renews the certificate * For DNS-01 domains (wildcards): Creates a new ACME order and returns challenge data */ -export const renewDomain = (options: Options) => (options.client ?? client).post({ +export const renewDomain = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/domains/{domain}/renew', ...options @@ -1779,7 +1742,7 @@ export const renewDomain = (options: Optio /** * Check domain status */ -export const checkDomainStatus = (options: Options) => (options.client ?? client).get({ +export const checkDomainStatus = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/domains/{domain}/status', ...options @@ -1788,7 +1751,7 @@ export const checkDomainStatus = (options: /** * Inspect a source ZIP without creating a project or retaining the upload. */ -export const inspectDropArchive = (options: Options) => (options.client ?? client).post({ +export const inspectDropArchive = (options: Options): RequestResult => (options.client ?? client).post({ ...formDataBodySerializer, security: [{ scheme: 'bearer', type: 'http' }], url: '/drop/inspect', @@ -1802,7 +1765,7 @@ export const inspectDropArchive = (options /** * List all email domains */ -export const listEmailDomains = (options?: Options) => (options?.client ?? client).get({ +export const listEmailDomains = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/email-domains', ...options @@ -1811,7 +1774,7 @@ export const listEmailDomains = (options?: /** * Create a new email domain */ -export const createEmailDomain = (options: Options) => (options.client ?? client).post({ +export const createEmailDomain = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/email-domains', ...options, @@ -1824,7 +1787,7 @@ export const createEmailDomain = (options: /** * Get an email domain by domain name with DNS records */ -export const getDomainByName = (options: Options) => (options.client ?? client).get({ +export const getDomainByName = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/email-domains/by-domain/{domain}', ...options @@ -1833,7 +1796,7 @@ export const getDomainByName = (options: O /** * Delete an email domain */ -export const deleteEmailDomain = (options: Options) => (options.client ?? client).delete({ +export const deleteEmailDomain = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/email-domains/{id}', ...options @@ -1842,7 +1805,7 @@ export const deleteEmailDomain = (options: /** * Get an email domain by ID with DNS records */ -export const getDomain = (options: Options) => (options.client ?? client).get({ +export const getDomain = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/email-domains/{id}', ...options @@ -1851,7 +1814,7 @@ export const getDomain = (options: Options /** * Get DNS records for an email domain */ -export const getDomainDnsRecords = (options: Options) => (options.client ?? client).get({ +export const getDomainDnsRecords = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/email-domains/{id}/dns-records', ...options @@ -1860,7 +1823,7 @@ export const getDomainDnsRecords = (option /** * Setup DNS records for an email domain using a configured DNS provider */ -export const setupDns = (options: Options) => (options.client ?? client).post({ +export const setupDns = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/email-domains/{id}/setup-dns', ...options, @@ -1873,7 +1836,7 @@ export const setupDns = (options: Options< /** * Verify an email domain's DNS configuration */ -export const verifyDomain = (options: Options) => (options.client ?? client).post({ +export const verifyDomain = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/email-domains/{id}/verify', ...options @@ -1882,7 +1845,7 @@ export const verifyDomain = (options: Opti /** * List all email providers */ -export const listEmailProviders = (options?: Options) => (options?.client ?? client).get({ +export const listEmailProviders = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/email-providers', ...options @@ -1891,7 +1854,7 @@ export const listEmailProviders = (options /** * Create a new email provider */ -export const createEmailProvider = (options: Options) => (options.client ?? client).post({ +export const createEmailProvider = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/email-providers', ...options, @@ -1904,7 +1867,7 @@ export const createEmailProvider = (option /** * Delete an email provider */ -export const deleteEmailProvider = (options: Options) => (options.client ?? client).delete({ +export const deleteEmailProvider = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/email-providers/{id}', ...options @@ -1913,7 +1876,7 @@ export const deleteEmailProvider = (option /** * Get an email provider by ID */ -export const getEmailProvider = (options: Options) => (options.client ?? client).get({ +export const getEmailProvider = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/email-providers/{id}', ...options @@ -1927,7 +1890,7 @@ export const getEmailProvider = (options: * preserves the stored secret, so operators can rename a provider without re-typing * passwords. `provider_type` is immutable; to switch providers, delete and recreate. */ -export const updateEmailProvider = (options: Options) => (options.client ?? client).patch({ +export const updateEmailProvider = (options: Options): RequestResult => (options.client ?? client).patch({ security: [{ scheme: 'bearer', type: 'http' }], url: '/email-providers/{id}', ...options, @@ -1940,7 +1903,7 @@ export const updateEmailProvider = (option /** * Test an email provider by sending a test email to the logged-in user */ -export const testProvider = (options: Options) => (options.client ?? client).post({ +export const testProvider = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/email-providers/{id}/test', ...options, @@ -1955,7 +1918,7 @@ export const testProvider = (options: Opti * subscription + SESv2 event destination), using the provider's stored * credentials. */ -export const setupEmailTracking = (options: Options) => (options.client ?? client).post({ +export const setupEmailTracking = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/email-providers/{id}/tracking/setup', ...options @@ -1964,7 +1927,7 @@ export const setupEmailTracking = (options /** * Live status of SES event tracking for a provider */ -export const getEmailTrackingStatus = (options: Options) => (options.client ?? client).get({ +export const getEmailTrackingStatus = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/email-providers/{id}/tracking/status', ...options @@ -1973,7 +1936,7 @@ export const getEmailTrackingStatus = (opt /** * List emails with optional filtering */ -export const listEmails = (options?: Options) => (options?.client ?? client).get({ +export const listEmails = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/emails', ...options @@ -1982,7 +1945,7 @@ export const listEmails = (options?: Optio /** * Send an email */ -export const sendEmail = (options: Options) => (options.client ?? client).post({ +export const sendEmail = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/emails', ...options, @@ -1995,7 +1958,7 @@ export const sendEmail = (options: Options /** * GET /emails/events */ -export const getGlobalEvents = (options?: Options) => (options?.client ?? client).get({ +export const getGlobalEvents = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/emails/events', ...options @@ -2004,7 +1967,7 @@ export const getGlobalEvents = (options?: /** * GET /emails/events/stats */ -export const getGlobalEventStats = (options?: Options) => (options?.client ?? client).get({ +export const getGlobalEventStats = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/emails/events/stats', ...options @@ -2013,7 +1976,7 @@ export const getGlobalEventStats = (option /** * Get email statistics */ -export const getEmailStats = (options?: Options) => (options?.client ?? client).get({ +export const getEmailStats = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/emails/stats', ...options @@ -2022,7 +1985,7 @@ export const getEmailStats = (options?: Op /** * Validate an email address */ -export const validateEmail = (options: Options) => (options.client ?? client).post({ +export const validateEmail = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/emails/validate', ...options, @@ -2038,7 +2001,7 @@ export const validateEmail = (options: Opt * This endpoint replaces original links in tracked emails. * No authentication required - it's called when the recipient clicks a link. */ -export const trackClick = (options: Options) => (options.client ?? client).get({ url: '/emails/{email_id}/track/click/{link_index}', ...options }); +export const trackClick = (options: Options): RequestResult => (options.client ?? client).get({ url: '/emails/{email_id}/track/click/{link_index}', ...options }); /** * Track email open - returns a 1x1 transparent GIF @@ -2046,12 +2009,12 @@ export const trackClick = (options: Option * This endpoint is embedded as an tag in emails. * No authentication required - it's called by the email client. */ -export const trackOpen = (options: Options) => (options.client ?? client).get({ url: '/emails/{email_id}/track/open', ...options }); +export const trackOpen = (options: Options): RequestResult => (options.client ?? client).get({ url: '/emails/{email_id}/track/open', ...options }); /** * Get an email by ID */ -export const getEmail = (options: Options) => (options.client ?? client).get({ +export const getEmail = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/emails/{id}', ...options @@ -2060,7 +2023,7 @@ export const getEmail = (options: Options< /** * Get email tracking summary */ -export const getEmailTracking = (options: Options) => (options.client ?? client).get({ +export const getEmailTracking = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/emails/{id}/tracking', ...options @@ -2069,7 +2032,7 @@ export const getEmailTracking = (options: /** * Get email tracking events */ -export const getEmailEvents = (options: Options) => (options.client ?? client).get({ +export const getEmailEvents = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/emails/{id}/tracking/events', ...options @@ -2078,7 +2041,7 @@ export const getEmailEvents = (options: Op /** * Get tracked links for an email */ -export const getEmailLinks = (options: Options) => (options.client ?? client).get({ +export const getEmailLinks = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/emails/{id}/tracking/links', ...options @@ -2087,12 +2050,12 @@ export const getEmailLinks = (options: Opt /** * Get all external services */ -export const listServices = (options?: Options) => (options?.client ?? client).get({ url: '/external-services', ...options }); +export const listServices = (options?: Options): RequestResult => (options?.client ?? client).get({ url: '/external-services', ...options }); /** * Create new external service */ -export const createService = (options: Options) => (options.client ?? client).post({ +export const createService = (options: Options): RequestResult => (options.client ?? client).post({ url: '/external-services', ...options, headers: { @@ -2104,7 +2067,7 @@ export const createService = (options: Opt /** * List available Docker containers that can be imported as services */ -export const listAvailableContainers = (options?: Options) => (options?.client ?? client).get({ +export const listAvailableContainers = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/available-containers', ...options @@ -2113,7 +2076,7 @@ export const listAvailableContainers = (op /** * Get external service details by slug */ -export const getServiceBySlug = (options: Options) => (options.client ?? client).get({ url: '/external-services/by-slug/{slug}', ...options }); +export const getServiceBySlug = (options: Options): RequestResult => (options.client ?? client).get({ url: '/external-services/by-slug/{slug}', ...options }); /** * Current health status for many services at once @@ -2121,12 +2084,12 @@ export const getServiceBySlug = (options: * Powers the status dot on the Storage list page. Pass a comma-separated * list of service IDs via `?ids=1,2,3`. Omit to get every service. */ -export const listServiceHealthStatuses = (options?: Options) => (options?.client ?? client).get({ url: '/external-services/health-status-batch', ...options }); +export const listServiceHealthStatuses = (options?: Options): RequestResult => (options?.client ?? client).get({ url: '/external-services/health-status-batch', ...options }); /** * Import an existing Docker container as a managed external service */ -export const importExternalService = (options: Options) => (options.client ?? client).post({ +export const importExternalService = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/import', ...options, @@ -2139,47 +2102,47 @@ export const importExternalService = (opti /** * List services linked to a project */ -export const listProjectServices = (options: Options) => (options.client ?? client).get({ url: '/external-services/projects/{project_id}', ...options }); +export const listProjectServices = (options: Options): RequestResult => (options.client ?? client).get({ url: '/external-services/projects/{project_id}', ...options }); /** * Get all environment variables for all services linked to a project */ -export const getProjectServiceEnvironmentVariables = (options: Options) => (options.client ?? client).get({ url: '/external-services/projects/{project_id}/environment', ...options }); +export const getProjectServiceEnvironmentVariables = (options: Options): RequestResult => (options.client ?? client).get({ url: '/external-services/projects/{project_id}/environment', ...options }); /** * Get provider metadata (display names, icons, descriptions) */ -export const getProvidersMetadata = (options?: Options) => (options?.client ?? client).get({ url: '/external-services/providers/metadata', ...options }); +export const getProvidersMetadata = (options?: Options): RequestResult => (options?.client ?? client).get({ url: '/external-services/providers/metadata', ...options }); /** * Get metadata for a specific provider */ -export const getProviderMetadata = (options: Options) => (options.client ?? client).get({ url: '/external-services/providers/metadata/{service_type}', ...options }); +export const getProviderMetadata = (options: Options): RequestResult => (options.client ?? client).get({ url: '/external-services/providers/metadata/{service_type}', ...options }); /** * Get available service types */ -export const getServiceTypes = (options?: Options) => (options?.client ?? client).get({ url: '/external-services/types', ...options }); +export const getServiceTypes = (options?: Options): RequestResult => (options?.client ?? client).get({ url: '/external-services/types', ...options }); /** * Get parameter schema for a specific service type */ -export const getServiceTypeParameters = (options: Options) => (options.client ?? client).get({ url: '/external-services/types/{service_type}/parameters', ...options }); +export const getServiceTypeParameters = (options: Options): RequestResult => (options.client ?? client).get({ url: '/external-services/types/{service_type}/parameters', ...options }); /** * Delete external service */ -export const deleteService = (options: Options) => (options.client ?? client).delete({ url: '/external-services/{id}', ...options }); +export const deleteService = (options: Options): RequestResult => (options.client ?? client).delete({ url: '/external-services/{id}', ...options }); /** * Get external service details */ -export const getService = (options: Options) => (options.client ?? client).get({ url: '/external-services/{id}', ...options }); +export const getService = (options: Options): RequestResult => (options.client ?? client).get({ url: '/external-services/{id}', ...options }); /** * Update external service */ -export const updateService = (options: Options) => (options.client ?? client).put({ +export const updateService = (options: Options): RequestResult => (options.client ?? client).put({ url: '/external-services/{id}', ...options, headers: { @@ -2200,7 +2163,7 @@ export const updateService = (options: Opt * unreachable (UI surfaces it as a banner above the table); the table * itself is empty in that case. Returns `400` for non-cluster services. */ -export const getClusterHealth = (options: Options) => (options.client ?? client).get({ +export const getClusterHealth = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{id}/cluster-health', ...options @@ -2214,7 +2177,7 @@ export const getClusterHealth = (options: * fires alerts on the Nth consecutive failure (so consecutive-failure state * stays honest). Returns the fresh snapshot the UI can display immediately. */ -export const triggerServiceHealthCheck = (options: Options) => (options.client ?? client).post({ url: '/external-services/{id}/health-check', ...options }); +export const triggerServiceHealthCheck = (options: Options): RequestResult => (options.client ?? client).post({ url: '/external-services/{id}/health-check', ...options }); /** * Persisted health status for an external service @@ -2223,7 +2186,7 @@ export const triggerServiceHealthCheck = ( * `ExternalServiceHealthMonitor`, plus recent check history for sparklines * and a 24-hour uptime percentage. Safe to poll from the UI every 30s. */ -export const getServiceHealthStatus = (options: Options) => (options.client ?? client).get({ url: '/external-services/{id}/health-status', ...options }); +export const getServiceHealthStatus = (options: Options): RequestResult => (options.client ?? client).get({ url: '/external-services/{id}/health-status', ...options }); /** * Begin adding a single new member to a running cluster. @@ -2235,7 +2198,7 @@ export const getServiceHealthStatus = (opt * poll `GET /external-services/{id}/members/{member_id}` to watch * `provisioning_step` advance through the phases. */ -export const addClusterMember = (options: Options) => (options.client ?? client).post({ +export const addClusterMember = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{id}/members', ...options, @@ -2253,7 +2216,7 @@ export const addClusterMember = (options: * 2-data-member quorum required for HA. Stops + removes the container, * deletes the row, and drops the Tier-2 DNS record. */ -export const removeClusterMember = (options: Options) => (options.client ?? client).delete({ +export const removeClusterMember = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{id}/members/{member_id}', ...options @@ -2268,7 +2231,7 @@ export const removeClusterMember = (option * `provisioning_container` → `registering_dns` → `done` (or `failed` * with `provisioning_error` set). */ -export const getClusterMember = (options: Options) => (options.client ?? client).get({ +export const getClusterMember = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{id}/members/{member_id}', ...options @@ -2280,7 +2243,7 @@ export const getClusterMember = (options: * replica transitions to primary; the role reconciler then refreshes * the role-aliased VIPs (≤30s). */ -export const promoteClusterMember = (options: Options) => (options.client ?? client).post({ +export const promoteClusterMember = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{id}/members/{member_id}/promote', ...options @@ -2292,7 +2255,7 @@ export const promoteClusterMember = (optio * Pass `percentile` to compute a histogram quantile instead of a plain * gauge/counter average. */ -export const externalServiceMetricsGetRange = (options: Options) => (options.client ?? client).get({ +export const externalServiceMetricsGetRange = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{id}/metrics', ...options @@ -2301,7 +2264,7 @@ export const externalServiceMetricsGetRange = (options: Options) => (options.client ?? client).get({ +export const externalServiceMetricsGetAlertRules = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{id}/metrics/alert-rules', ...options @@ -2313,7 +2276,7 @@ export const externalServiceMetricsGetAlertRules = (options: Options) => (options.client ?? client).post({ +export const externalServiceMetricsCreateAlertRule = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{id}/metrics/alert-rules', ...options, @@ -2326,7 +2289,7 @@ export const externalServiceMetricsCreateAlertRule = (options: Options) => (options.client ?? client).delete({ +export const externalServiceMetricsDeleteAlertRule = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{id}/metrics/alert-rules/{rule_id}', ...options @@ -2335,7 +2298,7 @@ export const externalServiceMetricsDeleteAlertRule = (options: Options) => (options.client ?? client).put({ +export const externalServiceMetricsUpdateAlertRule = (options: Options): RequestResult => (options.client ?? client).put({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{id}/metrics/alert-rules/{rule_id}', ...options, @@ -2352,7 +2315,7 @@ export const externalServiceMetricsUpdateAlertRule = (options: Options) => (options.client ?? client).get({ +export const externalServiceMetricsByDatabase = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{id}/metrics/by-database', ...options @@ -2364,7 +2327,7 @@ export const externalServiceMetricsByDatabase = (options: Options) => (options.client ?? client).patch({ +export const externalServiceMetricsToggle = (options: Options): RequestResult => (options.client ?? client).patch({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{id}/metrics/enable', ...options, @@ -2377,7 +2340,7 @@ export const externalServiceMetricsToggle = (options: Options) => (options.client ?? client).get({ +export const externalServiceMetricsGetLatest = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{id}/metrics/latest', ...options @@ -2389,7 +2352,7 @@ export const externalServiceMetricsGetLatest = (options: Options) => (options.client ?? client).get({ +export const externalServiceMetricsStatus = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{id}/metrics/status', ...options @@ -2399,27 +2362,27 @@ export const externalServiceMetricsStatus = (options: Options) => (options.client ?? client).get({ url: '/external-services/{id}/parameters/{param_name}', ...options }); +export const revealServiceParameter = (options: Options): RequestResult => (options.client ?? client).get({ url: '/external-services/{id}/parameters/{param_name}', ...options }); /** * Get environment variables preview with masked sensitive values */ -export const getServicePreviewEnvironmentVariablesMasked = (options: Options) => (options.client ?? client).get({ url: '/external-services/{id}/preview-environment-masked', ...options }); +export const getServicePreviewEnvironmentVariablesMasked = (options: Options): RequestResult => (options.client ?? client).get({ url: '/external-services/{id}/preview-environment-masked', ...options }); /** * Get environment variable names preview (safe - no sensitive values) */ -export const getServicePreviewEnvironmentVariableNames = (options: Options) => (options.client ?? client).get({ url: '/external-services/{id}/preview-environment-names', ...options }); +export const getServicePreviewEnvironmentVariableNames = (options: Options): RequestResult => (options.client ?? client).get({ url: '/external-services/{id}/preview-environment-names', ...options }); /** * List projects linked to service */ -export const listServiceProjects = (options: Options) => (options.client ?? client).get({ url: '/external-services/{id}/projects', ...options }); +export const listServiceProjects = (options: Options): RequestResult => (options.client ?? client).get({ url: '/external-services/{id}/projects', ...options }); /** * Link service to project */ -export const linkServiceToProject = (options: Options) => (options.client ?? client).post({ +export const linkServiceToProject = (options: Options): RequestResult => (options.client ?? client).post({ url: '/external-services/{id}/projects', ...options, headers: { @@ -2431,17 +2394,17 @@ export const linkServiceToProject = (optio /** * Unlink service from project */ -export const unlinkServiceFromProject = (options: Options) => (options.client ?? client).delete({ url: '/external-services/{id}/projects/{project_id}', ...options }); +export const unlinkServiceFromProject = (options: Options): RequestResult => (options.client ?? client).delete({ url: '/external-services/{id}/projects/{project_id}', ...options }); /** * Get all environment variables for a service-project pair */ -export const getServiceEnvironmentVariables = (options: Options) => (options.client ?? client).get({ url: '/external-services/{id}/projects/{project_id}/environment', ...options }); +export const getServiceEnvironmentVariables = (options: Options): RequestResult => (options.client ?? client).get({ url: '/external-services/{id}/projects/{project_id}/environment', ...options }); /** * Get specific environment variable for a service-project pair */ -export const getServiceEnvironmentVariable = (options: Options) => (options.client ?? client).get({ url: '/external-services/{id}/projects/{project_id}/environment/{var_name}', ...options }); +export const getServiceEnvironmentVariable = (options: Options): RequestResult => (options.client ?? client).get({ url: '/external-services/{id}/projects/{project_id}/environment/{var_name}', ...options }); /** * Update a service's resource limits (memory, CPU caps). @@ -2459,7 +2422,7 @@ export const getServiceEnvironmentVariable = (options: Options) => (options.client ?? client).patch({ +export const updateServiceResources = (options: Options): RequestResult => (options.client ?? client).patch({ url: '/external-services/{id}/resources', ...options, headers: { @@ -2468,7 +2431,7 @@ export const updateServiceResources = (opt } }); -export const startRestore = (options: Options) => (options.client ?? client).post({ +export const startRestore = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{id}/restore', ...options, @@ -2478,13 +2441,13 @@ export const startRestore = (options: Opti } }); -export const getRestoreCapabilities = (options: Options) => (options.client ?? client).get({ +export const getRestoreCapabilities = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{id}/restore-capabilities', ...options }); -export const planRestore = (options: Options) => (options.client ?? client).post({ +export const planRestore = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{id}/restore-plan', ...options, @@ -2494,7 +2457,7 @@ export const planRestore = (options: Optio } }); -export const listRestoreRunsForService = (options: Options) => (options.client ?? client).get({ +export const listRestoreRunsForService = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{id}/restore-runs', ...options @@ -2506,7 +2469,7 @@ export const listRestoreRunsForService = ( * Cleans up any leftover containers from the previous attempt and * re-runs cluster initialization with the provided member specifications. */ -export const retryCluster = (options: Options) => (options.client ?? client).post({ +export const retryCluster = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{id}/retry', ...options, @@ -2520,30 +2483,30 @@ export const retryCluster = (options: Opti * Inspect a service's container(s): status, restart count, OOM-killed flag, * exit code, and the cgroup limits actually applied. */ -export const getServiceRuntime = (options: Options) => (options.client ?? client).get({ url: '/external-services/{id}/runtime', ...options }); +export const getServiceRuntime = (options: Options): RequestResult => (options.client ?? client).get({ url: '/external-services/{id}/runtime', ...options }); /** * Start an external service */ -export const startService = (options: Options) => (options.client ?? client).post({ url: '/external-services/{id}/start', ...options }); +export const startService = (options: Options): RequestResult => (options.client ?? client).post({ url: '/external-services/{id}/start', ...options }); /** * Sample current CPU/memory usage from each of a service's containers. * One-shot sample, no streaming. Cheap to call (single Docker round-trip * per member) so the UI can poll on a 5–10s interval. */ -export const getServiceStats = (options: Options) => (options.client ?? client).get({ url: '/external-services/{id}/stats', ...options }); +export const getServiceStats = (options: Options): RequestResult => (options.client ?? client).get({ url: '/external-services/{id}/stats', ...options }); /** * Stop an external service */ -export const stopService = (options: Options) => (options.client ?? client).post({ url: '/external-services/{id}/stop', ...options }); +export const stopService = (options: Options): RequestResult => (options.client ?? client).post({ url: '/external-services/{id}/stop', ...options }); /** * Upgrade external service to new Docker image with data migration * This endpoint uses service-specific upgrade procedures (e.g., pg_upgrade for PostgreSQL) */ -export const upgradeService = (options: Options) => (options.client ?? client).post({ +export const upgradeService = (options: Options): RequestResult => (options.client ?? client).post({ url: '/external-services/{id}/upgrade', ...options, headers: { @@ -2563,7 +2526,7 @@ export const upgradeService = (options: Op * Returns 404 when no snapshot exists yet (probe hasn't run, or the service * isn't Postgres). */ -export const getPostgresWalHealth = (options: Options) => (options.client ?? client).get({ url: '/external-services/{id}/wal-health', ...options }); +export const getPostgresWalHealth = (options: Options): RequestResult => (options.client ?? client).get({ url: '/external-services/{id}/wal-health', ...options }); /** * Enable `pg_stat_statements` on a standalone Postgres service. @@ -2580,7 +2543,7 @@ export const getPostgresWalHealth = (optio * Confirmation is the caller's responsibility (UI dialog / CLI `--yes` flag) * before invoking this endpoint. */ -export const externalServiceEnablePgStatStatements = (options: Options) => (options.client ?? client).post({ +export const externalServiceEnablePgStatStatements = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{service_id}/pg-stat-statements/enable', ...options @@ -2591,7 +2554,7 @@ export const externalServiceEnablePgStatStatements = (options: Options) => (options.client ?? client).post({ +export const externalServiceResetPgStatStatements = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{service_id}/pg-stat-statements/reset', ...options, @@ -2601,7 +2564,7 @@ export const externalServiceResetPgStatStatements = (options: Options) => (options.client ?? client).get({ +export const getSlowQueries = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{service_id}/pg-stat-statements/slow-queries', ...options @@ -2614,7 +2577,7 @@ export const getSlowQueries = (options: Op * the capability with an "off — here's how to turn it on" state instead of * hiding it, and so the agent can tell "not set up" apart from "not supported". */ -export const getAiDataAccess = (options: Options) => (options.client ?? client).get({ +export const getAiDataAccess = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{service_id}/query/ai-data-access', ...options @@ -2627,7 +2590,7 @@ export const getAiDataAccess = (options: O * personal data, and enabling this sends them to the configured AI provider — * so it is a deliberate, audited, per-service decision by the operator. */ -export const setAiDataAccess = (options: Options) => (options.client ?? client).patch({ +export const setAiDataAccess = (options: Options): RequestResult => (options.client ?? client).patch({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{service_id}/query/ai-data-access', ...options, @@ -2640,7 +2603,7 @@ export const setAiDataAccess = (options: O /** * List containers at the root level (databases, keyspaces, etc.) */ -export const listRootContainers = (options: Options) => (options.client ?? client).get({ +export const listRootContainers = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{service_id}/query/containers', ...options @@ -2651,7 +2614,7 @@ export const listRootContainers = (options * Path segments are separated by forward slashes * Example: /external-services/1/query/containers/mydb lists schemas in database "mydb" */ -export const listContainersAtPath = (options: Options) => (options.client ?? client).get({ +export const listContainersAtPath = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{service_id}/query/containers/{path}', ...options @@ -2661,7 +2624,7 @@ export const listContainersAtPath = (optio * List entities (tables, collections, etc.) in a container * Example: /external-services/1/query/containers/mydb/public/entities lists tables in the public schema */ -export const listEntities = (options: Options) => (options.client ?? client).get({ +export const listEntities = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{service_id}/query/containers/{path}/entities', ...options @@ -2670,7 +2633,7 @@ export const listEntities = (options: Opti /** * Get detailed information about an entity (table schema) */ -export const getEntityInfo = (options: Options) => (options.client ?? client).get({ +export const getEntityInfo = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{service_id}/query/containers/{path}/entities/{entity}', ...options @@ -2683,7 +2646,7 @@ export const getEntityInfo = (options: Opt * Gated for AI callers by the service's `ai_data_access` opt-in — see * [`temps_core::ai_tool_call::AiToolCall`]. */ -export const readEntityRows = (options: Options) => (options.client ?? client).get({ +export const readEntityRows = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{service_id}/query/containers/{path}/entities/{entity}/data', ...options @@ -2692,7 +2655,7 @@ export const readEntityRows = (options: Op /** * Query data from an entity with optional filters, pagination, and sorting */ -export const queryData = (options: Options) => (options.client ?? client).post({ +export const queryData = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{service_id}/query/containers/{path}/entities/{entity}/data', ...options, @@ -2705,7 +2668,7 @@ export const queryData = (options: Options /** * Download an object (S3 only) as a streaming response */ -export const downloadObject = (options: Options) => (options.client ?? client).get({ +export const downloadObject = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{service_id}/query/containers/{path}/entities/{entity}/download', ...options @@ -2714,7 +2677,7 @@ export const downloadObject = (options: Op /** * Get information about a specific container */ -export const getQueryContainerInfo = (options: Options) => (options.client ?? client).get({ +export const getQueryContainerInfo = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{service_id}/query/containers/{path}/info', ...options @@ -2723,7 +2686,7 @@ export const getQueryContainerInfo = (opti /** * Check if a service supports query explorer functionality */ -export const checkExplorerSupport = (options: Options) => (options.client ?? client).get({ +export const checkExplorerSupport = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{service_id}/query/explorer-support', ...options @@ -2732,7 +2695,7 @@ export const checkExplorerSupport = (optio /** * List recent upgrades for a single service (newest first, page size 50). */ -export const listPgUpgrades = (options: Options) => (options.client ?? client).get({ +export const listPgUpgrades = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{service_id}/upgrades', ...options @@ -2741,7 +2704,7 @@ export const listPgUpgrades = (options: Op /** * Start a new PostgreSQL major-version upgrade for a service. */ -export const startPgUpgrade = (options: Options) => (options.client ?? client).post({ +export const startPgUpgrade = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{service_id}/upgrades', ...options, @@ -2754,7 +2717,7 @@ export const startPgUpgrade = (options: Op /** * Get a single upgrade by id, scoped to a service. */ -export const getPgUpgrade = (options: Options) => (options.client ?? client).get({ +export const getPgUpgrade = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{service_id}/upgrades/{id}', ...options @@ -2764,7 +2727,7 @@ export const getPgUpgrade = (options: Opti * Cancel an in-flight upgrade. The orchestrator stops at its next phase * boundary; already-terminal upgrades return 409. */ -export const cancelPgUpgrade = (options: Options) => (options.client ?? client).post({ +export const cancelPgUpgrade = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{service_id}/upgrades/{id}/cancel', ...options @@ -2773,7 +2736,7 @@ export const cancelPgUpgrade = (options: O /** * Get the accumulated JSONL log content for an upgrade (for dashboard display). */ -export const getPgUpgradeLogs = (options: Options) => (options.client ?? client).get({ +export const getPgUpgradeLogs = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{service_id}/upgrades/{id}/logs', ...options @@ -2783,7 +2746,7 @@ export const getPgUpgradeLogs = (options: * Retry a failed upgrade. The phase is preserved, so the state machine * resumes from where it failed. */ -export const retryPgUpgrade = (options: Options) => (options.client ?? client).post({ +export const retryPgUpgrade = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{service_id}/upgrades/{id}/retry', ...options @@ -2794,13 +2757,13 @@ export const retryPgUpgrade = (options: Op * Only valid while the rollback retention window is still open (see * `ROLLBACK_RETENTION_DAYS`) and the rollback volume has not been swept. */ -export const rollbackPgUpgrade = (options: Options) => (options.client ?? client).post({ +export const rollbackPgUpgrade = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/external-services/{service_id}/upgrades/{id}/rollback', ...options }); -export const getFile = (options: Options) => (options.client ?? client).get({ +export const getFile = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/files/{file_path}', ...options @@ -2819,7 +2782,7 @@ export const getFile = (options: Options(options: Options) => (options.client ?? client).post({ +export const recordFlagExposure = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/flags/exposure', ...options, @@ -2841,7 +2804,7 @@ export const recordFlagExposure = (options * Supports `If-None-Match`, so the SDK's background poll is a 304 in the * common case. */ -export const getFlagSnapshot = (options?: Options) => (options?.client ?? client).get({ +export const getFlagSnapshot = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/flags/snapshot', ...options @@ -2850,7 +2813,7 @@ export const getFlagSnapshot = (options?: /** * Get geolocation information for an IP address */ -export const getIpGeolocation = (options: Options) => (options.client ?? client).get({ +export const getIpGeolocation = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/geo/{ip}', ...options @@ -2859,7 +2822,7 @@ export const getIpGeolocation = (options: /** * List user's git provider connections */ -export const listConnections = (options?: Options) => (options?.client ?? client).get({ +export const listConnections = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/git-connections', ...options @@ -2868,7 +2831,7 @@ export const listConnections = (options?: /** * Permanently delete a git provider connection */ -export const deleteConnection = (options: Options) => (options.client ?? client).delete({ +export const deleteConnection = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/git-connections/{connection_id}', ...options @@ -2877,7 +2840,7 @@ export const deleteConnection = (options: /** * Activate a git provider connection */ -export const activateConnection = (options: Options) => (options.client ?? client).post({ +export const activateConnection = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/git-connections/{connection_id}/activate', ...options @@ -2886,7 +2849,7 @@ export const activateConnection = (options /** * Deactivate a git provider connection */ -export const deactivateConnection = (options: Options) => (options.client ?? client).post({ +export const deactivateConnection = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/git-connections/{connection_id}/deactivate', ...options @@ -2899,7 +2862,7 @@ export const deactivateConnection = (optio * and fires admin notifications on status transitions. Returns the updated * connection. */ -export const runConnectionHealthCheck = (options: Options) => (options.client ?? client).post({ +export const runConnectionHealthCheck = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/git-connections/{connection_id}/health-check', ...options @@ -2911,7 +2874,7 @@ export const runConnectionHealthCheck = (o * Fetches repositories from the connected git provider with support for pagination, search, and filtering. * This endpoint calls the provider's API directly to get the most up-to-date repository list. */ -export const listRepositoriesByConnection = (options: Options) => (options.client ?? client).get({ +export const listRepositoriesByConnection = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/git-connections/{connection_id}/repositories', ...options @@ -2927,7 +2890,7 @@ export const listRepositoriesByConnection = (options: Options) => (options.client ?? client).post({ +export const syncRepositories = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/git-connections/{connection_id}/sync', ...options @@ -2936,7 +2899,7 @@ export const syncRepositories = (options: /** * Update access token for a connection (when tokens expire or are rotated) */ -export const updateConnectionToken = (options: Options) => (options.client ?? client).post({ +export const updateConnectionToken = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/git-connections/{connection_id}/update-token', ...options, @@ -2949,7 +2912,7 @@ export const updateConnectionToken = (opti /** * Validate a connection by testing the access token */ -export const validateConnection = (options: Options) => (options.client ?? client).get({ +export const validateConnection = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/git-connections/{connection_id}/validate', ...options @@ -2958,7 +2921,7 @@ export const validateConnection = (options /** * List all git providers */ -export const listGitProviders = (options?: Options) => (options?.client ?? client).get({ +export const listGitProviders = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/git-providers', ...options @@ -2967,7 +2930,7 @@ export const listGitProviders = (options?: /** * Create a new git provider configuration */ -export const createGitProvider = (options: Options) => (options.client ?? client).post({ +export const createGitProvider = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/git-providers', ...options, @@ -2980,7 +2943,7 @@ export const createGitProvider = (options: /** * Create a Bitbucket Cloud provider with access token or app password authentication */ -export const createBitbucketProvider = (options: Options) => (options.client ?? client).post({ +export const createBitbucketProvider = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/git-providers/bitbucket', ...options, @@ -2994,7 +2957,7 @@ export const createBitbucketProvider = (op * Create a Generic git provider for self-hosted or arbitrary HTTPS git hosts. * Supports public repositories (no token) and private repositories (token-based). */ -export const createGenericProvider = (options: Options) => (options.client ?? client).post({ +export const createGenericProvider = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/git-providers/generic', ...options, @@ -3007,7 +2970,7 @@ export const createGenericProvider = (opti /** * Create a Gitea Personal Access Token provider */ -export const createGiteaPatProvider = (options: Options) => (options.client ?? client).post({ +export const createGiteaPatProvider = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/git-providers/gitea/pat', ...options, @@ -3020,7 +2983,7 @@ export const createGiteaPatProvider = (opt /** * Create a GitHub Personal Access Token provider */ -export const createGithubPatProvider = (options: Options) => (options.client ?? client).post({ +export const createGithubPatProvider = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/git-providers/github/pat', ...options, @@ -3033,7 +2996,7 @@ export const createGithubPatProvider = (op /** * Create a GitLab OAuth provider */ -export const createGitlabOauthProvider = (options: Options) => (options.client ?? client).post({ +export const createGitlabOauthProvider = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/git-providers/gitlab/oauth', ...options, @@ -3046,7 +3009,7 @@ export const createGitlabOauthProvider = ( /** * Create a GitLab PAT provider */ -export const createGitlabPatProvider = (options: Options) => (options.client ?? client).post({ +export const createGitlabPatProvider = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/git-providers/gitlab/pat', ...options, @@ -3059,7 +3022,7 @@ export const createGitlabPatProvider = (op /** * Permanently delete a git provider */ -export const deleteGitProvider = (options: Options) => (options.client ?? client).delete({ +export const deleteGitProvider = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/git-providers/{provider_id}', ...options @@ -3068,7 +3031,7 @@ export const deleteGitProvider = (options: /** * Get a specific git provider */ -export const getGitProvider = (options: Options) => (options.client ?? client).get({ +export const getGitProvider = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/git-providers/{provider_id}', ...options @@ -3077,7 +3040,7 @@ export const getGitProvider = (options: Op /** * Activate a git provider */ -export const activateProvider = (options: Options) => (options.client ?? client).post({ +export const activateProvider = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/git-providers/{provider_id}/activate', ...options @@ -3086,12 +3049,12 @@ export const activateProvider = (options: /** * Handle OAuth callback for a git provider */ -export const handleGitProviderOauthCallback = (options: Options) => (options.client ?? client).get({ url: '/git-providers/{provider_id}/callback', ...options }); +export const handleGitProviderOauthCallback = (options: Options): RequestResult => (options.client ?? client).get({ url: '/git-providers/{provider_id}/callback', ...options }); /** * Get connections for a specific git provider */ -export const getProviderConnections = (options: Options) => (options.client ?? client).get({ +export const getProviderConnections = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/git-providers/{provider_id}/connections', ...options @@ -3102,7 +3065,7 @@ export const getProviderConnections = (opt * you send are replaced; omitted fields keep their stored values. Fields that * don't apply to the provider's auth method are ignored on the service side. */ -export const updateGitProviderCredentials = (options: Options) => (options.client ?? client).patch({ +export const updateGitProviderCredentials = (options: Options): RequestResult => (options.client ?? client).patch({ security: [{ scheme: 'bearer', type: 'http' }], url: '/git-providers/{provider_id}/credentials', ...options, @@ -3115,7 +3078,7 @@ export const updateGitProviderCredentials = (options: Options) => (options.client ?? client).post({ +export const deactivateProvider = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/git-providers/{provider_id}/deactivate', ...options @@ -3124,7 +3087,7 @@ export const deactivateProvider = (options /** * Check if a git provider can be safely deleted */ -export const checkProviderDeletionSafety = (options: Options) => (options.client ?? client).get({ +export const checkProviderDeletionSafety = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/git-providers/{provider_id}/deletion-check', ...options @@ -3133,7 +3096,7 @@ export const checkProviderDeletionSafety = (options: Options) => (options.client ?? client).get({ +export const startGitProviderOauth = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/git-providers/{provider_id}/oauth/authorize', ...options @@ -3145,7 +3108,7 @@ export const startGitProviderOauth = (opti * Lists repositories synced to the database across every connection under * this provider, with the same pagination/filtering as `/repositories`. */ -export const listRepositoriesByProvider = (options: Options) => (options.client ?? client).get({ +export const listRepositoriesByProvider = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/git-providers/{provider_id}/repositories', ...options @@ -3154,7 +3117,7 @@ export const listRepositoriesByProvider = /** * Safely delete a git provider (only if no projects are using it) */ -export const deleteProviderSafely = (options: Options) => (options.client ?? client).delete({ +export const deleteProviderSafely = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/git-providers/{provider_id}/safe-delete', ...options @@ -3163,22 +3126,22 @@ export const deleteProviderSafely = (optio /** * Get information about a public repository (supports GitHub and GitLab) */ -export const getPublicRepository = (options: Options) => (options.client ?? client).get({ url: '/git/public/{provider}/{owner}/{repo}', ...options }); +export const getPublicRepository = (options: Options): RequestResult => (options.client ?? client).get({ url: '/git/public/{provider}/{owner}/{repo}', ...options }); /** * Get branches for a public repository (supports GitHub and GitLab) */ -export const getPublicBranches = (options: Options) => (options.client ?? client).get({ url: '/git/public/{provider}/{owner}/{repo}/branches', ...options }); +export const getPublicBranches = (options: Options): RequestResult => (options.client ?? client).get({ url: '/git/public/{provider}/{owner}/{repo}/branches', ...options }); /** * Detect presets for a public repository (supports GitHub and GitLab) */ -export const detectPublicPresets = (options: Options) => (options.client ?? client).get({ url: '/git/public/{provider}/{owner}/{repo}/presets', ...options }); +export const detectPublicPresets = (options: Options): RequestResult => (options.client ?? client).get({ url: '/git/public/{provider}/{owner}/{repo}/presets', ...options }); /** * Discover workloads from a source */ -export const discoverWorkloads = (options: Options) => (options.client ?? client).post({ +export const discoverWorkloads = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/imports/discover', ...options, @@ -3191,7 +3154,7 @@ export const discoverWorkloads = (options: /** * Execute an import */ -export const executeImport = (options: Options) => (options.client ?? client).post({ +export const executeImport = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/imports/execute', ...options, @@ -3204,7 +3167,7 @@ export const executeImport = (options: Opt /** * Create an import plan */ -export const createPlan = (options: Options) => (options.client ?? client).post({ +export const createPlan = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/imports/plan', ...options, @@ -3217,7 +3180,7 @@ export const createPlan = (options: Option /** * List available import sources */ -export const listSources = (options?: Options) => (options?.client ?? client).get({ +export const listSources = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/imports/sources', ...options @@ -3226,7 +3189,7 @@ export const listSources = (options?: Opti /** * Get import status */ -export const getImportStatus = (options: Options) => (options.client ?? client).get({ +export const getImportStatus = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/imports/{session_id}', ...options @@ -3235,7 +3198,7 @@ export const getImportStatus = (options: O /** * Get an incident by ID */ -export const getIncident = (options: Options) => (options.client ?? client).get({ +export const getIncident = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/incidents/{incident_id}', ...options @@ -3244,7 +3207,7 @@ export const getIncident = (options: Optio /** * Update incident status */ -export const updateIncidentStatus = (options: Options) => (options.client ?? client).patch({ +export const updateIncidentStatus = (options: Options): RequestResult => (options.client ?? client).patch({ security: [{ scheme: 'bearer', type: 'http' }], url: '/incidents/{incident_id}/status', ...options, @@ -3257,7 +3220,7 @@ export const updateIncidentStatus = (optio /** * Get incident updates */ -export const getIncidentUpdates = (options: Options) => (options.client ?? client).get({ +export const getIncidentUpdates = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/incidents/{incident_id}/updates', ...options @@ -3266,7 +3229,7 @@ export const getIncidentUpdates = (options /** * List all registered nodes (admin — session auth via RequireAuth) */ -export const adminListNodes = (options?: Options) => (options?.client ?? client).get({ +export const adminListNodes = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/internal/nodes', ...options @@ -3275,7 +3238,7 @@ export const adminListNodes = (options?: O /** * Register a new worker node or reconnect an existing one */ -export const registerNode = (options: Options) => (options.client ?? client).post({ +export const registerNode = (options: Options): RequestResult => (options.client ?? client).post({ url: '/internal/nodes/register', ...options, headers: { @@ -3289,7 +3252,7 @@ export const registerNode = (options: Opti * to ensure containers have been rescheduled. If the node still has active * containers, it will be drained automatically before removal. */ -export const adminRemoveNode = (options: Options) => (options.client ?? client).delete({ +export const adminRemoveNode = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/internal/nodes/{node_id}', ...options @@ -3298,7 +3261,7 @@ export const adminRemoveNode = (options: O /** * Get a specific node by ID (admin — session auth via RequireAuth) */ -export const adminGetNode = (options: Options) => (options.client ?? client).get({ +export const adminGetNode = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/internal/nodes/{node_id}', ...options @@ -3307,7 +3270,7 @@ export const adminGetNode = (options: Opti /** * List all containers running on a specific node */ -export const adminListNodeContainers = (options: Options) => (options.client ?? client).get({ +export const adminListNodeContainers = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/internal/nodes/{node_id}/containers', ...options @@ -3316,7 +3279,7 @@ export const adminListNodeContainers = (op /** * `POST /internal/nodes/{node_id}/dns/ack` */ -export const postDnsAck = (options: Options) => (options.client ?? client).post({ +export const postDnsAck = (options: Options): RequestResult => (options.client ?? client).post({ url: '/internal/nodes/{node_id}/dns/ack', ...options, headers: { @@ -3328,13 +3291,13 @@ export const postDnsAck = (options: Option /** * `GET /internal/nodes/{node_id}/dns/changes?since=N` */ -export const getDnsChanges = (options: Options) => (options.client ?? client).get({ url: '/internal/nodes/{node_id}/dns/changes', ...options }); +export const getDnsChanges = (options: Options): RequestResult => (options.client ?? client).get({ url: '/internal/nodes/{node_id}/dns/changes', ...options }); /** * Undrain (reactivate) a node so it can accept new deployments again. * Only works for nodes in "draining" or "drained" status. */ -export const adminUndrainNode = (options: Options) => (options.client ?? client).delete({ +export const adminUndrainNode = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/internal/nodes/{node_id}/drain', ...options @@ -3346,7 +3309,7 @@ export const adminUndrainNode = (options: * Returns container counts and whether the drain is complete. * Can be polled to track drain progress. */ -export const adminDrainStatus = (options: Options) => (options.client ?? client).get({ +export const adminDrainStatus = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/internal/nodes/{node_id}/drain', ...options @@ -3357,7 +3320,7 @@ export const adminDrainStatus = (options: * and trigger redeployment of all affected environments so their containers * are rescheduled to healthy nodes. */ -export const adminDrainNode = (options: Options) => (options.client ?? client).post({ +export const adminDrainNode = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/internal/nodes/{node_id}/drain', ...options @@ -3366,7 +3329,7 @@ export const adminDrainNode = (options: Op /** * Receive a heartbeat from a worker node */ -export const nodeHeartbeat = (options: Options) => (options.client ?? client).post({ +export const nodeHeartbeat = (options: Options): RequestResult => (options.client ?? client).post({ url: '/internal/nodes/{node_id}/heartbeat', ...options, headers: { @@ -3378,7 +3341,7 @@ export const nodeHeartbeat = (options: Opt /** * `GET /internal/nodes/{node_id}/network/peers` */ -export const listPeers = (options: Options) => (options.client ?? client).get({ url: '/internal/nodes/{node_id}/network/peers', ...options }); +export const listPeers = (options: Options): RequestResult => (options.client ?? client).get({ url: '/internal/nodes/{node_id}/network/peers', ...options }); /** * Get decrypted S3 credentials for a backup/restore operation. @@ -3387,12 +3350,12 @@ export const listPeers = (options: Options * or download backups. The credentials are decrypted from the stored S3 source * and returned over the authenticated TLS/WireGuard channel. */ -export const getS3Credentials = (options: Options) => (options.client ?? client).get({ url: '/internal/nodes/{node_id}/s3-credentials/{s3_source_id}', ...options }); +export const getS3Credentials = (options: Options): RequestResult => (options.client ?? client).get({ url: '/internal/nodes/{node_id}/s3-credentials/{s3_source_id}', ...options }); /** * List all IP access control rules */ -export const listIpAccessControl = (options?: Options) => (options?.client ?? client).get({ +export const listIpAccessControl = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/ip-access-control', ...options @@ -3401,7 +3364,7 @@ export const listIpAccessControl = (option /** * Create a new IP access control rule */ -export const createIpAccessControl = (options: Options) => (options.client ?? client).post({ +export const createIpAccessControl = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/ip-access-control', ...options, @@ -3414,7 +3377,7 @@ export const createIpAccessControl = (opti /** * Check if an IP address is blocked */ -export const checkIpBlocked = (options: Options) => (options.client ?? client).get({ +export const checkIpBlocked = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/ip-access-control/check/{ip}', ...options @@ -3423,7 +3386,7 @@ export const checkIpBlocked = (options: Op /** * Delete an IP access control rule */ -export const deleteIpAccessControl = (options: Options) => (options.client ?? client).delete({ +export const deleteIpAccessControl = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/ip-access-control/{id}', ...options @@ -3432,7 +3395,7 @@ export const deleteIpAccessControl = (opti /** * Get a single IP access control rule by ID */ -export const getIpAccessControl = (options: Options) => (options.client ?? client).get({ +export const getIpAccessControl = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/ip-access-control/{id}', ...options @@ -3441,7 +3404,7 @@ export const getIpAccessControl = (options /** * Update an IP access control rule */ -export const updateIpAccessControl = (options: Options) => (options.client ?? client).patch({ +export const updateIpAccessControl = (options: Options): RequestResult => (options.client ?? client).patch({ security: [{ scheme: 'bearer', type: 'http' }], url: '/ip-access-control/{id}', ...options, @@ -3454,7 +3417,7 @@ export const updateIpAccessControl = (opti /** * Delete one or more keys */ -export const kvDel = (options: Options) => (options.client ?? client).post({ +export const kvDel = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/kv/del', ...options, @@ -3467,7 +3430,7 @@ export const kvDel = (options: Options(options?: Options) => (options?.client ?? client).delete({ +export const kvDisable = (options?: Options): RequestResult => (options?.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/kv/disable', ...options @@ -3476,7 +3439,7 @@ export const kvDisable = (options?: Option /** * Enable KV service */ -export const kvEnable = (options: Options) => (options.client ?? client).post({ +export const kvEnable = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/kv/enable', ...options, @@ -3489,7 +3452,7 @@ export const kvEnable = (options: Options< /** * Set expiration on a key */ -export const kvExpire = (options: Options) => (options.client ?? client).post({ +export const kvExpire = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/kv/expire', ...options, @@ -3502,7 +3465,7 @@ export const kvExpire = (options: Options< /** * Get a value by key */ -export const kvGet = (options: Options) => (options.client ?? client).post({ +export const kvGet = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/kv/get', ...options, @@ -3515,7 +3478,7 @@ export const kvGet = (options: Options(options: Options) => (options.client ?? client).post({ +export const kvIncr = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/kv/incr', ...options, @@ -3528,7 +3491,7 @@ export const kvIncr = (options: Options(options: Options) => (options.client ?? client).post({ +export const kvKeys = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/kv/keys', ...options, @@ -3541,7 +3504,7 @@ export const kvKeys = (options: Options(options: Options) => (options.client ?? client).post({ +export const kvSet = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/kv/set', ...options, @@ -3554,7 +3517,7 @@ export const kvSet = (options: Options(options?: Options) => (options?.client ?? client).get({ +export const kvStatus = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/kv/status', ...options @@ -3563,7 +3526,7 @@ export const kvStatus = (options?: Options /** * Get time-to-live for a key */ -export const kvTtl = (options: Options) => (options.client ?? client).post({ +export const kvTtl = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/kv/ttl', ...options, @@ -3576,7 +3539,7 @@ export const kvTtl = (options: Options(options: Options) => (options.client ?? client).patch({ +export const kvUpdate = (options: Options): RequestResult => (options.client ?? client).patch({ security: [{ scheme: 'bearer', type: 'http' }], url: '/kv/update', ...options, @@ -3586,9 +3549,9 @@ export const kvUpdate = (options: Options< } }); -export const listRoutes = (options?: Options) => (options?.client ?? client).get({ url: '/lb/routes', ...options }); +export const listRoutes = (options?: Options): RequestResult => (options?.client ?? client).get({ url: '/lb/routes', ...options }); -export const createRoute = (options: Options) => (options.client ?? client).post({ +export const createRoute = (options: Options): RequestResult => (options.client ?? client).post({ url: '/lb/routes', ...options, headers: { @@ -3597,11 +3560,11 @@ export const createRoute = (options: Optio } }); -export const deleteRoute = (options: Options) => (options.client ?? client).delete({ url: '/lb/routes/{domain}', ...options }); +export const deleteRoute = (options: Options): RequestResult => (options.client ?? client).delete({ url: '/lb/routes/{domain}', ...options }); -export const getRoute = (options: Options) => (options.client ?? client).get({ url: '/lb/routes/{domain}', ...options }); +export const getRoute = (options: Options): RequestResult => (options.client ?? client).get({ url: '/lb/routes/{domain}', ...options }); -export const updateRoute = (options: Options) => (options.client ?? client).put({ +export const updateRoute = (options: Options): RequestResult => (options.client ?? client).put({ url: '/lb/routes/{domain}', ...options, headers: { @@ -3610,12 +3573,12 @@ export const updateRoute = (options: Optio } }); -export const logout = (options?: Options) => (options?.client ?? client).post({ url: '/logout', ...options }); +export const logout = (options?: Options): RequestResult => (options?.client ?? client).post({ url: '/logout', ...options }); /** * Get context lines surrounding a specific log line */ -export const getLogContext = (options: Options) => (options.client ?? client).get({ +export const getLogContext = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/logs/context', ...options @@ -3624,7 +3587,7 @@ export const getLogContext = (options: Opt /** * Search logs with structured filters and full text search */ -export const searchLogs = (options: Options) => (options.client ?? client).post({ +export const searchLogs = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/logs/search', ...options, @@ -3637,7 +3600,7 @@ export const searchLogs = (options: Option /** * Live tail logs via Server-Sent Events */ -export const tailLogs = (options: Options) => (options.client ?? client).get({ +export const tailLogs = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/logs/tail', ...options @@ -3646,7 +3609,7 @@ export const tailLogs = (options: Options< /** * Get monitor-based health summaries for multiple projects in a single query */ -export const getProjectsMonitorHealth = (options: Options) => (options.client ?? client).get({ +export const getProjectsMonitorHealth = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/monitors-health/projects', ...options @@ -3655,7 +3618,7 @@ export const getProjectsMonitorHealth = (o /** * Delete a monitor */ -export const deleteMonitor = (options: Options) => (options.client ?? client).delete({ +export const deleteMonitor = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/monitors/{monitor_id}', ...options @@ -3664,7 +3627,7 @@ export const deleteMonitor = (options: Opt /** * Get a monitor by ID */ -export const getMonitor = (options: Options) => (options.client ?? client).get({ +export const getMonitor = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/monitors/{monitor_id}', ...options @@ -3673,7 +3636,7 @@ export const getMonitor = (options: Option /** * Get bucketed status data for a monitor using TimescaleDB */ -export const getBucketedStatus = (options: Options) => (options.client ?? client).get({ +export const getBucketedStatus = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/monitors/{monitor_id}/bucketed', ...options @@ -3682,7 +3645,7 @@ export const getBucketedStatus = (options: /** * Get current status and uptime metrics for a monitor */ -export const getCurrentMonitorStatus = (options: Options) => (options.client ?? client).get({ +export const getCurrentMonitorStatus = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/monitors/{monitor_id}/current-status', ...options @@ -3691,7 +3654,7 @@ export const getCurrentMonitorStatus = (op /** * Get uptime history for a monitor */ -export const getUptimeHistory = (options: Options) => (options.client ?? client).get({ +export const getUptimeHistory = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/monitors/{monitor_id}/uptime', ...options @@ -3700,7 +3663,7 @@ export const getUptimeHistory = (options: /** * Fetch a time-series range for a single metric on a node. */ -export const nodeMetricsGetRange = (options: Options) => (options.client ?? client).get({ +export const nodeMetricsGetRange = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/nodes/{id}/metrics', ...options @@ -3709,7 +3672,7 @@ export const nodeMetricsGetRange = (option /** * Delete notification preferences */ -export const deletePreferences = (options?: Options) => (options?.client ?? client).delete({ +export const deletePreferences = (options?: Options): RequestResult => (options?.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/notification-preferences', ...options @@ -3718,7 +3681,7 @@ export const deletePreferences = (options? /** * Get notification preferences */ -export const getPreferences = (options?: Options) => (options?.client ?? client).get({ +export const getPreferences = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/notification-preferences', ...options @@ -3727,7 +3690,7 @@ export const getPreferences = (options?: O /** * Update notification preferences */ -export const updatePreferences = (options: Options) => (options.client ?? client).put({ +export const updatePreferences = (options: Options): RequestResult => (options.client ?? client).put({ security: [{ scheme: 'bearer', type: 'http' }], url: '/notification-preferences', ...options, @@ -3740,7 +3703,7 @@ export const updatePreferences = (options: /** * List all notification providers */ -export const listNotificationProviders = (options?: Options) => (options?.client ?? client).get({ +export const listNotificationProviders = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/notification-providers', ...options @@ -3749,7 +3712,7 @@ export const listNotificationProviders = ( /** * Create a new notification provider */ -export const createNotificationProvider = (options: Options) => (options.client ?? client).post({ +export const createNotificationProvider = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/notification-providers', ...options, @@ -3762,7 +3725,7 @@ export const createNotificationProvider = /** * Create a new Cloudflare Email Sending notification provider */ -export const createCloudflareProvider = (options: Options) => (options.client ?? client).post({ +export const createCloudflareProvider = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/notification-providers/cloudflare', ...options, @@ -3775,7 +3738,7 @@ export const createCloudflareProvider = (o /** * Update a Cloudflare Email Sending notification provider */ -export const updateCloudflareProvider = (options: Options) => (options.client ?? client).put({ +export const updateCloudflareProvider = (options: Options): RequestResult => (options.client ?? client).put({ security: [{ scheme: 'bearer', type: 'http' }], url: '/notification-providers/cloudflare/{id}', ...options, @@ -3788,7 +3751,7 @@ export const updateCloudflareProvider = (o /** * Create a new Email notification provider */ -export const createNotificationEmailProvider = (options: Options) => (options.client ?? client).post({ +export const createNotificationEmailProvider = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/notification-providers/email', ...options, @@ -3801,7 +3764,7 @@ export const createNotificationEmailProvider = (options: Options) => (options.client ?? client).put({ +export const updateNotificationEmailProvider = (options: Options): RequestResult => (options.client ?? client).put({ security: [{ scheme: 'bearer', type: 'http' }], url: '/notification-providers/email/{id}', ...options, @@ -3814,7 +3777,7 @@ export const updateNotificationEmailProvider = (options: Options) => (options.client ?? client).post({ +export const createSlackProvider = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/notification-providers/slack', ...options, @@ -3827,7 +3790,7 @@ export const createSlackProvider = (option /** * Update a Slack notification provider */ -export const updateSlackProvider = (options: Options) => (options.client ?? client).put({ +export const updateSlackProvider = (options: Options): RequestResult => (options.client ?? client).put({ security: [{ scheme: 'bearer', type: 'http' }], url: '/notification-providers/slack/{id}', ...options, @@ -3845,7 +3808,7 @@ export const updateSlackProvider = (option * The webhook will receive a JSON payload with notification details including: * id, title, message, type, priority, severity, timestamp, and metadata. */ -export const createWebhookProvider = (options: Options) => (options.client ?? client).post({ +export const createWebhookProvider = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/notification-providers/webhook', ...options, @@ -3858,7 +3821,7 @@ export const createWebhookProvider = (opti /** * Update a Webhook notification provider */ -export const updateWebhookProvider = (options: Options) => (options.client ?? client).put({ +export const updateWebhookProvider = (options: Options): RequestResult => (options.client ?? client).put({ security: [{ scheme: 'bearer', type: 'http' }], url: '/notification-providers/webhook/{id}', ...options, @@ -3871,7 +3834,7 @@ export const updateWebhookProvider = (opti /** * Delete a notification provider */ -export const deleteNotificationProvider = (options: Options) => (options.client ?? client).delete({ +export const deleteNotificationProvider = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/notification-providers/{id}', ...options @@ -3880,7 +3843,7 @@ export const deleteNotificationProvider = /** * Get a single notification provider */ -export const getNotificationProvider = (options: Options) => (options.client ?? client).get({ +export const getNotificationProvider = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/notification-providers/{id}', ...options @@ -3889,7 +3852,7 @@ export const getNotificationProvider = (op /** * Update a notification provider */ -export const updateNotificationProvider = (options: Options) => (options.client ?? client).put({ +export const updateNotificationProvider = (options: Options): RequestResult => (options.client ?? client).put({ security: [{ scheme: 'bearer', type: 'http' }], url: '/notification-providers/{id}', ...options, @@ -3899,7 +3862,7 @@ export const updateNotificationProvider = } }); -export const revealNotificationProviderConfig = (options: Options) => (options.client ?? client).get({ +export const revealNotificationProviderConfig = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/notification-providers/{id}/config/{field}', ...options @@ -3908,7 +3871,7 @@ export const revealNotificationProviderConfig = (options: Options) => (options.client ?? client).post({ +export const testNotificationProvider = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/notification-providers/{id}/test', ...options @@ -3917,7 +3880,7 @@ export const testNotificationProvider = (o /** * List all ACME orders */ -export const listOrders = (options?: Options) => (options?.client ?? client).get({ +export const listOrders = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/orders', ...options @@ -3926,7 +3889,7 @@ export const listOrders = (options?: Optio /** * List alert rules for a project (newest first, paginated). */ -export const listAlerts = (options: Options) => (options.client ?? client).get({ +export const listAlerts = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/otel/alerts', ...options @@ -3935,7 +3898,7 @@ export const listAlerts = (options: Option /** * Create a new alert rule for a project. */ -export const createAlert = (options: Options) => (options.client ?? client).post({ +export const createAlert = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/otel/alerts', ...options, @@ -3952,7 +3915,7 @@ export const createAlert = (options: Optio * the per-bucket band + which points would have fired. Powers the form's * "would this have fired?" preview and the explorer band overlay. Read-only. */ -export const previewAlert = (options: Options) => (options.client ?? client).post({ +export const previewAlert = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/otel/alerts/preview', ...options, @@ -3965,7 +3928,7 @@ export const previewAlert = (options: Opti /** * Delete an alert rule. */ -export const deleteAlert = (options: Options) => (options.client ?? client).delete({ +export const deleteAlert = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/otel/alerts/{id}', ...options @@ -3974,7 +3937,7 @@ export const deleteAlert = (options: Optio /** * Fetch a single alert rule by id. */ -export const getAlert = (options: Options) => (options.client ?? client).get({ +export const getAlert = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/otel/alerts/{id}', ...options @@ -3983,7 +3946,7 @@ export const getAlert = (options: Options< /** * Update an alert rule's fields. */ -export const updateAlert = (options: Options) => (options.client ?? client).patch({ +export const updateAlert = (options: Options): RequestResult => (options.client ?? client).patch({ security: [{ scheme: 'bearer', type: 'http' }], url: '/otel/alerts/{id}', ...options, @@ -3996,7 +3959,7 @@ export const updateAlert = (options: Optio /** * List dashboards for a project (newest first, paginated). */ -export const listDashboards = (options: Options) => (options.client ?? client).get({ +export const listDashboards = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/otel/dashboards', ...options @@ -4005,7 +3968,7 @@ export const listDashboards = (options: Op /** * Create a new dashboard for a project. */ -export const createDashboard = (options: Options) => (options.client ?? client).post({ +export const createDashboard = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/otel/dashboards', ...options, @@ -4018,7 +3981,7 @@ export const createDashboard = (options: O /** * Delete a dashboard. */ -export const deleteDashboard = (options: Options) => (options.client ?? client).delete({ +export const deleteDashboard = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/otel/dashboards/{id}', ...options @@ -4027,7 +3990,7 @@ export const deleteDashboard = (options: O /** * Fetch a single dashboard by id. */ -export const getDashboard = (options: Options) => (options.client ?? client).get({ +export const getDashboard = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/otel/dashboards/{id}', ...options @@ -4036,7 +3999,7 @@ export const getDashboard = (options: Opti /** * Update a dashboard's name and/or layout. */ -export const updateDashboard = (options: Options) => (options.client ?? client).patch({ +export const updateDashboard = (options: Options): RequestResult => (options.client ?? client).patch({ security: [{ scheme: 'bearer', type: 'http' }], url: '/otel/dashboards/{id}', ...options, @@ -4054,7 +4017,7 @@ export const updateDashboard = (options: O * OTel GenAI semantic conventions, which use **seconds** (a fractional * double), not milliseconds — do not read them as ms without converting. */ -export const queryGenaiTraces = (options: Options) => (options.client ?? client).get({ +export const queryGenaiTraces = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/otel/genai/traces', ...options @@ -4068,7 +4031,7 @@ export const queryGenaiTraces = (options: * OTel GenAI semantic conventions, which use **seconds** (a fractional * double), not milliseconds — do not read them as ms without converting. */ -export const getGenaiTrace = (options: Options) => (options.client ?? client).get({ +export const getGenaiTrace = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/otel/genai/traces/{project_id}/{trace_id}', ...options @@ -4083,7 +4046,7 @@ export const getGenaiTrace = (options: Opt * `truncated: true` signals a hit on either cap; `truncated_projects` * lists the dropped project IDs. See ADR-027 §4 for the full design. */ -export const getUnifiedTrace = (options: Options) => (options.client ?? client).get({ +export const getUnifiedTrace = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/otel/global/traces/{trace_id}', ...options @@ -4092,7 +4055,7 @@ export const getUnifiedTrace = (options: O /** * Get health summaries for a project. */ -export const getHealth = (options: Options) => (options.client ?? client).get({ +export const getHealth = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/otel/health/{project_id}', ...options @@ -4101,7 +4064,7 @@ export const getHealth = (options: Options /** * List anomaly insights for a project. */ -export const listInsights = (options: Options) => (options.client ?? client).get({ +export const listInsights = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/otel/insights/{project_id}', ...options @@ -4110,7 +4073,7 @@ export const listInsights = (options: Opti /** * Query log records with optional filters. */ -export const queryLogs = (options: Options) => (options.client ?? client).get({ +export const queryLogs = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/otel/logs', ...options @@ -4120,7 +4083,7 @@ export const queryLogs = (options: Options * List the attribute (label) keys observed on a metric — powers the * label-filter key autocomplete. */ -export const listMetricLabelKeys = (options: Options) => (options.client ?? client).get({ +export const listMetricLabelKeys = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/otel/metric-label-keys', ...options @@ -4130,7 +4093,7 @@ export const listMetricLabelKeys = (option * List the distinct values seen for a label key on a metric — powers value * autocomplete once a key is chosen. */ -export const listMetricLabelValues = (options: Options) => (options.client ?? client).get({ +export const listMetricLabelValues = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/otel/metric-label-values', ...options @@ -4139,7 +4102,7 @@ export const listMetricLabelValues = (opti /** * List distinct metric names for a project. */ -export const listMetricNames = (options: Options) => (options.client ?? client).get({ +export const listMetricNames = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/otel/metric-names/{project_id}', ...options @@ -4148,7 +4111,7 @@ export const listMetricNames = (options: O /** * Query metrics with time bucketing. */ -export const queryMetrics = (options: Options) => (options.client ?? client).get({ +export const queryMetrics = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/otel/metrics', ...options @@ -4157,7 +4120,7 @@ export const queryMetrics = (options: Opti /** * Get OTel pipeline statistics (admin/system view). */ -export const getPipelineStats = (options?: Options) => (options?.client ?? client).get({ +export const getPipelineStats = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/otel/pipeline-stats', ...options @@ -4166,7 +4129,7 @@ export const getPipelineStats = (options?: /** * Get storage quota for a project. */ -export const getQuota = (options: Options) => (options.client ?? client).get({ +export const getQuota = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/otel/quota/{project_id}', ...options @@ -4176,7 +4139,7 @@ export const getQuota = (options: Options< * Query trace summaries — one row per trace with span count, error count, * root span info, and proper trace-level pagination. */ -export const queryTraceSummaries = (options: Options) => (options.client ?? client).get({ +export const queryTraceSummaries = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/otel/trace-summaries', ...options @@ -4194,7 +4157,7 @@ export const queryTraceSummaries = (option * numeric value shares `duration_ms`'s unit, and never state a duration in * milliseconds unless it came from a `duration_ms` field. */ -export const queryTraces = (options: Options) => (options.client ?? client).get({ +export const queryTraces = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/otel/traces', ...options @@ -4208,7 +4171,7 @@ export const queryTraces = (options: Optio * without a second round-trip. See ADR-027 §3 for the full auth model and * topology-disclosure trade-offs. */ -export const getCrossProjectTraceSiblings = (options: Options) => (options.client ?? client).get({ +export const getCrossProjectTraceSiblings = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/otel/traces/cross-project/{trace_id}', ...options @@ -4227,7 +4190,7 @@ export const getCrossProjectTraceSiblings = (options: Options) => (options.client ?? client).get({ +export const getTrace = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/otel/traces/{project_id}/{trace_id}', ...options @@ -4240,7 +4203,7 @@ export const getTrace = (options: Options< * checks rate limit and storage quota, routes high-severity logs * to DB and all logs to S3. */ -export const ingestLogs = (options: Options) => (options.client ?? client).post({ +export const ingestLogs = (options: Options): RequestResult => (options.client ?? client).post({ url: '/otel/v1/logs', ...options, headers: { @@ -4255,7 +4218,7 @@ export const ingestLogs = (options: Option * Authenticates via API key in header, decompresses, decodes protobuf, * checks rate limit and storage quota, then stores. */ -export const ingestMetrics = (options: Options) => (options.client ?? client).post({ +export const ingestMetrics = (options: Options): RequestResult => (options.client ?? client).post({ url: '/otel/v1/metrics', ...options, headers: { @@ -4270,7 +4233,7 @@ export const ingestMetrics = (options: Opt * Authenticates via API key in header, decompresses, decodes protobuf, * checks rate limit and storage quota, then stores spans. */ -export const ingestTraces = (options: Options) => (options.client ?? client).post({ +export const ingestTraces = (options: Options): RequestResult => (options.client ?? client).post({ url: '/otel/v1/traces', ...options, headers: { @@ -4282,7 +4245,7 @@ export const ingestTraces = (options: Opti /** * Ingest log records with project/environment/deployment in the URL path. */ -export const ingestLogsByPath = (options: Options) => (options.client ?? client).post({ +export const ingestLogsByPath = (options: Options): RequestResult => (options.client ?? client).post({ url: '/otel/v1/{project_id}/{environment_id}/{deployment_id}/logs', ...options, headers: { @@ -4294,7 +4257,7 @@ export const ingestLogsByPath = (options: /** * Ingest metrics with project/environment/deployment in the URL path. */ -export const ingestMetricsByPath = (options: Options) => (options.client ?? client).post({ +export const ingestMetricsByPath = (options: Options): RequestResult => (options.client ?? client).post({ url: '/otel/v1/{project_id}/{environment_id}/{deployment_id}/metrics', ...options, headers: { @@ -4306,7 +4269,7 @@ export const ingestMetricsByPath = (option /** * Ingest trace spans with project/environment/deployment in the URL path. */ -export const ingestTracesByPath = (options: Options) => (options.client ?? client).post({ +export const ingestTracesByPath = (options: Options): RequestResult => (options.client ?? client).post({ url: '/otel/v1/{project_id}/{environment_id}/{deployment_id}/traces', ...options, headers: { @@ -4318,7 +4281,7 @@ export const ingestTracesByPath = (options /** * Check if performance metrics exist for a project */ -export const hasPerformanceMetrics = (options: Options) => (options.client ?? client).get({ +export const hasPerformanceMetrics = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/performance/has-metrics', ...options @@ -4327,7 +4290,7 @@ export const hasPerformanceMetrics = (opti /** * Get performance metrics */ -export const getPerformanceMetrics = (options: Options) => (options.client ?? client).get({ +export const getPerformanceMetrics = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/performance/metrics', ...options @@ -4336,7 +4299,7 @@ export const getPerformanceMetrics = (opti /** * Get metrics over time */ -export const getMetricsOverTime = (options: Options) => (options.client ?? client).get({ +export const getMetricsOverTime = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/performance/metrics-over-time', ...options @@ -4345,7 +4308,7 @@ export const getMetricsOverTime = (options /** * Get grouped page metrics */ -export const getGroupedPageMetrics = (options: Options) => (options.client ?? client).get({ +export const getGroupedPageMetrics = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/performance/page-metrics', ...options @@ -4357,7 +4320,7 @@ export const getGroupedPageMetrics = (opti * Returns details about the server's access mode, public IP address, private IP address, * and domain creation capabilities. Both IP addresses are always included when available. */ -export const getAccessInfo = (options?: Options) => (options?.client ?? client).get({ +export const getAccessInfo = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/platform/access-info', ...options @@ -4366,7 +4329,7 @@ export const getAccessInfo = (options?: Op /** * Get private/local IP address of the server */ -export const getPrivateIp = (options?: Options) => (options?.client ?? client).get({ +export const getPrivateIp = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/platform/private-ip', ...options @@ -4375,7 +4338,7 @@ export const getPrivateIp = (options?: Opt /** * Get public IP address of the server */ -export const getPublicIp = (options?: Options) => (options?.client ?? client).get({ +export const getPublicIp = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/platform/public-ip', ...options @@ -4384,7 +4347,7 @@ export const getPublicIp = (options?: Opti /** * List all available presets */ -export const listPresets = (options?: Options) => (options?.client ?? client).get({ +export const listPresets = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/presets', ...options @@ -4397,7 +4360,7 @@ export const listPresets = (options?: Opti * The CLI can use this to build Docker images locally without needing a Dockerfile * in the project directory, enabling zero-config deployments. */ -export const generatePresetDockerfile = (options: Options) => (options.client ?? client).post({ +export const generatePresetDockerfile = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/presets/{slug}/dockerfile', ...options, @@ -4407,25 +4370,25 @@ export const generatePresetDockerfile = (o } }); -export const getPreviewGatewayLogs = (options?: Options) => (options?.client ?? client).get({ +export const getPreviewGatewayLogs = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/preview-gateway/logs', ...options }); -export const restartPreviewGateway = (options?: Options) => (options?.client ?? client).post({ +export const restartPreviewGateway = (options?: Options): RequestResult => (options?.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/preview-gateway/restart', ...options }); -export const getPreviewGatewaySettings = (options?: Options) => (options?.client ?? client).get({ +export const getPreviewGatewaySettings = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/preview-gateway/settings', ...options }); -export const patchPreviewGatewaySettings = (options: Options) => (options.client ?? client).patch({ +export const patchPreviewGatewaySettings = (options: Options): RequestResult => (options.client ?? client).patch({ security: [{ scheme: 'bearer', type: 'http' }], url: '/preview-gateway/settings', ...options, @@ -4435,13 +4398,13 @@ export const patchPreviewGatewaySettings = (options?: Options) => (options?.client ?? client).get({ +export const getPreviewGatewayStatus = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/preview-gateway/status', ...options }); -export const upgradePreviewGateway = (options: Options) => (options.client ?? client).post({ +export const upgradePreviewGateway = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/preview-gateway/upgrade', ...options, @@ -4454,7 +4417,7 @@ export const upgradePreviewGateway = (opti /** * Get a list of all projects */ -export const getProjects = (options?: Options) => (options?.client ?? client).get({ +export const getProjects = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects', ...options @@ -4463,7 +4426,7 @@ export const getProjects = (options?: Opti /** * Create a new project */ -export const createProject = (options: Options) => (options.client ?? client).post({ +export const createProject = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects', ...options, @@ -4476,7 +4439,7 @@ export const createProject = (options: Opt /** * Get details of a specific project by slug */ -export const getProjectBySlug = (options: Options) => (options.client ?? client).get({ +export const getProjectBySlug = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/by-slug/{slug}', ...options @@ -4489,7 +4452,7 @@ export const getProjectBySlug = (options: * specified configuration. The template is cloned to a new repository under * the authenticated user's account or specified organization. */ -export const createProjectFromTemplate = (options: Options) => (options.client ?? client).post({ +export const createProjectFromTemplate = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/from-template', ...options, @@ -4502,13 +4465,13 @@ export const createProjectFromTemplate = ( /** * Get project statistics */ -export const getProjectStatistics = (options?: Options) => (options?.client ?? client).get({ +export const getProjectStatistics = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/statistics', ...options }); -export const deleteProject = (options: Options) => (options.client ?? client).delete({ +export const deleteProject = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{id}', ...options @@ -4517,13 +4480,13 @@ export const deleteProject = (options: Opt /** * Get details of a specific project */ -export const getProject = (options: Options) => (options.client ?? client).get({ +export const getProject = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{id}', ...options }); -export const updateProject = (options: Options) => (options.client ?? client).put({ +export const updateProject = (options: Options): RequestResult => (options.client ?? client).put({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{id}', ...options, @@ -4533,12 +4496,12 @@ export const updateProject = (options: Opt } }); -export const getProjectDeployments = (options: Options) => (options.client ?? client).get({ url: '/projects/{id}/deployments', ...options }); +export const getProjectDeployments = (options: Options): RequestResult => (options.client ?? client).get({ url: '/projects/{id}/deployments', ...options }); /** * Get the last deployment for a specific project */ -export const getLastDeployment = (options: Options) => (options.client ?? client).get({ url: '/projects/{id}/last-deployment', ...options }); +export const getLastDeployment = (options: Options): RequestResult => (options.client ?? client).get({ url: '/projects/{id}/last-deployment', ...options }); /** * Change a project's source type to a Git-less type (docker_image / @@ -4546,7 +4509,7 @@ export const getLastDeployment = (options: * endpoint (`POST /projects/{id}/git`), which also supplies the repository and * provider connection. */ -export const changeProjectSource = (options: Options) => (options.client ?? client).patch({ +export const changeProjectSource = (options: Options): RequestResult => (options.client ?? client).patch({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{id}/source', ...options, @@ -4559,7 +4522,7 @@ export const changeProjectSource = (option /** * Trigger pipeline for a specific project */ -export const triggerProjectPipeline = (options: Options) => (options.client ?? client).post({ +export const triggerProjectPipeline = (options: Options): RequestResult => (options.client ?? client).post({ url: '/projects/{id}/trigger-pipeline', ...options, headers: { @@ -4568,13 +4531,13 @@ export const triggerProjectPipeline = (opt } }); -export const listProjectAccess = (options: Options) => (options.client ?? client).get({ +export const listProjectAccess = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/access', ...options }); -export const grantProjectAccess = (options: Options) => (options.client ?? client).post({ +export const grantProjectAccess = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/access', ...options, @@ -4584,7 +4547,7 @@ export const grantProjectAccess = (options } }); -export const revokeProjectAccess = (options: Options) => (options.client ?? client).delete({ +export const revokeProjectAccess = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/access/{team_id}', ...options @@ -4593,19 +4556,19 @@ export const revokeProjectAccess = (option /** * Get active visitors count */ -export const getActiveVisitors = (options: Options) => (options.client ?? client).get({ +export const getActiveVisitors = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/active-visitors', ...options }); -export const listAgents = (options: Options) => (options.client ?? client).get({ +export const listAgents = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/agents', ...options }); -export const createAgent = (options: Options) => (options.client ?? client).post({ +export const createAgent = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/agents', ...options, @@ -4615,31 +4578,31 @@ export const createAgent = (options: Optio } }); -export const getCliStatus = (options: Options) => (options.client ?? client).get({ +export const getCliStatus = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/agents/cli-status', ...options }); -export const listAllRuns = (options: Options) => (options.client ?? client).get({ +export const listAllRuns = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/agents/runs', ...options }); -export const latestRunForSource = (options: Options) => (options.client ?? client).get({ +export const latestRunForSource = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/agents/runs/latest-for-source', ...options }); -export const getRunWithLogs = (options: Options) => (options.client ?? client).get({ +export const getRunWithLogs = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/agents/runs/{run_id}', ...options }); -export const cancelRun = (options: Options) => (options.client ?? client).post({ +export const cancelRun = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/agents/runs/{run_id}/cancel', ...options @@ -4649,7 +4612,7 @@ export const cancelRun = (options: Options * Retry a completed, failed, cancelled, or no_fix run with the same trigger context. * Creates a new run record and spawns the executor. */ -export const retryRun = (options: Options) => (options.client ?? client).post({ +export const retryRun = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/agents/runs/{run_id}/retry', ...options @@ -4660,13 +4623,13 @@ export const retryRun = (options: Options< * Polls the agent_run_logs table every 500ms for new entries and streams them. * Closes when the run reaches a terminal status. */ -export const streamRunEvents = (options: Options) => (options.client ?? client).sse.get({ +export const streamRunEvents = (options: Options): Promise> => (options.client ?? client).sse.get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/agents/runs/{run_id}/stream', ...options }); -export const getSandboxStatus = (options: Options) => (options.client ?? client).get({ +export const getSandboxStatus = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/agents/sandbox-status', ...options @@ -4677,25 +4640,25 @@ export const getSandboxStatus = (options: * where agents will actually execute (host or sandbox container). If no * `provider_id` is supplied the globally active provider is tested. */ -export const smokeTestAgent = (options: Options) => (options.client ?? client).post({ +export const smokeTestAgent = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/agents/smoke-test', ...options }); -export const deleteAgent = (options: Options) => (options.client ?? client).delete({ +export const deleteAgent = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/agents/{slug}', ...options }); -export const getAgent = (options: Options) => (options.client ?? client).get({ +export const getAgent = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/agents/{slug}', ...options }); -export const updateAgent = (options: Options) => (options.client ?? client).put({ +export const updateAgent = (options: Options): RequestResult => (options.client ?? client).put({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/agents/{slug}', ...options, @@ -4705,13 +4668,13 @@ export const updateAgent = (options: Optio } }); -export const listAgentRuns = (options: Options) => (options.client ?? client).get({ +export const listAgentRuns = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/agents/{slug}/runs', ...options }); -export const triggerAgent = (options: Options) => (options.client ?? client).post({ +export const triggerAgent = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/agents/{slug}/trigger', ...options, @@ -4724,7 +4687,7 @@ export const triggerAgent = (options: Opti /** * Get aggregated metrics by time bucket */ -export const getAggregatedBuckets = (options: Options) => (options.client ?? client).get({ +export const getAggregatedBuckets = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/aggregated-buckets', ...options @@ -4735,7 +4698,7 @@ export const getAggregatedBuckets = (optio * the per-project `ai_debug_chat_enabled` toggle to be on; returns 403 when the * feature is disabled so revoking it consistently hides existing chat content. */ -export const findConversation = (options: Options) => (options.client ?? client).get({ +export const findConversation = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/ai/conversations', ...options @@ -4744,7 +4707,7 @@ export const findConversation = (options: /** * Get-or-create the chat for a context (seeds it on first open). */ -export const createConversation = (options: Options) => (options.client ?? client).post({ +export const createConversation = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/ai/conversations', ...options, @@ -4758,7 +4721,7 @@ export const createConversation = (options * List all active conversations for a project, most-recently-active first. * Powers the conversation switcher in the AI assistant sidebar. */ -export const listConversations = (options: Options) => (options.client ?? client).get({ +export const listConversations = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/ai/conversations/list', ...options @@ -4767,7 +4730,7 @@ export const listConversations = (options: /** * Full conversation history (excluding the internal system seed). */ -export const getConversation = (options: Options) => (options.client ?? client).get({ +export const getConversation = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/ai/conversations/{public_id}', ...options @@ -4776,7 +4739,7 @@ export const getConversation = (options: O /** * Rename a conversation (set its human-facing title). */ -export const renameConversation = (options: Options) => (options.client ?? client).patch({ +export const renameConversation = (options: Options): RequestResult => (options.client ?? client).patch({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/ai/conversations/{public_id}', ...options, @@ -4789,7 +4752,7 @@ export const renameConversation = (options /** * Archive (soft-delete) a conversation. */ -export const archiveConversation = (options: Options) => (options.client ?? client).post({ +export const archiveConversation = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/ai/conversations/{public_id}/archive', ...options @@ -4798,7 +4761,7 @@ export const archiveConversation = (option /** * Send a user message; stream the assistant reply as Server-Sent Events. */ -export const sendMessage = (options: Options) => (options.client ?? client).sse.post({ +export const sendMessage = (options: Options): Promise> => (options.client ?? client).sse.post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/ai/conversations/{public_id}/messages', ...options, @@ -4811,7 +4774,7 @@ export const sendMessage = (options: Optio /** * List all pending actions for a conversation (most-recently-proposed first). */ -export const listPendingActions = (options: Options) => (options.client ?? client).get({ +export const listPendingActions = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/ai/conversations/{public_id}/pending-actions', ...options @@ -4820,7 +4783,7 @@ export const listPendingActions = (options /** * Get a single pending action by its public id (scoped to the project). */ -export const getPendingAction = (options: Options) => (options.client ?? client).get({ +export const getPendingAction = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/ai/pending-actions/{action_public_id}', ...options @@ -4830,7 +4793,7 @@ export const getPendingAction = (options: * Confirm a proposed AI action: validate permission, atomically claim, execute, * persist outcome. The execution uses the CONFIRMING user's auth — never the model's. */ -export const confirmPendingAction = (options: Options) => (options.client ?? client).post({ +export const confirmPendingAction = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/ai/pending-actions/{action_public_id}/confirm', ...options @@ -4839,7 +4802,7 @@ export const confirmPendingAction = (optio /** * Reject a proposed AI action (no execution). Status transitions to "rejected". */ -export const rejectPendingAction = (options: Options) => (options.client ?? client).post({ +export const rejectPendingAction = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/ai/pending-actions/{action_public_id}/reject', ...options @@ -4852,7 +4815,7 @@ export const rejectPendingAction = (option * entry point, an onboarding path, or nothing — instead of letting the user * click something that fails with a 409 they can't act on. */ -export const getChatReadiness = (options: Options) => (options.client ?? client).get({ +export const getChatReadiness = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/ai/readiness', ...options @@ -4861,7 +4824,7 @@ export const getChatReadiness = (options: /** * List alarms for a project with optional filters. */ -export const listProjectAlarms = (options: Options) => (options.client ?? client).get({ +export const listProjectAlarms = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/alarms', ...options @@ -4870,7 +4833,7 @@ export const listProjectAlarms = (options: /** * Get alarm counts by status/severity/type for a project (dashboard summary widget). */ -export const getProjectAlarmsSummary = (options: Options) => (options.client ?? client).get({ +export const getProjectAlarmsSummary = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/alarms/summary', ...options @@ -4879,7 +4842,7 @@ export const getProjectAlarmsSummary = (op /** * Acknowledge a firing alarm (marks it as seen but not resolved). */ -export const acknowledgeAlarm = (options: Options) => (options.client ?? client).post({ +export const acknowledgeAlarm = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/alarms/{alarm_id}/acknowledge', ...options @@ -4888,7 +4851,7 @@ export const acknowledgeAlarm = (options: /** * Resolve an alarm. */ -export const resolveAlarm = (options: Options) => (options.client ?? client).post({ +export const resolveAlarm = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/alarms/{alarm_id}/resolve', ...options @@ -4898,7 +4861,7 @@ export const resolveAlarm = (options: Opti * Start an autofixer analysis run for the given error group. * Creates the run record immediately and spawns analysis in the background. */ -export const startAnalysis = (options: Options) => (options.client ?? client).post({ +export const startAnalysis = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/autofixer/analyze', ...options, @@ -4911,7 +4874,7 @@ export const startAnalysis = (options: Opt /** * Get a single autofixer run with its logs. */ -export const getRun = (options: Options) => (options.client ?? client).get({ +export const getRun = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/autofixer/runs/{run_id}', ...options @@ -4920,7 +4883,7 @@ export const getRun = (options: Options(options: Options) => (options.client ?? client).post({ +export const addContext = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/autofixer/runs/{run_id}/add-context', ...options, @@ -4933,7 +4896,7 @@ export const addContext = (options: Option /** * Cancel an autofixer run and clean up the work directory. */ -export const cancel = (options: Options) => (options.client ?? client).post({ +export const cancel = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/autofixer/runs/{run_id}/cancel', ...options @@ -4943,7 +4906,7 @@ export const cancel = (options: Options(options: Options) => (options.client ?? client).post({ +export const createPr = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/autofixer/runs/{run_id}/create-pr', ...options @@ -4953,7 +4916,7 @@ export const createPr = (options: Options< * Transition from analysis to fix phase. * Requires phase == "analyzed". */ -export const startFix = (options: Options) => (options.client ?? client).post({ +export const startFix = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/autofixer/runs/{run_id}/fix', ...options @@ -4964,7 +4927,7 @@ export const startFix = (options: Options< * Uses the same Claude session (--continue) in the existing work directory. * Requires phase == "analyzed". */ -export const reAnalyze = (options: Options) => (options.client ?? client).post({ +export const reAnalyze = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/autofixer/runs/{run_id}/re-analyze', ...options @@ -4975,7 +4938,7 @@ export const reAnalyze = (options: Options * Polls every 500 ms. Keeps the connection open through "analyzed" and "fix_ready" * waiting states; closes only on terminal statuses. */ -export const streamEvents = (options: Options) => (options.client ?? client).sse.get({ +export const streamEvents = (options: Options): Promise> => (options.client ?? client).sse.get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/autofixer/runs/{run_id}/stream', ...options @@ -4984,7 +4947,7 @@ export const streamEvents = (options: Opti /** * Update automatic deployment setting for a project */ -export const updateAutomaticDeploy = (options: Options) => (options.client ?? client).post({ +export const updateAutomaticDeploy = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/automatic-deploy', ...options, @@ -4997,7 +4960,7 @@ export const updateAutomaticDeploy = (opti /** * List all custom domains for a project */ -export const listCustomDomainsForProject = (options: Options) => (options.client ?? client).get({ +export const listCustomDomainsForProject = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/custom-domains', ...options @@ -5006,7 +4969,7 @@ export const listCustomDomainsForProject = (options: Options) => (options.client ?? client).post({ +export const createCustomDomain = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/custom-domains', ...options, @@ -5019,7 +4982,7 @@ export const createCustomDomain = (options /** * Delete a custom domain */ -export const deleteCustomDomain = (options: Options) => (options.client ?? client).delete({ +export const deleteCustomDomain = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/custom-domains/{domain_id}', ...options @@ -5028,7 +4991,7 @@ export const deleteCustomDomain = (options /** * Get a custom domain by ID */ -export const getCustomDomain = (options: Options) => (options.client ?? client).get({ +export const getCustomDomain = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/custom-domains/{domain_id}', ...options @@ -5037,7 +5000,7 @@ export const getCustomDomain = (options: O /** * Update a custom domain */ -export const updateCustomDomain = (options: Options) => (options.client ?? client).put({ +export const updateCustomDomain = (options: Options): RequestResult => (options.client ?? client).put({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/custom-domains/{domain_id}', ...options, @@ -5050,7 +5013,7 @@ export const updateCustomDomain = (options /** * Link a custom domain to a certificate */ -export const linkCustomDomainToCertificate = (options: Options) => (options.client ?? client).post({ +export const linkCustomDomainToCertificate = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/custom-domains/{domain_id}/link-certificate/{certificate_id}', ...options @@ -5059,7 +5022,7 @@ export const linkCustomDomainToCertificate = (options: Options) => (options.client ?? client).patch({ +export const updateProjectDeploymentConfig = (options: Options): RequestResult => (options.client ?? client).patch({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/deployment-config', ...options, @@ -5072,7 +5035,7 @@ export const updateProjectDeploymentConfig = (options: Options) => (options.client ?? client).get({ +export const listDeploymentTokens = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/deployment-tokens', ...options @@ -5081,7 +5044,7 @@ export const listDeploymentTokens = (optio /** * Create a new deployment token for a project */ -export const createDeploymentToken = (options: Options) => (options.client ?? client).post({ +export const createDeploymentToken = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/deployment-tokens', ...options, @@ -5094,7 +5057,7 @@ export const createDeploymentToken = (opti /** * Delete a deployment token */ -export const deleteDeploymentToken = (options: Options) => (options.client ?? client).delete({ +export const deleteDeploymentToken = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/deployment-tokens/{token_id}', ...options @@ -5103,7 +5066,7 @@ export const deleteDeploymentToken = (opti /** * Get a specific deployment token */ -export const getDeploymentToken = (options: Options) => (options.client ?? client).get({ +export const getDeploymentToken = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/deployment-tokens/{token_id}', ...options @@ -5112,7 +5075,7 @@ export const getDeploymentToken = (options /** * Update a deployment token */ -export const updateDeploymentToken = (options: Options) => (options.client ?? client).patch({ +export const updateDeploymentToken = (options: Options): RequestResult => (options.client ?? client).patch({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/deployment-tokens/{token_id}', ...options, @@ -5125,7 +5088,7 @@ export const updateDeploymentToken = (opti /** * Rotate a deployment token, invalidating its old secret and issuing a new one */ -export const rotateDeploymentToken = (options: Options) => (options.client ?? client).post({ +export const rotateDeploymentToken = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/deployment-tokens/{token_id}/rotate', ...options @@ -5134,12 +5097,12 @@ export const rotateDeploymentToken = (opti /** * Get a specific deployment by ID for a project (identified by ID or slug) */ -export const getDeployment = (options: Options) => (options.client ?? client).get({ url: '/projects/{project_id}/deployments/{deployment_id}', ...options }); +export const getDeployment = (options: Options): RequestResult => (options.client ?? client).get({ url: '/projects/{project_id}/deployments/{deployment_id}', ...options }); /** * Cancel a deployment */ -export const cancelDeployment = (options: Options) => (options.client ?? client).post({ url: '/projects/{project_id}/deployments/{deployment_id}/cancel', ...options }); +export const cancelDeployment = (options: Options): RequestResult => (options.client ?? client).post({ url: '/projects/{project_id}/deployments/{deployment_id}/cancel', ...options }); /** * List the captured (historical) container-log dumps for a deployment. @@ -5151,12 +5114,12 @@ export const cancelDeployment = (options: * for a given (often older) deployment, so a user can read the logs of a * container that no longer exists. */ -export const listDeploymentContainerLogs = (options: Options) => (options.client ?? client).get({ url: '/projects/{project_id}/deployments/{deployment_id}/container-logs', ...options }); +export const listDeploymentContainerLogs = (options: Options): RequestResult => (options.client ?? client).get({ url: '/projects/{project_id}/deployments/{deployment_id}/container-logs', ...options }); /** * Get the captured text content of a single historical container-log dump. */ -export const getDeploymentContainerLogContent = (options: Options) => (options.client ?? client).get({ url: '/projects/{project_id}/deployments/{deployment_id}/container-logs/{log_id}', ...options }); +export const getDeploymentContainerLogContent = (options: Options): RequestResult => (options.client ?? client).get({ url: '/projects/{project_id}/deployments/{deployment_id}/container-logs/{log_id}', ...options }); /** * Get jobs for a specific deployment @@ -5164,12 +5127,12 @@ export const getDeploymentContainerLogContent = (options: Options) => (options.client ?? client).get({ url: '/projects/{project_id}/deployments/{deployment_id}/jobs', ...options }); +export const getDeploymentJobs = (options: Options): RequestResult => (options.client ?? client).get({ url: '/projects/{project_id}/deployments/{deployment_id}/jobs', ...options }); /** * Get logs for a specific deployment job */ -export const getDeploymentJobLogs = (options: Options) => (options.client ?? client).get({ url: '/projects/{project_id}/deployments/{deployment_id}/jobs/{job_id}/logs', ...options }); +export const getDeploymentJobLogs = (options: Options): RequestResult => (options.client ?? client).get({ url: '/projects/{project_id}/deployments/{deployment_id}/jobs/{job_id}/logs', ...options }); /** * Tail logs for a specific deployment job in real-time via WebSocket @@ -5186,12 +5149,12 @@ export const getDeploymentJobLogs = (optio * Authorization: Bearer tk_your_api_key_here * ``` */ -export const tailDeploymentJobLogs = (options: Options) => (options.client ?? client).get({ url: '/projects/{project_id}/deployments/{deployment_id}/jobs/{job_id}/logs/tail', ...options }); +export const tailDeploymentJobLogs = (options: Options): RequestResult => (options.client ?? client).get({ url: '/projects/{project_id}/deployments/{deployment_id}/jobs/{job_id}/logs/tail', ...options }); /** * Get all operations for a deployment */ -export const getDeploymentOperations = (options: Options) => (options.client ?? client).get({ +export const getDeploymentOperations = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/deployments/{deployment_id}/operations', ...options @@ -5200,7 +5163,7 @@ export const getDeploymentOperations = (op /** * Execute a deployment operation (deploy, mark_complete, take_screenshot) */ -export const executeDeploymentOperation = (options: Options) => (options.client ?? client).post({ +export const executeDeploymentOperation = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/deployments/{deployment_id}/operations', ...options, @@ -5213,7 +5176,7 @@ export const executeDeploymentOperation = /** * Get the status of a specific operation type */ -export const getDeploymentOperationStatus = (options: Options) => (options.client ?? client).get({ +export const getDeploymentOperationStatus = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/deployments/{deployment_id}/operations/{operation_type}', ...options @@ -5222,7 +5185,7 @@ export const getDeploymentOperationStatus = (options: Options) => (options.client ?? client).post({ url: '/projects/{project_id}/deployments/{deployment_id}/pause', ...options }); +export const pauseDeployment = (options: Options): RequestResult => (options.client ?? client).post({ url: '/projects/{project_id}/deployments/{deployment_id}/pause', ...options }); /** * Promote a deployment to another environment @@ -5230,7 +5193,7 @@ export const pauseDeployment = (options: O * Creates a new deployment in the target environment using the source deployment's * Docker image. Useful for promoting a validated preview/staging deployment to production. */ -export const promoteDeployment = (options: Options) => (options.client ?? client).post({ +export const promoteDeployment = (options: Options): RequestResult => (options.client ?? client).post({ url: '/projects/{project_id}/deployments/{deployment_id}/promote', ...options, headers: { @@ -5242,19 +5205,19 @@ export const promoteDeployment = (options: /** * Resume a deployment */ -export const resumeDeployment = (options: Options) => (options.client ?? client).post({ url: '/projects/{project_id}/deployments/{deployment_id}/resume', ...options }); +export const resumeDeployment = (options: Options): RequestResult => (options.client ?? client).post({ url: '/projects/{project_id}/deployments/{deployment_id}/resume', ...options }); -export const rollbackToDeployment = (options: Options) => (options.client ?? client).post({ url: '/projects/{project_id}/deployments/{deployment_id}/rollback', ...options }); +export const rollbackToDeployment = (options: Options): RequestResult => (options.client ?? client).post({ url: '/projects/{project_id}/deployments/{deployment_id}/rollback', ...options }); /** * Teardown a specific deployment */ -export const teardownDeployment = (options: Options) => (options.client ?? client).delete({ url: '/projects/{project_id}/deployments/{deployment_id}/teardown', ...options }); +export const teardownDeployment = (options: Options): RequestResult => (options.client ?? client).delete({ url: '/projects/{project_id}/deployments/{deployment_id}/teardown', ...options }); /** * List all DSNs for a project */ -export const listDsns = (options: Options) => (options.client ?? client).get({ +export const listDsns = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/dsns', ...options @@ -5263,7 +5226,7 @@ export const listDsns = (options: Options< /** * Create a new DSN for a project */ -export const createDsn = (options: Options) => (options.client ?? client).post({ +export const createDsn = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/dsns', ...options, @@ -5276,7 +5239,7 @@ export const createDsn = (options: Options /** * Get or create DSN for a project/environment/deployment combination */ -export const getOrCreateDsn = (options: Options) => (options.client ?? client).post({ +export const getOrCreateDsn = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/dsns/get-or-create', ...options, @@ -5289,7 +5252,7 @@ export const getOrCreateDsn = (options: Op /** * Regenerate DSN keys (rotate keys) */ -export const regenerateDsn = (options: Options) => (options.client ?? client).post({ +export const regenerateDsn = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/dsns/{dsn_id}/regenerate', ...options, @@ -5302,7 +5265,7 @@ export const regenerateDsn = (options: Opt /** * Revoke (deactivate) a DSN */ -export const revokeDsn = (options: Options) => (options.client ?? client).post({ +export const revokeDsn = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/dsns/{dsn_id}/revoke', ...options @@ -5311,12 +5274,12 @@ export const revokeDsn = (options: Options /** * Get environment variables for a project, optionally filtered by environment */ -export const getEnvironmentVariables = (options: Options) => (options.client ?? client).get({ url: '/projects/{project_id}/env-vars', ...options }); +export const getEnvironmentVariables = (options: Options): RequestResult => (options.client ?? client).get({ url: '/projects/{project_id}/env-vars', ...options }); /** * Create a new environment variable */ -export const createEnvironmentVariable = (options: Options) => (options.client ?? client).post({ +export const createEnvironmentVariable = (options: Options): RequestResult => (options.client ?? client).post({ url: '/projects/{project_id}/env-vars', ...options, headers: { @@ -5337,7 +5300,7 @@ export const createEnvironmentVariable = ( * Values are always returned as a masked preview. Use the per-key reveal * endpoint for plaintext (audit-logged). */ -export const getResolvedEnvironmentVariables = (options: Options) => (options.client ?? client).get({ url: '/projects/{project_id}/env-vars/resolved', ...options }); +export const getResolvedEnvironmentVariables = (options: Options): RequestResult => (options.client ?? client).get({ url: '/projects/{project_id}/env-vars/resolved', ...options }); /** * Reveal the plaintext value of a resolved environment variable. @@ -5353,22 +5316,22 @@ export const getResolvedEnvironmentVariables = (options: Options) => (options.client ?? client).get({ url: '/projects/{project_id}/env-vars/resolved/{key}/value', ...options }); +export const getResolvedEnvironmentVariableValue = (options: Options): RequestResult => (options.client ?? client).get({ url: '/projects/{project_id}/env-vars/resolved/{key}/value', ...options }); /** * Get environment variable value by key */ -export const getEnvironmentVariableValue = (options: Options) => (options.client ?? client).get({ url: '/projects/{project_id}/env-vars/{key}/value', ...options }); +export const getEnvironmentVariableValue = (options: Options): RequestResult => (options.client ?? client).get({ url: '/projects/{project_id}/env-vars/{key}/value', ...options }); /** * Delete an environment variable */ -export const deleteEnvironmentVariable = (options: Options) => (options.client ?? client).delete({ url: '/projects/{project_id}/env-vars/{var_id}', ...options }); +export const deleteEnvironmentVariable = (options: Options): RequestResult => (options.client ?? client).delete({ url: '/projects/{project_id}/env-vars/{var_id}', ...options }); /** * Update an environment variable */ -export const updateEnvironmentVariable = (options: Options) => (options.client ?? client).put({ +export const updateEnvironmentVariable = (options: Options): RequestResult => (options.client ?? client).put({ url: '/projects/{project_id}/env-vars/{var_id}', ...options, headers: { @@ -5380,12 +5343,12 @@ export const updateEnvironmentVariable = ( /** * Get all environments for a project */ -export const getEnvironments = (options: Options) => (options.client ?? client).get({ url: '/projects/{project_id}/environments', ...options }); +export const getEnvironments = (options: Options): RequestResult => (options.client ?? client).get({ url: '/projects/{project_id}/environments', ...options }); /** * Create a new environment for a project */ -export const createEnvironment = (options: Options) => (options.client ?? client).post({ +export const createEnvironment = (options: Options): RequestResult => (options.client ?? client).post({ url: '/projects/{project_id}/environments', ...options, headers: { @@ -5403,28 +5366,28 @@ export const createEnvironment = (options: * Warning: This action is permanent and cannot be undone. * Active deployments are automatically cancelled before deletion. */ -export const deleteEnvironment = (options: Options) => (options.client ?? client).delete({ url: '/projects/{project_id}/environments/{env_id}', ...options }); +export const deleteEnvironment = (options: Options): RequestResult => (options.client ?? client).delete({ url: '/projects/{project_id}/environments/{env_id}', ...options }); /** * Get a specific environment by ID or slug */ -export const getEnvironment = (options: Options) => (options.client ?? client).get({ url: '/projects/{project_id}/environments/{env_id}', ...options }); +export const getEnvironment = (options: Options): RequestResult => (options.client ?? client).get({ url: '/projects/{project_id}/environments/{env_id}', ...options }); -export const getEnvironmentCrons = (options: Options) => (options.client ?? client).get({ url: '/projects/{project_id}/environments/{env_id}/crons', ...options }); +export const getEnvironmentCrons = (options: Options): RequestResult => (options.client ?? client).get({ url: '/projects/{project_id}/environments/{env_id}/crons', ...options }); -export const getCronById = (options: Options) => (options.client ?? client).get({ url: '/projects/{project_id}/environments/{env_id}/crons/{cron_id}', ...options }); +export const getCronById = (options: Options): RequestResult => (options.client ?? client).get({ url: '/projects/{project_id}/environments/{env_id}/crons/{cron_id}', ...options }); -export const getCronExecutions = (options: Options) => (options.client ?? client).get({ url: '/projects/{project_id}/environments/{env_id}/crons/{cron_id}/executions', ...options }); +export const getCronExecutions = (options: Options): RequestResult => (options.client ?? client).get({ url: '/projects/{project_id}/environments/{env_id}/crons/{cron_id}/executions', ...options }); /** * Get all environment domains for a specific environment */ -export const getEnvironmentDomains = (options: Options) => (options.client ?? client).get({ url: '/projects/{project_id}/environments/{env_id}/domains', ...options }); +export const getEnvironmentDomains = (options: Options): RequestResult => (options.client ?? client).get({ url: '/projects/{project_id}/environments/{env_id}/domains', ...options }); /** * Add a new environment domain */ -export const addEnvironmentDomain = (options: Options) => (options.client ?? client).post({ +export const addEnvironmentDomain = (options: Options): RequestResult => (options.client ?? client).post({ url: '/projects/{project_id}/environments/{env_id}/domains', ...options, headers: { @@ -5436,12 +5399,12 @@ export const addEnvironmentDomain = (optio /** * Delete an environment domain */ -export const deleteEnvironmentDomain = (options: Options) => (options.client ?? client).delete({ url: '/projects/{project_id}/environments/{env_id}/domains/{domain_id}', ...options }); +export const deleteEnvironmentDomain = (options: Options): RequestResult => (options.client ?? client).delete({ url: '/projects/{project_id}/environments/{env_id}/domains/{domain_id}', ...options }); /** * Update environment settings */ -export const updateEnvironmentSettings = (options: Options) => (options.client ?? client).put({ +export const updateEnvironmentSettings = (options: Options): RequestResult => (options.client ?? client).put({ url: '/projects/{project_id}/environments/{env_id}/settings', ...options, headers: { @@ -5456,7 +5419,7 @@ export const updateEnvironmentSettings = ( * Manually put an on-demand environment to sleep. Stops containers and sets * `sleeping = true`. If no OnDemandWaker is available, falls back to DB flag only. */ -export const sleepEnvironment = (options: Options) => (options.client ?? client).post({ url: '/projects/{project_id}/environments/{env_id}/sleep', ...options }); +export const sleepEnvironment = (options: Options): RequestResult => (options.client ?? client).post({ url: '/projects/{project_id}/environments/{env_id}/sleep', ...options }); /** * Rename the auto-managed subdomain for an environment. @@ -5465,7 +5428,7 @@ export const sleepEnvironment = (options: * hostname stops resolving once the proxy reloads its route table. * Custom domains attached to the environment are unaffected. */ -export const updateEnvironmentSubdomain = (options: Options) => (options.client ?? client).patch({ +export const updateEnvironmentSubdomain = (options: Options): RequestResult => (options.client ?? client).patch({ url: '/projects/{project_id}/environments/{env_id}/subdomain', ...options, headers: { @@ -5477,7 +5440,7 @@ export const updateEnvironmentSubdomain = /** * Teardown an environment and all its active deployments */ -export const teardownEnvironment = (options: Options) => (options.client ?? client).delete({ url: '/projects/{project_id}/environments/{env_id}/teardown', ...options }); +export const teardownEnvironment = (options: Options): RequestResult => (options.client ?? client).delete({ url: '/projects/{project_id}/environments/{env_id}/teardown', ...options }); /** * Wake a sleeping on-demand environment @@ -5487,12 +5450,12 @@ export const teardownEnvironment = (option * `sleeping = false`. If no OnDemandWaker is available (proxy not running * in same process), falls back to setting the DB flag only. */ -export const wakeEnvironment = (options: Options) => (options.client ?? client).post({ url: '/projects/{project_id}/environments/{env_id}/wake', ...options }); +export const wakeEnvironment = (options: Options): RequestResult => (options.client ?? client).post({ url: '/projects/{project_id}/environments/{env_id}/wake', ...options }); /** * Get logs for a container in an environment via WebSocket */ -export const getContainerLogs = (options: Options) => (options.client ?? client).get({ +export const getContainerLogs = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/environments/{environment_id}/container-logs', ...options @@ -5501,7 +5464,7 @@ export const getContainerLogs = (options: /** * List all containers for an environment */ -export const listContainers = (options: Options) => (options.client ?? client).get({ +export const listContainers = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/environments/{environment_id}/containers', ...options @@ -5510,13 +5473,13 @@ export const listContainers = (options: Op /** * Get detailed information about a specific container */ -export const getContainerDetail = (options: Options) => (options.client ?? client).get({ +export const getContainerDetail = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/environments/{environment_id}/containers/{container_id}', ...options }); -export const getContainerEnvironmentVariable = (options: Options) => (options.client ?? client).get({ +export const getContainerEnvironmentVariable = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/environments/{environment_id}/containers/{container_id}/environment/{variable_name}', ...options @@ -5525,7 +5488,7 @@ export const getContainerEnvironmentVariable = (options: Options) => (options.client ?? client).get({ +export const getContainerLogsById = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/environments/{environment_id}/containers/{container_id}/logs', ...options @@ -5534,7 +5497,7 @@ export const getContainerLogsById = (optio /** * Get metrics/stats for a specific container */ -export const getContainerMetrics = (options: Options) => (options.client ?? client).get({ url: '/projects/{project_id}/environments/{environment_id}/containers/{container_id}/metrics', ...options }); +export const getContainerMetrics = (options: Options): RequestResult => (options.client ?? client).get({ url: '/projects/{project_id}/environments/{environment_id}/containers/{container_id}/metrics', ...options }); /** * Fetch a time-series range for a single container resource metric @@ -5545,7 +5508,7 @@ export const getContainerMetrics = (option * `container.memory_percent`, `container.network_rx_bytes_delta`, * `container.network_tx_bytes_delta`. */ -export const containerMetricsGetHistory = (options: Options) => (options.client ?? client).get({ +export const containerMetricsGetHistory = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/environments/{environment_id}/containers/{container_id}/metrics/history', ...options @@ -5554,22 +5517,22 @@ export const containerMetricsGetHistory = /** * Stream container metrics via Server-Sent Events (SSE) */ -export const streamContainerMetrics = (options: Options) => (options.client ?? client).get({ url: '/projects/{project_id}/environments/{environment_id}/containers/{container_id}/metrics/stream', ...options }); +export const streamContainerMetrics = (options: Options): RequestResult => (options.client ?? client).get({ url: '/projects/{project_id}/environments/{environment_id}/containers/{container_id}/metrics/stream', ...options }); /** * Restart a container */ -export const restartContainer = (options: Options) => (options.client ?? client).post({ url: '/projects/{project_id}/environments/{environment_id}/containers/{container_id}/restart', ...options }); +export const restartContainer = (options: Options): RequestResult => (options.client ?? client).post({ url: '/projects/{project_id}/environments/{environment_id}/containers/{container_id}/restart', ...options }); /** * Start a container */ -export const startContainer = (options: Options) => (options.client ?? client).post({ url: '/projects/{project_id}/environments/{environment_id}/containers/{container_id}/start', ...options }); +export const startContainer = (options: Options): RequestResult => (options.client ?? client).post({ url: '/projects/{project_id}/environments/{environment_id}/containers/{container_id}/start', ...options }); /** * Stop a specific container */ -export const stopContainer = (options: Options) => (options.client ?? client).post({ url: '/projects/{project_id}/environments/{environment_id}/containers/{container_id}/stop', ...options }); +export const stopContainer = (options: Options): RequestResult => (options.client ?? client).post({ url: '/projects/{project_id}/environments/{environment_id}/containers/{container_id}/stop', ...options }); /** * Deploy from an external Docker image @@ -5577,7 +5540,7 @@ export const stopContainer = (options: Opt * Triggers a deployment using a pre-built Docker image from an external registry. * The image will be pulled and deployed to the specified environment. */ -export const deployFromImage = (options: Options) => (options.client ?? client).post({ +export const deployFromImage = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/environments/{environment_id}/deploy/image', ...options, @@ -5597,7 +5560,7 @@ export const deployFromImage = (options: O * The uploaded file should be a tarball created by `docker save myimage:tag > image.tar` * or `docker save myimage:tag | gzip > image.tar.gz` (gzip compressed tarballs are also supported). */ -export const deployFromImageUpload = (options: Options) => (options.client ?? client).post({ +export const deployFromImageUpload = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/environments/{environment_id}/deploy/image-upload', ...options @@ -5606,7 +5569,7 @@ export const deployFromImageUpload = (opti /** * Upload source code and immediately start a preset-based deployment. */ -export const deployFromUploadedSource = (options: Options) => (options.client ?? client).post({ +export const deployFromUploadedSource = (options: Options): RequestResult => (options.client ?? client).post({ ...formDataBodySerializer, security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/environments/{environment_id}/deploy/source', @@ -5622,7 +5585,7 @@ export const deployFromUploadedSource = (o * * Triggers a deployment using a previously uploaded static file bundle. */ -export const deployFromStatic = (options: Options) => (options.client ?? client).post({ +export const deployFromStatic = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/environments/{environment_id}/deploy/static', ...options, @@ -5635,12 +5598,12 @@ export const deployFromStatic = (options: /** * List all alert rules for a project */ -export const listAlertRules = (options: Options) => (options.client ?? client).get({ url: '/projects/{project_id}/error-alert-rules', ...options }); +export const listAlertRules = (options: Options): RequestResult => (options.client ?? client).get({ url: '/projects/{project_id}/error-alert-rules', ...options }); /** * Create a new alert rule */ -export const createAlertRule = (options: Options) => (options.client ?? client).post({ +export const createAlertRule = (options: Options): RequestResult => (options.client ?? client).post({ url: '/projects/{project_id}/error-alert-rules', ...options, headers: { @@ -5652,17 +5615,17 @@ export const createAlertRule = (options: O /** * Delete an alert rule */ -export const deleteAlertRule = (options: Options) => (options.client ?? client).delete({ url: '/projects/{project_id}/error-alert-rules/{rule_id}', ...options }); +export const deleteAlertRule = (options: Options): RequestResult => (options.client ?? client).delete({ url: '/projects/{project_id}/error-alert-rules/{rule_id}', ...options }); /** * Get a specific alert rule */ -export const getAlertRule = (options: Options) => (options.client ?? client).get({ url: '/projects/{project_id}/error-alert-rules/{rule_id}', ...options }); +export const getAlertRule = (options: Options): RequestResult => (options.client ?? client).get({ url: '/projects/{project_id}/error-alert-rules/{rule_id}', ...options }); /** * Update an existing alert rule */ -export const updateAlertRule = (options: Options) => (options.client ?? client).put({ +export const updateAlertRule = (options: Options): RequestResult => (options.client ?? client).put({ url: '/projects/{project_id}/error-alert-rules/{rule_id}', ...options, headers: { @@ -5674,22 +5637,22 @@ export const updateAlertRule = (options: O /** * Get error dashboard statistics */ -export const getErrorDashboardStats = (options: Options) => (options.client ?? client).get({ url: '/projects/{project_id}/error-dashboard-stats', ...options }); +export const getErrorDashboardStats = (options: Options): RequestResult => (options.client ?? client).get({ url: '/projects/{project_id}/error-dashboard-stats', ...options }); /** * List error groups for a project */ -export const listErrorGroups = (options: Options) => (options.client ?? client).get({ url: '/projects/{project_id}/error-groups', ...options }); +export const listErrorGroups = (options: Options): RequestResult => (options.client ?? client).get({ url: '/projects/{project_id}/error-groups', ...options }); /** * Get a specific error group */ -export const getErrorGroup = (options: Options) => (options.client ?? client).get({ url: '/projects/{project_id}/error-groups/{group_id}', ...options }); +export const getErrorGroup = (options: Options): RequestResult => (options.client ?? client).get({ url: '/projects/{project_id}/error-groups/{group_id}', ...options }); /** * Update error group status */ -export const updateErrorGroup = (options: Options) => (options.client ?? client).put({ +export const updateErrorGroup = (options: Options): RequestResult => (options.client ?? client).put({ url: '/projects/{project_id}/error-groups/{group_id}', ...options, headers: { @@ -5701,27 +5664,27 @@ export const updateErrorGroup = (options: /** * List error events for a specific group */ -export const listErrorEvents = (options: Options) => (options.client ?? client).get({ url: '/projects/{project_id}/error-groups/{group_id}/events', ...options }); +export const listErrorEvents = (options: Options): RequestResult => (options.client ?? client).get({ url: '/projects/{project_id}/error-groups/{group_id}/events', ...options }); /** * Get a specific error event */ -export const getErrorEvent = (options: Options) => (options.client ?? client).get({ url: '/projects/{project_id}/error-groups/{group_id}/events/{event_id}', ...options }); +export const getErrorEvent = (options: Options): RequestResult => (options.client ?? client).get({ url: '/projects/{project_id}/error-groups/{group_id}/events/{event_id}', ...options }); /** * Get error statistics for a project */ -export const getErrorStats = (options: Options) => (options.client ?? client).get({ url: '/projects/{project_id}/error-stats', ...options }); +export const getErrorStats = (options: Options): RequestResult => (options.client ?? client).get({ url: '/projects/{project_id}/error-stats', ...options }); /** * Get error time series data for charts */ -export const getErrorTimeSeries = (options: Options) => (options.client ?? client).get({ url: '/projects/{project_id}/error-time-series', ...options }); +export const getErrorTimeSeries = (options: Options): RequestResult => (options.client ?? client).get({ url: '/projects/{project_id}/error-time-series', ...options }); /** * Get event counts with filtering */ -export const getEventsCount = (options: Options) => (options.client ?? client).get({ +export const getEventsCount = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/events', ...options @@ -5730,7 +5693,7 @@ export const getEventsCount = (options: Op /** * Get event type breakdown */ -export const getEventTypeBreakdown = (options: Options) => (options.client ?? client).get({ +export const getEventTypeBreakdown = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/events/breakdown', ...options @@ -5743,7 +5706,7 @@ export const getEventTypeBreakdown = (opti * identity is resolved automatically by middleware. No geolocation or user-agent * enrichment is performed — this is a lightweight server-side ingestion path. */ -export const recordConsoleEvent = (options: Options) => (options.client ?? client).post({ +export const recordConsoleEvent = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/events/ingest', ...options, @@ -5756,7 +5719,7 @@ export const recordConsoleEvent = (options /** * Get property breakdown by grouping events by a column */ -export const getPropertyBreakdown = (options: Options) => (options.client ?? client).get({ +export const getPropertyBreakdown = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/events/properties/breakdown', ...options @@ -5765,7 +5728,7 @@ export const getPropertyBreakdown = (optio /** * Get property timeline by grouping events by a column over time */ -export const getPropertyTimeline = (options: Options) => (options.client ?? client).get({ +export const getPropertyTimeline = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/events/properties/timeline', ...options @@ -5774,7 +5737,7 @@ export const getPropertyTimeline = (option /** * Get events timeline */ -export const getEventsTimeline = (options: Options) => (options.client ?? client).get({ +export const getEventsTimeline = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/events/timeline', ...options @@ -5783,7 +5746,7 @@ export const getEventsTimeline = (options: /** * Get all unique/distinct event types for a project (paginated) */ -export const getUniqueEvents = (options: Options) => (options.client ?? client).get({ +export const getUniqueEvents = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/events/unique', ...options @@ -5792,7 +5755,7 @@ export const getUniqueEvents = (options: O /** * List external images for a project */ -export const listRemoteExternalImages = (options: Options) => (options.client ?? client).get({ +export const listRemoteExternalImages = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/external-images', ...options @@ -5804,7 +5767,7 @@ export const listRemoteExternalImages = (o * Registers an external Docker image reference without triggering a deployment. * The image can be deployed later using the deploy/image endpoint. */ -export const registerExternalImage = (options: Options) => (options.client ?? client).post({ +export const registerExternalImage = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/external-images', ...options, @@ -5817,7 +5780,7 @@ export const registerExternalImage = (opti /** * Delete an external image */ -export const deleteExternalImage = (options: Options) => (options.client ?? client).delete({ +export const deleteExternalImage = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/external-images/{image_id}', ...options @@ -5826,19 +5789,19 @@ export const deleteExternalImage = (option /** * Get details of a specific external image */ -export const getRemoteExternalImage = (options: Options) => (options.client ?? client).get({ +export const getRemoteExternalImage = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/external-images/{image_id}', ...options }); -export const listFlags = (options: Options) => (options.client ?? client).get({ +export const listFlags = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/flags', ...options }); -export const createFlag = (options: Options) => (options.client ?? client).post({ +export const createFlag = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/flags', ...options, @@ -5848,19 +5811,19 @@ export const createFlag = (options: Option } }); -export const archiveFlag = (options: Options) => (options.client ?? client).delete({ +export const archiveFlag = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/flags/{key}', ...options }); -export const getFlag = (options: Options) => (options.client ?? client).get({ +export const getFlag = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/flags/{key}', ...options }); -export const updateFlag = (options: Options) => (options.client ?? client).patch({ +export const updateFlag = (options: Options): RequestResult => (options.client ?? client).patch({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/flags/{key}', ...options, @@ -5873,7 +5836,7 @@ export const updateFlag = (options: Option /** * Set a flag's value in one environment, and/or flip its kill switch. */ -export const setFlagEnvironment = (options: Options) => (options.client ?? client).put({ +export const setFlagEnvironment = (options: Options): RequestResult => (options.client ?? client).put({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/flags/{key}/environments/{environment_id}', ...options, @@ -5890,7 +5853,7 @@ export const setFlagEnvironment = (options * even be re-created under the same name, which makes an accidental archive * unrecoverable through the API. */ -export const restoreFlag = (options: Options) => (options.client ?? client).post({ +export const restoreFlag = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/flags/{key}/restore', ...options @@ -5899,7 +5862,7 @@ export const restoreFlag = (options: Optio /** * List all funnels for a project */ -export const listFunnels = (options: Options) => (options.client ?? client).get({ +export const listFunnels = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/funnels', ...options @@ -5908,7 +5871,7 @@ export const listFunnels = (options: Optio /** * Create a new funnel */ -export const createFunnel = (options: Options) => (options.client ?? client).post({ +export const createFunnel = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/funnels', ...options, @@ -5921,7 +5884,7 @@ export const createFunnel = (options: Opti /** * Preview funnel metrics without creating the funnel */ -export const previewFunnelMetrics = (options: Options) => (options.client ?? client).post({ +export const previewFunnelMetrics = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/funnels/preview', ...options, @@ -5934,7 +5897,7 @@ export const previewFunnelMetrics = (optio /** * Delete a funnel */ -export const deleteFunnel = (options: Options) => (options.client ?? client).delete({ +export const deleteFunnel = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/funnels/{funnel_id}', ...options @@ -5943,7 +5906,7 @@ export const deleteFunnel = (options: Opti /** * Update a funnel */ -export const updateFunnel = (options: Options) => (options.client ?? client).put({ +export const updateFunnel = (options: Options): RequestResult => (options.client ?? client).put({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/funnels/{funnel_id}', ...options, @@ -5956,7 +5919,7 @@ export const updateFunnel = (options: Opti /** * Get funnel metrics */ -export const getFunnelMetrics = (options: Options) => (options.client ?? client).get({ +export const getFunnelMetrics = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/funnels/{funnel_id}/metrics', ...options @@ -5965,7 +5928,7 @@ export const getFunnelMetrics = (options: /** * Update git settings for a project */ -export const updateGitSettings = (options: Options) => (options.client ?? client).post({ +export const updateGitSettings = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/git', ...options, @@ -5982,7 +5945,7 @@ export const updateGitSettings = (options: * Use this when a webhook has been manually deleted on the GitLab side * and automatic deployments have stopped working. */ -export const reinstallGitlabWebhook = (options: Options) => (options.client ?? client).post({ +export const reinstallGitlabWebhook = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/gitlab/reinstall-webhook', ...options @@ -5991,12 +5954,12 @@ export const reinstallGitlabWebhook = (opt /** * Check if project has any error groups */ -export const hasErrorGroups = (options: Options) => (options.client ?? client).get({ url: '/projects/{project_id}/has-error-groups', ...options }); +export const hasErrorGroups = (options: Options): RequestResult => (options.client ?? client).get({ url: '/projects/{project_id}/has-error-groups', ...options }); /** * Check if project has any analytics events */ -export const hasAnalyticsEvents = (options: Options) => (options.client ?? client).get({ +export const hasAnalyticsEvents = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/has-events', ...options @@ -6005,7 +5968,7 @@ export const hasAnalyticsEvents = (options /** * Get hourly visits */ -export const getHourlyVisits = (options: Options) => (options.client ?? client).get({ +export const getHourlyVisits = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/hourly-visits', ...options @@ -6014,7 +5977,7 @@ export const getHourlyVisits = (options: O /** * List all external images for a project */ -export const listExternalImages = (options: Options) => (options.client ?? client).get({ +export const listExternalImages = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/images', ...options @@ -6023,7 +5986,7 @@ export const listExternalImages = (options /** * Push an external Docker image */ -export const pushExternalImage = (options: Options) => (options.client ?? client).post({ +export const pushExternalImage = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/images/push', ...options, @@ -6036,7 +5999,7 @@ export const pushExternalImage = (options: /** * Get details of a specific external image */ -export const getExternalImage = (options: Options) => (options.client ?? client).get({ +export const getExternalImage = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/images/{image_id}', ...options @@ -6045,7 +6008,7 @@ export const getExternalImage = (options: /** * List incidents for a project */ -export const listIncidents = (options: Options) => (options.client ?? client).get({ +export const listIncidents = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/incidents', ...options @@ -6054,7 +6017,7 @@ export const listIncidents = (options: Opt /** * Create a new incident */ -export const createIncident = (options: Options) => (options.client ?? client).post({ +export const createIncident = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/incidents', ...options, @@ -6067,7 +6030,7 @@ export const createIncident = (options: Op /** * Get bucketed incident data for a project */ -export const getBucketedIncidents = (options: Options) => (options.client ?? client).get({ +export const getBucketedIncidents = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/incidents/bucketed', ...options @@ -6076,7 +6039,7 @@ export const getBucketedIncidents = (optio /** * Purge all logs for a project before a given timestamp */ -export const purgeProjectLogs = (options: Options) => (options.client ?? client).delete({ +export const purgeProjectLogs = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/logs', ...options, @@ -6086,13 +6049,13 @@ export const purgeProjectLogs = (options: } }); -export const listMcps = (options: Options) => (options.client ?? client).get({ +export const listMcps = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/mcp-servers', ...options }); -export const createMcp = (options: Options) => (options.client ?? client).post({ +export const createMcp = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/mcp-servers', ...options, @@ -6102,19 +6065,19 @@ export const createMcp = (options: Options } }); -export const deleteMcp = (options: Options) => (options.client ?? client).delete({ +export const deleteMcp = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/mcp-servers/{slug}', ...options }); -export const getMcp = (options: Options) => (options.client ?? client).get({ +export const getMcp = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/mcp-servers/{slug}', ...options }); -export const updateMcp = (options: Options) => (options.client ?? client).put({ +export const updateMcp = (options: Options): RequestResult => (options.client ?? client).put({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/mcp-servers/{slug}', ...options, @@ -6124,7 +6087,7 @@ export const updateMcp = (options: Options } }); -export const revealMcpConfig = (options: Options) => (options.client ?? client).get({ +export const revealMcpConfig = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/mcp-servers/{slug}/config/{field}', ...options @@ -6133,7 +6096,7 @@ export const revealMcpConfig = (options: O /** * List monitors for a project */ -export const listMonitors = (options: Options) => (options.client ?? client).get({ +export const listMonitors = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/monitors', ...options @@ -6142,7 +6105,7 @@ export const listMonitors = (options: Opti /** * Create a new monitor */ -export const createMonitor = (options: Options) => (options.client ?? client).post({ +export const createMonitor = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/monitors', ...options, @@ -6161,7 +6124,7 @@ export const createMonitor = (options: Opt * expose a `*_truncated` flag; clients fetch the full row from the * `/full` endpoint only when the user explicitly clicks "Show full". */ -export const observabilityListEvents = (options: Options) => (options.client ?? client).get({ +export const observabilityListEvents = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/observe/events', ...options @@ -6172,7 +6135,7 @@ export const observabilityListEvents = (op * "Show full" action calls this — the list response carries truncated * previews + a `*_truncated` flag to let the UI decide whether to fetch. */ -export const observabilityFullEvent = (options: Options) => (options.client ?? client).get({ +export const observabilityFullEvent = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/observe/events/{kind}/{event_id}/full', ...options @@ -6181,7 +6144,7 @@ export const observabilityFullEvent = (opt /** * Delete all uploaded source files for a release. */ -export const deleteReleaseSourceFiles = (options: Options) => (options.client ?? client).delete({ +export const deleteReleaseSourceFiles = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/releases/{release}/source-files', ...options @@ -6190,7 +6153,7 @@ export const deleteReleaseSourceFiles = (o /** * List uploaded source files for a release (metadata only). */ -export const listSourceFiles = (options: Options) => (options.client ?? client).get({ +export const listSourceFiles = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/releases/{release}/source-files', ...options @@ -6208,7 +6171,7 @@ export const listSourceFiles = (options: O * Requires the project's `error_source_context_enabled` toggle to be on. * Upserts on (project, release, file_path). */ -export const uploadSourceFile = (options: Options) => (options.client ?? client).post({ +export const uploadSourceFile = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/releases/{release}/source-files', ...options @@ -6217,7 +6180,7 @@ export const uploadSourceFile = (options: /** * Delete all source maps for a specific release */ -export const deleteReleaseSourceMaps = (options: Options) => (options.client ?? client).delete({ +export const deleteReleaseSourceMaps = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/releases/{release}/source-maps', ...options @@ -6226,7 +6189,7 @@ export const deleteReleaseSourceMaps = (op /** * List all source maps for a specific release */ -export const listSourceMaps = (options: Options) => (options.client ?? client).get({ +export const listSourceMaps = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/releases/{release}/source-maps', ...options @@ -6244,7 +6207,7 @@ export const listSourceMaps = (options: Op * * If a source map already exists for the same (project, release, file_path), it is replaced. */ -export const uploadSourceMap = (options: Options) => (options.client ?? client).post({ +export const uploadSourceMap = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/releases/{release}/source-maps', ...options @@ -6253,7 +6216,7 @@ export const uploadSourceMap = (options: O /** * Recent ingested events for the activity feed. */ -export const revenueRecentEvents = (options: Options) => (options.client ?? client).get({ +export const revenueRecentEvents = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/revenue/events', ...options @@ -6262,7 +6225,7 @@ export const revenueRecentEvents = (option /** * List revenue integrations for a project. */ -export const revenueListIntegrations = (options: Options) => (options.client ?? client).get({ +export const revenueListIntegrations = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/revenue/integrations', ...options @@ -6272,7 +6235,7 @@ export const revenueListIntegrations = (op * Create a new revenue integration. Response contains the generated * webhook path that the user must paste into their provider's dashboard. */ -export const revenueCreateIntegration = (options: Options) => (options.client ?? client).post({ +export const revenueCreateIntegration = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/revenue/integrations', ...options, @@ -6286,7 +6249,7 @@ export const revenueCreateIntegration = (o * Delete a revenue integration (permanent — use rotate_token to refresh * credentials without breaking history). */ -export const revenueDeleteIntegration = (options: Options) => (options.client ?? client).delete({ +export const revenueDeleteIntegration = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/revenue/integrations/{integration_id}', ...options @@ -6297,7 +6260,7 @@ export const revenueDeleteIntegration = (o * clears the config back to the accept-everything default. The config's * provider tag must match the integration's provider. */ -export const revenueUpdateConfig = (options: Options) => (options.client ?? client).post({ +export const revenueUpdateConfig = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/revenue/integrations/{integration_id}/config', ...options, @@ -6313,7 +6276,7 @@ export const revenueUpdateConfig = (option * timeseries. Ingestion is idempotent: re-uploading the same file is a * no-op. */ -export const revenueImportInvoicesCsv = (options: Options) => (options.client ?? client).post({ +export const revenueImportInvoicesCsv = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/revenue/integrations/{integration_id}/import/invoices', ...options @@ -6325,7 +6288,7 @@ export const revenueImportInvoicesCsv = (o * API keys. Webhooks remain the source of truth for live updates — * CSV rows never overwrite newer webhook state. */ -export const revenueImportSubscriptionsCsv = (options: Options) => (options.client ?? client).post({ +export const revenueImportSubscriptionsCsv = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/revenue/integrations/{integration_id}/import/subscriptions', ...options @@ -6335,7 +6298,7 @@ export const revenueImportSubscriptionsCsv = (options: Options) => (options.client ?? client).post({ +export const revenueRotateToken = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/revenue/integrations/{integration_id}/rotate-token', ...options @@ -6345,7 +6308,7 @@ export const revenueRotateToken = (options * Replace the stored signing secret without rotating the webhook URL. * Use this after rotating the secret in the provider's dashboard. */ -export const revenueUpdateSecret = (options: Options) => (options.client ?? client).post({ +export const revenueUpdateSecret = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/revenue/integrations/{integration_id}/update-secret', ...options, @@ -6358,7 +6321,7 @@ export const revenueUpdateSecret = (option /** * New + churned customers per bucket. */ -export const revenueMetricsCustomers = (options: Options) => (options.client ?? client).get({ +export const revenueMetricsCustomers = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/revenue/metrics/customers', ...options @@ -6367,7 +6330,7 @@ export const revenueMetricsCustomers = (op /** * Bucketed MRR timeseries for the revenue chart. */ -export const revenueMetricsMrr = (options: Options) => (options.client ?? client).get({ +export const revenueMetricsMrr = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/revenue/metrics/mrr', ...options @@ -6376,7 +6339,7 @@ export const revenueMetricsMrr = (options: /** * Current MRR / ARR / churn / ARPU for a project, in one currency. */ -export const revenueMetricsSummary = (options: Options) => (options.client ?? client).get({ +export const revenueMetricsSummary = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/revenue/metrics/summary', ...options @@ -6385,14 +6348,14 @@ export const revenueMetricsSummary = (opti /** * List project secrets (metadata only — values never returned). */ -export const listProjectSecrets = (options: Options) => (options.client ?? client).get({ url: '/projects/{project_id}/secrets', ...options }); +export const listProjectSecrets = (options: Options): RequestResult => (options.client ?? client).get({ url: '/projects/{project_id}/secrets', ...options }); /** * Create a new secret. The value is encrypted before storage and will be * mounted as a file at `/run/secrets/` on the next deployment. * The plaintext value is NOT returned — the response carries only metadata. */ -export const createProjectSecret = (options: Options) => (options.client ?? client).post({ +export const createProjectSecret = (options: Options): RequestResult => (options.client ?? client).post({ url: '/projects/{project_id}/secrets', ...options, headers: { @@ -6405,14 +6368,14 @@ export const createProjectSecret = (option * Delete a project secret. Running containers keep their mounted secret files * until they are redeployed. */ -export const deleteProjectSecret = (options: Options) => (options.client ?? client).delete({ url: '/projects/{project_id}/secrets/{secret_id}', ...options }); +export const deleteProjectSecret = (options: Options): RequestResult => (options.client ?? client).delete({ url: '/projects/{project_id}/secrets/{secret_id}', ...options }); /** * Update a project secret. Value rotation requires a redeploy to take effect — * running containers keep their currently-mounted values until the next * deployment. */ -export const updateProjectSecret = (options: Options) => (options.client ?? client).put({ +export const updateProjectSecret = (options: Options): RequestResult => (options.client ?? client).put({ url: '/projects/{project_id}/secrets/{secret_id}', ...options, headers: { @@ -6424,7 +6387,7 @@ export const updateProjectSecret = (option /** * Update project settings */ -export const updateProjectSettings = (options: Options) => (options.client ?? client).post({ +export const updateProjectSettings = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/settings', ...options, @@ -6434,13 +6397,13 @@ export const updateProjectSettings = (opti } }); -export const listSkills = (options: Options) => (options.client ?? client).get({ +export const listSkills = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/skills', ...options }); -export const createSkill = (options: Options) => (options.client ?? client).post({ +export const createSkill = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/skills', ...options, @@ -6453,7 +6416,7 @@ export const createSkill = (options: Optio /** * Upload a skill with an archive (tar.gz) — project-scoped. */ -export const uploadSkill = (options: Options) => (options.client ?? client).post({ +export const uploadSkill = (options: Options): RequestResult => (options.client ?? client).post({ ...formDataBodySerializer, security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/skills/upload', @@ -6464,19 +6427,19 @@ export const uploadSkill = (options: Optio } }); -export const deleteSkill = (options: Options) => (options.client ?? client).delete({ +export const deleteSkill = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/skills/{slug}', ...options }); -export const getSkill = (options: Options) => (options.client ?? client).get({ +export const getSkill = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/skills/{slug}', ...options }); -export const updateSkill = (options: Options) => (options.client ?? client).put({ +export const updateSkill = (options: Options): RequestResult => (options.client ?? client).put({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/skills/{slug}', ...options, @@ -6489,7 +6452,7 @@ export const updateSkill = (options: Optio /** * Download a skill's archive (tar.gz) — project-scoped. */ -export const downloadSkillArchive = (options: Options) => (options.client ?? client).get({ +export const downloadSkillArchive = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/skills/{slug}/archive', ...options @@ -6498,7 +6461,7 @@ export const downloadSkillArchive = (optio /** * List all releases that have source maps for a project */ -export const listReleases = (options: Options) => (options.client ?? client).get({ +export const listReleases = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/source-map-releases', ...options @@ -6507,7 +6470,7 @@ export const listReleases = (options: Opti /** * Delete a specific source map by ID */ -export const deleteSourceMap = (options: Options) => (options.client ?? client).delete({ +export const deleteSourceMap = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/source-maps/{source_map_id}', ...options @@ -6516,7 +6479,7 @@ export const deleteSourceMap = (options: O /** * List static bundles for a project */ -export const listStaticBundles = (options: Options) => (options.client ?? client).get({ +export const listStaticBundles = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/static-bundles', ...options @@ -6525,7 +6488,7 @@ export const listStaticBundles = (options: /** * Delete a static bundle */ -export const deleteStaticBundle = (options: Options) => (options.client ?? client).delete({ +export const deleteStaticBundle = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/static-bundles/{bundle_id}', ...options @@ -6534,7 +6497,7 @@ export const deleteStaticBundle = (options /** * Get details of a specific static bundle */ -export const getStaticBundle = (options: Options) => (options.client ?? client).get({ +export const getStaticBundle = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/static-bundles/{bundle_id}', ...options @@ -6543,7 +6506,7 @@ export const getStaticBundle = (options: O /** * Get status page overview */ -export const getStatusOverview = (options: Options) => (options.client ?? client).get({ +export const getStatusOverview = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/status', ...options @@ -6552,7 +6515,7 @@ export const getStatusOverview = (options: /** * Get unique counts over time frame */ -export const getUniqueCounts = (options: Options) => (options.client ?? client).get({ +export const getUniqueCounts = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/unique-counts', ...options @@ -6564,24 +6527,19 @@ export const getUniqueCounts = (options: O * Uploads a tar.gz or zip file containing static assets. The bundle can be * deployed later using the deploy/static endpoint. */ -export const uploadStaticBundle = (options: Options) => (options.client ?? client).post({ - ...formDataBodySerializer, +export const uploadStaticBundle = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/upload/static', - ...options, - headers: { - 'Content-Type': null, - ...options.headers - } + ...options }); -export const listProjectScans = (options: Options) => (options.client ?? client).get({ +export const listProjectScans = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/vulnerability-scans', ...options }); -export const triggerScan = (options: Options) => (options.client ?? client).post({ +export const triggerScan = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/vulnerability-scans', ...options, @@ -6591,13 +6549,13 @@ export const triggerScan = (options: Optio } }); -export const getLatestScansPerEnvironment = (options: Options) => (options.client ?? client).get({ +export const getLatestScansPerEnvironment = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/vulnerability-scans/environments', ...options }); -export const getLatestScan = (options: Options) => (options.client ?? client).get({ +export const getLatestScan = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/vulnerability-scans/latest', ...options @@ -6606,7 +6564,7 @@ export const getLatestScan = (options: Opt /** * List all webhooks for a project */ -export const listWebhooks = (options: Options) => (options.client ?? client).get({ +export const listWebhooks = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/webhooks', ...options @@ -6615,7 +6573,7 @@ export const listWebhooks = (options: Opti /** * Create a new webhook */ -export const createWebhook = (options: Options) => (options.client ?? client).post({ +export const createWebhook = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/webhooks', ...options, @@ -6628,7 +6586,7 @@ export const createWebhook = (options: Opt /** * Delete a webhook */ -export const deleteWebhook = (options: Options) => (options.client ?? client).delete({ +export const deleteWebhook = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/webhooks/{webhook_id}', ...options @@ -6637,7 +6595,7 @@ export const deleteWebhook = (options: Opt /** * Get a specific webhook */ -export const getWebhook = (options: Options) => (options.client ?? client).get({ +export const getWebhook = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/webhooks/{webhook_id}', ...options @@ -6646,7 +6604,7 @@ export const getWebhook = (options: Option /** * Update a webhook */ -export const updateWebhook = (options: Options) => (options.client ?? client).put({ +export const updateWebhook = (options: Options): RequestResult => (options.client ?? client).put({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/webhooks/{webhook_id}', ...options, @@ -6659,7 +6617,7 @@ export const updateWebhook = (options: Opt /** * List webhook deliveries */ -export const listDeliveries = (options: Options) => (options.client ?? client).get({ +export const listDeliveries = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/webhooks/{webhook_id}/deliveries', ...options @@ -6668,7 +6626,7 @@ export const listDeliveries = (options: Op /** * Get a specific webhook delivery by ID */ -export const getDelivery = (options: Options) => (options.client ?? client).get({ +export const getDelivery = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/webhooks/{webhook_id}/deliveries/{delivery_id}', ...options @@ -6677,13 +6635,13 @@ export const getDelivery = (options: Optio /** * Retry a failed delivery */ -export const retryDelivery = (options: Options) => (options.client ?? client).post({ +export const retryDelivery = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/webhooks/{webhook_id}/deliveries/{delivery_id}/retry', ...options }); -export const workflowDryRun = (options: Options) => (options.client ?? client).post({ +export const workflowDryRun = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/workflows/dry-run', ...options, @@ -6696,7 +6654,7 @@ export const workflowDryRun = (options: Op /** * Get proxy logs with optional filters and pagination */ -export const getProxyLogs = (options?: Options) => (options?.client ?? client).get({ +export const getProxyLogs = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/proxy-logs', ...options @@ -6708,7 +6666,7 @@ export const getProxyLogs = (options?: Opt * Returned in the same order as the internal taxonomy so the UI can use it as * a stable dropdown. */ -export const listKnownAiAgents = (options?: Options) => (options?.client ?? client).get({ +export const listKnownAiAgents = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/proxy-logs/ai-agents/known', ...options @@ -6717,7 +6675,7 @@ export const listKnownAiAgents = (options? /** * Get a proxy log by request ID (for tracing) */ -export const getProxyLogByRequestId = (options: Options) => (options.client ?? client).get({ +export const getProxyLogByRequestId = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/proxy-logs/request/{request_id}', ...options @@ -6730,7 +6688,7 @@ export const getProxyLogByRequestId = (opt * agent name (e.g. `ChatGPT-User`). Use `GET /proxy-logs/ai-agents/known` to * list all valid agent names. Unknown agent names return an empty items array. */ -export const getAiAgentPages = (options: Options) => (options.client ?? client).get({ +export const getAiAgentPages = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/proxy-logs/stats/ai-agent-pages', ...options @@ -6739,7 +6697,7 @@ export const getAiAgentPages = (options: O /** * Get the per-AI-agent breakdown for a project over a time window. */ -export const getAiAgentBreakdown = (options?: Options) => (options?.client ?? client).get({ +export const getAiAgentBreakdown = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/proxy-logs/stats/ai-agents', ...options @@ -6751,7 +6709,7 @@ export const getAiAgentBreakdown = (option * Powers the "AI agents over time" stacked chart. Same data source as the AI * agent breakdown (request logs), just bucketed. */ -export const getAiAgentTimeline = (options?: Options) => (options?.client ?? client).get({ +export const getAiAgentTimeline = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/proxy-logs/stats/ai-agents/timeline', ...options @@ -6760,7 +6718,7 @@ export const getAiAgentTimeline = (options /** * Get the top pages crawled by AI agents over a time window. */ -export const getAiPageBreakdown = (options?: Options) => (options?.client ?? client).get({ +export const getAiPageBreakdown = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/proxy-logs/stats/ai-pages', ...options @@ -6770,7 +6728,7 @@ export const getAiPageBreakdown = (options * HTTP status-class breakdown for AI-agent traffic — are bots being served * (2xx) or hitting broken/blocked pages (4xx/5xx)? */ -export const getAiStatusBreakdown = (options?: Options) => (options?.client ?? client).get({ +export const getAiStatusBreakdown = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/proxy-logs/stats/ai-status', ...options @@ -6779,7 +6737,7 @@ export const getAiStatusBreakdown = (optio /** * Get health summaries for multiple projects (last 1 hour) */ -export const getProjectsHealth = (options: Options) => (options.client ?? client).get({ +export const getProjectsHealth = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/proxy-logs/stats/projects-health', ...options @@ -6788,7 +6746,7 @@ export const getProjectsHealth = (options: /** * Get time-bucketed statistics with optional filters */ -export const getTimeBucketStats = (options: Options) => (options.client ?? client).get({ +export const getTimeBucketStats = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/proxy-logs/stats/time-buckets', ...options @@ -6797,7 +6755,7 @@ export const getTimeBucketStats = (options /** * Get today's request count with optional filters */ -export const getTodayStats = (options?: Options) => (options?.client ?? client).get({ +export const getTodayStats = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/proxy-logs/stats/today', ...options @@ -6806,7 +6764,7 @@ export const getTodayStats = (options?: Op /** * Get a single proxy log by ID */ -export const getProxyLogById = (options: Options) => (options.client ?? client).get({ +export const getProxyLogById = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/proxy-logs/{id}', ...options @@ -6818,7 +6776,7 @@ export const getProxyLogById = (options: O * Lists repositories that have been synced to the database with filtering options. * This provides fast access to repository metadata with filtering by connection, search, and other criteria. */ -export const listSyncedRepositories = (options?: Options) => (options?.client ?? client).get({ +export const listSyncedRepositories = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/repositories', ...options @@ -6827,7 +6785,7 @@ export const listSyncedRepositories = (opt /** * Get repository by owner and name from any connection */ -export const getRepositoryByName = (options: Options) => (options.client ?? client).get({ +export const getRepositoryByName = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/repositories/{owner}/{name}', ...options @@ -6836,7 +6794,7 @@ export const getRepositoryByName = (option /** * Get all repositories with same owner/name from all git providers */ -export const getAllRepositoriesByName = (options: Options) => (options.client ?? client).get({ +export const getAllRepositoriesByName = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/repositories/{owner}/{name}/all', ...options @@ -6845,7 +6803,7 @@ export const getAllRepositoriesByName = (o /** * Get repository preset by owner and name */ -export const getRepositoryPresetByName = (options: Options) => (options.client ?? client).get({ +export const getRepositoryPresetByName = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/repositories/{owner}/{name}/preset', ...options @@ -6854,7 +6812,7 @@ export const getRepositoryPresetByName = ( /** * Get repository branches */ -export const getRepositoryBranches = (options: Options) => (options.client ?? client).get({ +export const getRepositoryBranches = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/repositories/{owner}/{repo}/branches', ...options @@ -6863,13 +6821,13 @@ export const getRepositoryBranches = (opti /** * Get repository tags */ -export const getRepositoryTags = (options: Options) => (options.client ?? client).get({ +export const getRepositoryTags = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/repositories/{owner}/{repo}/tags', ...options }); -export const getRepositoryPresetLive = (options: Options) => (options.client ?? client).get({ +export const getRepositoryPresetLive = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/repositories/{repository_id}/preset/live', ...options @@ -6878,7 +6836,7 @@ export const getRepositoryPresetLive = (op /** * Get repository by ID */ -export const getRepositoryById = (options: Options) => (options.client ?? client).get({ +export const getRepositoryById = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/repository/{repository_id}', ...options @@ -6887,7 +6845,7 @@ export const getRepositoryById = (options: /** * Get repository branches by repository ID */ -export const getBranchesByRepositoryId = (options: Options) => (options.client ?? client).get({ +export const getBranchesByRepositoryId = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/repository/{repository_id}/branches', ...options @@ -6896,7 +6854,7 @@ export const getBranchesByRepositoryId = ( /** * List recent commits for a repository branch */ -export const listCommitsByRepositoryId = (options: Options) => (options.client ?? client).get({ +export const listCommitsByRepositoryId = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/repository/{repository_id}/commits', ...options @@ -6905,7 +6863,7 @@ export const listCommitsByRepositoryId = ( /** * Check if a commit exists in a repository */ -export const checkCommitExists = (options: Options) => (options.client ?? client).get({ +export const checkCommitExists = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/repository/{repository_id}/commits/{commit_sha}', ...options @@ -6914,13 +6872,13 @@ export const checkCommitExists = (options: /** * Get repository tags by repository ID */ -export const getTagsByRepositoryId = (options: Options) => (options.client ?? client).get({ +export const getTagsByRepositoryId = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/repository/{repository_id}/tags', ...options }); -export const getRestoreRun = (options: Options) => (options.client ?? client).get({ +export const getRestoreRun = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/restore-runs/{id}', ...options @@ -6931,7 +6889,7 @@ export const getRestoreRun = (options: Opt * transactions page. Supports filtering by project, date range, and * event type. */ -export const revenueGlobalEvents = (options?: Options) => (options?.client ?? client).get({ +export const revenueGlobalEvents = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/revenue/events', ...options @@ -6941,7 +6899,7 @@ export const revenueGlobalEvents = (option * Org-wide MRR total, summed across every project in the install. * Powers the single-number MRR card on the main dashboard. */ -export const revenueMetricsGlobalMrr = (options?: Options) => (options?.client ?? client).get({ +export const revenueMetricsGlobalMrr = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/revenue/metrics/global-mrr', ...options @@ -6952,7 +6910,7 @@ export const revenueMetricsGlobalMrr = (op * active subscriptions/customers, and transaction count. Powers the * header on the Revenue transactions page. */ -export const revenueMetricsGlobalSummary = (options?: Options) => (options?.client ?? client).get({ +export const revenueMetricsGlobalSummary = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/revenue/metrics/global-summary', ...options @@ -6962,7 +6920,7 @@ export const revenueMetricsGlobalSummary = (options?: Options) => (options?.client ?? client).get({ +export const revenueListProviders = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/revenue/providers', ...options @@ -6971,7 +6929,7 @@ export const revenueListProviders = (optio /** * Get session replays for a project */ -export const getProjectSessionReplays = (options: Options) => (options.client ?? client).get({ +export const getProjectSessionReplays = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/session-replays', ...options @@ -6980,7 +6938,7 @@ export const getProjectSessionReplays = (o /** * Get events for a specific session */ -export const getSessionEvents = (options: Options) => (options.client ?? client).get({ +export const getSessionEvents = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/sessions/{session_id}/events', ...options @@ -6989,7 +6947,7 @@ export const getSessionEvents = (options: /** * Get application settings */ -export const getSettings = (options?: Options) => (options?.client ?? client).get({ +export const getSettings = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/settings', ...options @@ -6998,7 +6956,7 @@ export const getSettings = (options?: Opti /** * Update application settings */ -export const updateSettings = (options: Options) => (options.client ?? client).put({ +export const updateSettings = (options: Options): RequestResult => (options.client ?? client).put({ security: [{ scheme: 'bearer', type: 'http' }], url: '/settings', ...options, @@ -7011,7 +6969,7 @@ export const updateSettings = (options: Op /** * Save an encrypted AI provider token for use in sandbox containers. */ -export const saveAgentToken = (options: Options) => (options.client ?? client).post({ +export const saveAgentToken = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/settings/agent-token', ...options, @@ -7026,7 +6984,7 @@ export const saveAgentToken = (options: Op * configured?" so the settings UI can render configured/not-configured * badges without leaking the encrypted credential. */ -export const listAiProviders = (options?: Options) => (options?.client ?? client).get({ +export const listAiProviders = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/settings/ai-providers', ...options @@ -7038,7 +6996,7 @@ export const listAiProviders = (options?: * (base URL overrides, request headers, etc.) can land here too without * changing the shape of `save_credential`. */ -export const updateAiProvider = (options: Options) => (options.client ?? client).patch({ +export const updateAiProvider = (options: Options): RequestResult => (options.client ?? client).patch({ security: [{ scheme: 'bearer', type: 'http' }], url: '/settings/ai-providers/{provider_id}', ...options, @@ -7054,7 +7012,7 @@ export const updateAiProvider = (options: * same rule on the button, but we re-check server-side so a stale tab * can't bypass it. */ -export const activateAiProvider = (options: Options) => (options.client ?? client).post({ +export const activateAiProvider = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/settings/ai-providers/{provider_id}/activate', ...options @@ -7069,7 +7027,7 @@ export const activateAiProvider = (options * - `ApiKey` / `OauthToken`: the key/token string. * - `ConfigFile`: the full file body (e.g. OpenCode's `auth.json`). */ -export const saveAiProviderCredential = (options: Options) => (options.client ?? client).post({ +export const saveAiProviderCredential = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/settings/ai-providers/{provider_id}/credential', ...options, @@ -7086,7 +7044,7 @@ export const saveAiProviderCredential = (o * meet or exceed the configured alert threshold. Read-only — does not send * notifications. Used by the dashboard to surface a low-disk-space warning. */ -export const getDiskStatus = (options?: Options) => (options?.client ?? client).get({ +export const getDiskStatus = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/settings/disk-status', ...options @@ -7095,7 +7053,7 @@ export const getDiskStatus = (options?: Op /** * List currently-valid node enrollment tokens (hashes elided). */ -export const listEnrollmentTokens = (options?: Options) => (options?.client ?? client).get({ +export const listEnrollmentTokens = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/settings/enrollment-tokens', ...options @@ -7104,7 +7062,7 @@ export const listEnrollmentTokens = (optio /** * Mint a short-lived, single-use node enrollment token. */ -export const mintEnrollmentToken = (options: Options) => (options.client ?? client).post({ +export const mintEnrollmentToken = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/settings/enrollment-tokens', ...options, @@ -7117,7 +7075,7 @@ export const mintEnrollmentToken = (option /** * Revoke a node enrollment token by id. */ -export const revokeEnrollmentToken = (options: Options) => (options.client ?? client).delete({ +export const revokeEnrollmentToken = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/settings/enrollment-tokens/{id}', ...options @@ -7129,7 +7087,7 @@ export const revokeEnrollmentToken = (opti * Removes the stored join token hash, allowing any node to register * (if no other authentication is in place). */ -export const revokeJoinToken = (options?: Options) => (options?.client ?? client).delete({ +export const revokeJoinToken = (options?: Options): RequestResult => (options?.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/settings/join-token', ...options @@ -7141,7 +7099,7 @@ export const revokeJoinToken = (options?: * Creates a random 32-byte hex token, stores the SHA-256 hash in settings, * and returns the plaintext exactly once. If a token already exists, it is replaced. */ -export const generateJoinToken = (options?: Options) => (options?.client ?? client).post({ +export const generateJoinToken = (options?: Options): RequestResult => (options?.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/settings/join-token/generate', ...options @@ -7150,19 +7108,19 @@ export const generateJoinToken = (options? /** * Check whether a join token is currently configured */ -export const getJoinTokenStatus = (options?: Options) => (options?.client ?? client).get({ +export const getJoinTokenStatus = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/settings/join-token/status', ...options }); -export const listGlobalMcps = (options?: Options) => (options?.client ?? client).get({ +export const listGlobalMcps = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/settings/mcp-servers', ...options }); -export const createGlobalMcp = (options: Options) => (options.client ?? client).post({ +export const createGlobalMcp = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/settings/mcp-servers', ...options, @@ -7172,19 +7130,19 @@ export const createGlobalMcp = (options: O } }); -export const deleteGlobalMcp = (options: Options) => (options.client ?? client).delete({ +export const deleteGlobalMcp = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/settings/mcp-servers/{slug}', ...options }); -export const getGlobalMcp = (options: Options) => (options.client ?? client).get({ +export const getGlobalMcp = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/settings/mcp-servers/{slug}', ...options }); -export const updateGlobalMcp = (options: Options) => (options.client ?? client).put({ +export const updateGlobalMcp = (options: Options): RequestResult => (options.client ?? client).put({ security: [{ scheme: 'bearer', type: 'http' }], url: '/settings/mcp-servers/{slug}', ...options, @@ -7194,7 +7152,7 @@ export const updateGlobalMcp = (options: O } }); -export const revealGlobalMcpConfig = (options: Options) => (options.client ?? client).get({ +export const revealGlobalMcpConfig = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/settings/mcp-servers/{slug}/config/{field}', ...options @@ -7206,31 +7164,31 @@ export const revealGlobalMcpConfig = (opti * Reloads all routes from the database into the in-memory proxy cache. * Useful as a workaround when routes are out of sync. */ -export const refreshRouteTable = (options?: Options) => (options?.client ?? client).post({ +export const refreshRouteTable = (options?: Options): RequestResult => (options?.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/settings/routes/refresh', ...options }); -export const rebuildSandboxImage = (options?: Options) => (options?.client ?? client).sse.post({ +export const rebuildSandboxImage = (options?: Options): Promise> => (options?.client ?? client).sse.post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/settings/sandbox-rebuild', ...options }); -export const getGlobalSandboxStatus = (options?: Options) => (options?.client ?? client).get({ +export const getGlobalSandboxStatus = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/settings/sandbox-status', ...options }); -export const listSecrets = (options?: Options) => (options?.client ?? client).get({ +export const listSecrets = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/settings/secrets', ...options }); -export const upsertSecret = (options: Options) => (options.client ?? client).post({ +export const upsertSecret = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/settings/secrets', ...options, @@ -7240,19 +7198,19 @@ export const upsertSecret = (options: Opti } }); -export const deleteSecret = (options: Options) => (options.client ?? client).delete({ +export const deleteSecret = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/settings/secrets/{name}', ...options }); -export const listGlobalSkills = (options?: Options) => (options?.client ?? client).get({ +export const listGlobalSkills = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/settings/skills', ...options }); -export const createGlobalSkill = (options: Options) => (options.client ?? client).post({ +export const createGlobalSkill = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/settings/skills', ...options, @@ -7265,7 +7223,7 @@ export const createGlobalSkill = (options: /** * Upload a skill with an archive (tar.gz) — global. */ -export const uploadGlobalSkill = (options: Options) => (options.client ?? client).post({ +export const uploadGlobalSkill = (options: Options): RequestResult => (options.client ?? client).post({ ...formDataBodySerializer, security: [{ scheme: 'bearer', type: 'http' }], url: '/settings/skills/upload', @@ -7276,19 +7234,19 @@ export const uploadGlobalSkill = (options: } }); -export const deleteGlobalSkill = (options: Options) => (options.client ?? client).delete({ +export const deleteGlobalSkill = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/settings/skills/{slug}', ...options }); -export const getGlobalSkill = (options: Options) => (options.client ?? client).get({ +export const getGlobalSkill = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/settings/skills/{slug}', ...options }); -export const updateGlobalSkill = (options: Options) => (options.client ?? client).put({ +export const updateGlobalSkill = (options: Options): RequestResult => (options.client ?? client).put({ security: [{ scheme: 'bearer', type: 'http' }], url: '/settings/skills/{slug}', ...options, @@ -7301,7 +7259,7 @@ export const updateGlobalSkill = (options: /** * Download a skill's archive (tar.gz) — global. */ -export const downloadGlobalSkillArchive = (options: Options) => (options.client ?? client).get({ +export const downloadGlobalSkillArchive = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/settings/skills/{slug}/archive', ...options @@ -7310,19 +7268,19 @@ export const downloadGlobalSkillArchive = /** * Report whether a newer temps release is available for this install. */ -export const getUpdateStatus = (options?: Options) => (options?.client ?? client).get({ +export const getUpdateStatus = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/settings/update-status', ...options }); -export const listTeams = (options?: Options) => (options?.client ?? client).get({ +export const listTeams = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/teams', ...options }); -export const createTeam = (options: Options) => (options.client ?? client).post({ +export const createTeam = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/teams', ...options, @@ -7332,19 +7290,19 @@ export const createTeam = (options: Option } }); -export const deleteTeam = (options: Options) => (options.client ?? client).delete({ +export const deleteTeam = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/teams/{team_id}', ...options }); -export const getTeam = (options: Options) => (options.client ?? client).get({ +export const getTeam = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/teams/{team_id}', ...options }); -export const updateTeam = (options: Options) => (options.client ?? client).patch({ +export const updateTeam = (options: Options): RequestResult => (options.client ?? client).patch({ security: [{ scheme: 'bearer', type: 'http' }], url: '/teams/{team_id}', ...options, @@ -7354,13 +7312,13 @@ export const updateTeam = (options: Option } }); -export const listTeamMembers = (options: Options) => (options.client ?? client).get({ +export const listTeamMembers = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/teams/{team_id}/members', ...options }); -export const addTeamMember = (options: Options) => (options.client ?? client).post({ +export const addTeamMember = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/teams/{team_id}/members', ...options, @@ -7370,13 +7328,13 @@ export const addTeamMember = (options: Opt } }); -export const removeTeamMember = (options: Options) => (options.client ?? client).delete({ +export const removeTeamMember = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/teams/{team_id}/members/{user_id}', ...options }); -export const updateTeamMemberRole = (options: Options) => (options.client ?? client).patch({ +export const updateTeamMemberRole = (options: Options): RequestResult => (options.client ?? client).patch({ security: [{ scheme: 'bearer', type: 'http' }], url: '/teams/{team_id}/members/{user_id}', ...options, @@ -7386,7 +7344,7 @@ export const updateTeamMemberRole = (optio } }); -export const listTeamProjects = (options: Options) => (options.client ?? client).get({ +export const listTeamProjects = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/teams/{team_id}/projects', ...options @@ -7397,7 +7355,7 @@ export const listTeamProjects = (options: * * Returns a list of all public templates, optionally filtered by tag or featured status. */ -export const listProjectTemplates = (options?: Options) => (options?.client ?? client).get({ +export const listProjectTemplates = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/templates', ...options @@ -7408,7 +7366,7 @@ export const listProjectTemplates = (optio * * Returns a list of all unique tags used by public templates. */ -export const listProjectTemplateTags = (options?: Options) => (options?.client ?? client).get({ +export const listProjectTemplateTags = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/templates/tags', ...options @@ -7419,15 +7377,15 @@ export const listProjectTemplateTags = (op * * Returns detailed information about a single template. */ -export const getProjectTemplate = (options: Options) => (options.client ?? client).get({ +export const getProjectTemplate = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/templates/{slug}', ...options }); -export const getCurrentUser = (options?: Options) => (options?.client ?? client).get({ url: '/user/me', ...options }); +export const getCurrentUser = (options?: Options): RequestResult => (options?.client ?? client).get({ url: '/user/me', ...options }); -export const listUsers = (options: Options) => (options.client ?? client).get({ +export const listUsers = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/users', ...options @@ -7436,7 +7394,7 @@ export const listUsers = (options: Options /** * Create a new user with roles */ -export const createUser = (options: Options) => (options.client ?? client).post({ +export const createUser = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/users', ...options, @@ -7449,7 +7407,7 @@ export const createUser = (options: Option /** * Update current user's information */ -export const updateSelf = (options: Options) => (options.client ?? client).patch({ +export const updateSelf = (options: Options): RequestResult => (options.client ?? client).patch({ security: [{ scheme: 'bearer', type: 'http' }], url: '/users/me', ...options, @@ -7459,7 +7417,7 @@ export const updateSelf = (options: Option } }); -export const disableMfa = (options: Options) => (options.client ?? client).delete({ +export const disableMfa = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/users/me/mfa', ...options, @@ -7469,13 +7427,13 @@ export const disableMfa = (options: Option } }); -export const setupMfa = (options?: Options) => (options?.client ?? client).post({ +export const setupMfa = (options?: Options): RequestResult => (options?.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/users/me/mfa/setup', ...options }); -export const verifyAndEnableMfa = (options: Options) => (options.client ?? client).post({ +export const verifyAndEnableMfa = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/users/me/mfa/verify', ...options, @@ -7485,7 +7443,7 @@ export const verifyAndEnableMfa = (options } }); -export const changePasswordSelf = (options: Options) => (options.client ?? client).post({ +export const changePasswordSelf = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/users/me/password', ...options, @@ -7498,7 +7456,7 @@ export const changePasswordSelf = (options /** * Delete a user */ -export const deleteUser = (options: Options) => (options.client ?? client).delete({ +export const deleteUser = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/users/{user_id}', ...options @@ -7507,7 +7465,7 @@ export const deleteUser = (options: Option /** * Update user information (admin only) */ -export const updateUser = (options: Options) => (options.client ?? client).patch({ +export const updateUser = (options: Options): RequestResult => (options.client ?? client).patch({ security: [{ scheme: 'bearer', type: 'http' }], url: '/users/{user_id}', ...options, @@ -7517,13 +7475,13 @@ export const updateUser = (options: Option } }); -export const restoreUser = (options: Options) => (options.client ?? client).post({ +export const restoreUser = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/users/{user_id}/restore', ...options }); -export const assignRole = (options: Options) => (options.client ?? client).post({ +export const assignRole = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/users/{user_id}/roles', ...options, @@ -7533,19 +7491,19 @@ export const assignRole = (options: Option } }); -export const removeRole = (options: Options) => (options.client ?? client).delete({ +export const removeRole = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/users/{user_id}/roles/{role_type}', ...options }); -export const listSandboxes = (options?: Options) => (options?.client ?? client).get({ +export const listSandboxes = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/v1/sandboxes', ...options }); -export const createSandbox = (options: Options) => (options.client ?? client).post({ +export const createSandbox = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/v1/sandboxes', ...options, @@ -7560,7 +7518,7 @@ export const createSandbox = (options: Opt * sandboxes reference each entry) and per-VM disks. Empty on Docker-only * hosts. Admin/read scope — this exposes host storage layout. */ -export const rootfsReport = (options?: Options) => (options?.client ?? client).get({ +export const rootfsReport = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/v1/sandboxes/rootfs', ...options @@ -7570,13 +7528,13 @@ export const rootfsReport = (options?: Opt * Reclaim rootfs cache entries not backing any live sandbox. Idempotent; * safe to call any time (live VMs hold their own per-VM disks). */ -export const rootfsGc = (options?: Options) => (options?.client ?? client).post({ +export const rootfsGc = (options?: Options): RequestResult => (options?.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/v1/sandboxes/rootfs/gc', ...options }); -export const getSandbox = (options: Options) => (options.client ?? client).get({ +export const getSandbox = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/v1/sandboxes/{id}', ...options @@ -7591,7 +7549,7 @@ export const getSandbox = (options: Option * `wait=true` streams `application/x-ndjson`: the first line is the * running envelope, the second is the finished envelope with `exitCode`. */ -export const cmd = (options: Options) => (options.client ?? client).post({ +export const cmd = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/v1/sandboxes/{id}/cmd', ...options, @@ -7601,7 +7559,7 @@ export const cmd = (options: Options(options: Options) => (options.client ?? client).get({ +export const getCmd = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/v1/sandboxes/{id}/cmd/{cmd_id}', ...options @@ -7613,19 +7571,19 @@ export const getCmd = (options: Options(options: Options) => (options.client ?? client).get({ +export const cmdLogs = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/v1/sandboxes/{id}/cmd/{cmd_id}/logs', ...options }); -export const destroySandbox = (options: Options) => (options.client ?? client).post({ +export const destroySandbox = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/v1/sandboxes/{id}/destroy', ...options }); -export const domain = (options: Options) => (options.client ?? client).get({ +export const domain = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/v1/sandboxes/{id}/domain', ...options @@ -7635,13 +7593,13 @@ export const domain = (options: Options(options: Options) => (options.client ?? client).get({ +export const listEvents = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/v1/sandboxes/{id}/events', ...options }); -export const exec = (options: Options) => (options.client ?? client).post({ +export const exec = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/v1/sandboxes/{id}/exec', ...options, @@ -7651,7 +7609,7 @@ export const exec = (options: Options(options: Options) => (options.client ?? client).post({ +export const execDetached = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/v1/sandboxes/{id}/exec-detached', ...options, @@ -7661,7 +7619,7 @@ export const execDetached = (options: Opti } }); -export const extendTimeout = (options: Options) => (options.client ?? client).post({ +export const extendTimeout = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/v1/sandboxes/{id}/extend-timeout', ...options, @@ -7671,7 +7629,7 @@ export const extendTimeout = (options: Opt } }); -export const mkdir = (options: Options) => (options.client ?? client).post({ +export const mkdir = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/v1/sandboxes/{id}/fs/mkdir', ...options, @@ -7681,13 +7639,13 @@ export const mkdir = (options: Options(options: Options) => (options.client ?? client).get({ +export const readFile = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/v1/sandboxes/{id}/fs/read', ...options }); -export const statPath = (options: Options) => (options.client ?? client).get({ +export const statPath = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/v1/sandboxes/{id}/fs/stat', ...options @@ -7709,7 +7667,7 @@ export const statPath = (options: Options< * force us to break SDK compat. Instead we dispatch on Content-Type, * preserve JSON for native callers, and add tar for SDK callers. */ -export const writeFile = (options: Options) => (options.client ?? client).post({ +export const writeFile = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/v1/sandboxes/{id}/fs/write', ...options, @@ -7725,7 +7683,7 @@ export const writeFile = (options: Options * file errors, previously-written entries are left in place and the * error describes which file broke. */ -export const writeFiles = (options: Options) => (options.client ?? client).post({ +export const writeFiles = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/v1/sandboxes/{id}/fs/write-batch', ...options, @@ -7735,13 +7693,13 @@ export const writeFiles = (options: Option } }); -export const listJobs = (options: Options) => (options.client ?? client).get({ +export const listJobs = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/v1/sandboxes/{id}/jobs', ...options }); -export const jobStatus = (options: Options) => (options.client ?? client).get({ +export const jobStatus = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/v1/sandboxes/{id}/jobs/{job_id}', ...options @@ -7753,7 +7711,7 @@ export const jobStatus = (options: Options * inside the sandbox container. Returns 204 on success; 404 if the * sandbox or job is unknown. */ -export const killJob = (options: Options) => (options.client ?? client).post({ +export const killJob = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/v1/sandboxes/{id}/jobs/{job_id}/kill', ...options, @@ -7775,13 +7733,13 @@ export const killJob = (options: Options(options: Options) => (options.client ?? client).get({ +export const jobLogs = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/v1/sandboxes/{id}/jobs/{job_id}/logs', ...options }); -export const pauseSandbox = (options: Options) => (options.client ?? client).post({ +export const pauseSandbox = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/v1/sandboxes/{id}/pause', ...options @@ -7803,7 +7761,7 @@ export const pauseSandbox = (options: Opti * Anyone holding the returned URL can view the preview until it expires; * there is no per-link revocation short of rotating the preview password. */ -export const sandboxCreatePreviewLink = (options: Options) => (options.client ?? client).post({ +export const sandboxCreatePreviewLink = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/v1/sandboxes/{id}/preview-link', ...options, @@ -7813,13 +7771,13 @@ export const sandboxCreatePreviewLink = (o } }); -export const clearPreviewPassword = (options: Options) => (options.client ?? client).delete({ +export const clearPreviewPassword = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/v1/sandboxes/{id}/preview-password', ...options }); -export const setPreviewPassword = (options: Options) => (options.client ?? client).put({ +export const setPreviewPassword = (options: Options): RequestResult => (options.client ?? client).put({ security: [{ scheme: 'bearer', type: 'http' }], url: '/v1/sandboxes/{id}/preview-password', ...options, @@ -7833,7 +7791,7 @@ export const setPreviewPassword = (options * Grow a Firecracker sandbox's root disk. Offline resize — the VM reboots * (filesystem/data persist) rather than resizing fully live. */ -export const resizeSandbox = (options: Options) => (options.client ?? client).post({ +export const resizeSandbox = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/v1/sandboxes/{id}/resize', ...options, @@ -7843,19 +7801,19 @@ export const resizeSandbox = (options: Opt } }); -export const restartSandbox = (options: Options) => (options.client ?? client).post({ +export const restartSandbox = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/v1/sandboxes/{id}/restart', ...options }); -export const resumeSandbox = (options: Options) => (options.client ?? client).post({ +export const resumeSandbox = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/v1/sandboxes/{id}/resume', ...options }); -export const sourceSandbox = (options: Options) => (options.client ?? client).post({ +export const sourceSandbox = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/v1/sandboxes/{id}/source', ...options, @@ -7865,7 +7823,7 @@ export const sourceSandbox = (options: Opt } }); -export const stopSandbox = (options: Options) => (options.client ?? client).post({ +export const stopSandbox = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/v1/sandboxes/{id}/stop', ...options @@ -7876,7 +7834,7 @@ export const stopSandbox = (options: Optio * calls `POST /v1/sandboxes/{id}/{cmdId}/kill` — note the path has the * command ID directly under the sandbox, NOT under `/jobs/` or `/cmd/`. */ -export const cmdKill = (options: Options) => (options.client ?? client).post({ +export const cmdKill = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/v1/sandboxes/{id}/{cmd_id}/kill', ...options, @@ -7889,7 +7847,7 @@ export const cmdKill = (options: Options(options: Options) => (options.client ?? client).get({ +export const getVisitorSessions = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/visitors/{visitor_id}/session-replays', ...options @@ -7898,7 +7856,7 @@ export const getVisitorSessions = (options /** * Delete a session replay */ -export const deleteSessionReplay = (options: Options) => (options.client ?? client).delete({ +export const deleteSessionReplay = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/visitors/{visitor_id}/session-replays/{session_id}', ...options @@ -7907,7 +7865,7 @@ export const deleteSessionReplay = (option /** * Get session replay data with visitor info (without events) */ -export const getSessionReplay = (options: Options) => (options.client ?? client).get({ +export const getSessionReplay = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/visitors/{visitor_id}/session-replays/{session_id}', ...options @@ -7916,7 +7874,7 @@ export const getSessionReplay = (options: /** * Update session duration */ -export const updateSessionDuration = (options: Options) => (options.client ?? client).put({ +export const updateSessionDuration = (options: Options): RequestResult => (options.client ?? client).put({ security: [{ scheme: 'bearer', type: 'http' }], url: '/visitors/{visitor_id}/session-replays/{session_id}/duration', ...options, @@ -7929,7 +7887,7 @@ export const updateSessionDuration = (opti /** * Get session replay events (with session and visitor metadata) */ -export const getSessionReplayEvents = (options: Options) => (options.client ?? client).get({ +export const getSessionReplayEvents = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/visitors/{visitor_id}/session-replays/{session_id}/events', ...options @@ -7938,7 +7896,7 @@ export const getSessionReplayEvents = (opt /** * Add events to an existing session */ -export const addEvents = (options: Options) => (options.client ?? client).post({ +export const addEvents = (options: Options): RequestResult => (options.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/visitors/{visitor_id}/session-replays/{session_id}/events', ...options, @@ -7948,19 +7906,19 @@ export const addEvents = (options: Options } }); -export const deleteScan = (options: Options) => (options.client ?? client).delete({ +export const deleteScan = (options: Options): RequestResult => (options.client ?? client).delete({ security: [{ scheme: 'bearer', type: 'http' }], url: '/vulnerability-scans/{scan_id}', ...options }); -export const getScan = (options: Options) => (options.client ?? client).get({ +export const getScan = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/vulnerability-scans/{scan_id}', ...options }); -export const getScanVulnerabilities = (options: Options) => (options.client ?? client).get({ +export const getScanVulnerabilities = (options: Options): RequestResult => (options.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/vulnerability-scans/{scan_id}/vulnerabilities', ...options @@ -7969,12 +7927,12 @@ export const getScanVulnerabilities = (opt /** * List available event types */ -export const listEventTypes = (options?: Options) => (options?.client ?? client).get({ url: '/webhook-event-types', ...options }); +export const listEventTypes = (options?: Options): RequestResult => (options?.client ?? client).get({ url: '/webhook-event-types', ...options }); /** * Trigger weekly digest generation manually */ -export const triggerWeeklyDigest = (options?: Options) => (options?.client ?? client).post({ +export const triggerWeeklyDigest = (options?: Options): RequestResult => (options?.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/weekly-digest/trigger', ...options @@ -7987,7 +7945,7 @@ export const triggerWeeklyDigest = (option * manifest drives sidebar navigation rendering for every authenticated * user, not just admins. */ -export const listExternalPlugins = (options?: Options) => (options?.client ?? client).get({ +export const listExternalPlugins = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/x/plugins', ...options @@ -8002,7 +7960,7 @@ export const listExternalPlugins = (option * * Requires `SystemAdmin` permission. */ -export const reloadPlugins = (options?: Options) => (options?.client ?? client).post({ +export const reloadPlugins = (options?: Options): RequestResult => (options?.client ?? client).post({ security: [{ scheme: 'bearer', type: 'http' }], url: '/x/plugins/reload', ...options @@ -8011,7 +7969,7 @@ export const reloadPlugins = (options?: Op /** * Ingest a Sentry envelope (binary payload) */ -export const ingestSentryEnvelope = (options: Options) => (options.client ?? client).post({ +export const ingestSentryEnvelope = (options: Options): RequestResult => (options.client ?? client).post({ bodySerializer: null, url: '/{project_id}/envelope/', ...options, @@ -8024,7 +7982,7 @@ export const ingestSentryEnvelope = (optio /** * Ingest a Sentry event (JSON payload) */ -export const ingestSentryEvent = (options: Options) => (options.client ?? client).post({ +export const ingestSentryEvent = (options: Options): RequestResult => (options.client ?? client).post({ url: '/{project_id}/store/', ...options, headers: { @@ -8036,9 +7994,37 @@ export const ingestSentryEvent = (options: /** * List audit logs with optional filtering */ -export const listAuditLogs = (options?: Options) => (options?.client ?? client).get({ url: 'audit/logs', ...options }); +export const listAuditLogs = (options?: Options): RequestResult => (options?.client ?? client).get({ url: 'audit/logs', ...options }); /** * Get a specific audit log entry by ID */ -export const getAuditLog = (options: Options) => (options.client ?? client).get({ url: 'audit/logs/{id}', ...options }); +export const getAuditLog = (options: Options): RequestResult => (options.client ?? client).get({ url: 'audit/logs/{id}', ...options }); + +export const disconnectCloud = (options?: Options): RequestResult => (options?.client ?? client).delete({ + security: [{ scheme: 'bearer', type: 'http' }], + url: '/cloud', + ...options +}); + +export const getCloudCapability = (options?: Options): RequestResult => (options?.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }], + url: '/cloud/capability', + ...options +}); + +export const enrollCloud = (options: Options): RequestResult => (options.client ?? client).post({ + security: [{ scheme: 'bearer', type: 'http' }], + url: '/cloud/enroll', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +export const getCloudStatus = (options?: Options): RequestResult => (options?.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }], + url: '/cloud/status', + ...options +}); diff --git a/apps/temps-cli/src/api/types.gen.ts b/apps/temps-cli/src/api/types.gen.ts index 2b001b433..d7795261c 100644 --- a/apps/temps-cli/src/api/types.gen.ts +++ b/apps/temps-cli/src/api/types.gen.ts @@ -1019,11 +1019,6 @@ export type AppSettings = { * hardware that already has its own per-host headroom). */ build_limits?: BuildLimitsSettings; - /** - * Managed control-plane connection. Credentials are deliberately not - * stored here; they live in the owner-only cloud-link state file. - */ - cloud?: CloudSettings; /** * Cluster-DNS resolver settings (ADR-024, experimental beta). Off by * default — see `ClusterDnsSettings` for the incident background and @@ -1117,6 +1112,11 @@ export type AppSettings = { * from appearing on installs that were already configured via the CLI. */ setup_complete?: boolean; + /** + * Managed control-plane connection. Credentials are deliberately not + * stored here; they live in the owner-only cloud-link state file. + */ + cloud?: CloudSettings; }; /** @@ -1350,10 +1350,7 @@ export type AuthFlavorDto = { export type AuthResponse = { message: string; - mfa_enrollment_required: boolean; mfa_required: boolean; - mfa_setup?: null | MfaSetupResponse; - password_change_required: boolean; success: boolean; user_id?: number | null; }; @@ -2140,38 +2137,11 @@ export type CliLoginRequest = { username: string; }; -export type CloudCapability = { - configured: boolean; - reason?: string | null; - setup_path: string; -}; - /** * Cloud provider detected from node metadata */ export type CloudProvider = 'aws' | 'gcp' | 'azure' | 'hetzner' | 'digitalocean' | 'other'; -/** - * Non-secret managed control-plane settings stored with application settings. - */ -export type CloudSettings = { - /** - * HTTPS origin used for enrollment and telemetry mirroring. - */ - backend_url?: string; -}; - -export type CloudStatus = { - account_email?: string | null; - backend_url: string; - health: string; - health_message: string; - instance_id?: string | null; - spooled_spans: number; - status: string; - status_message: string; -}; - /** * Configuration for a Cloudflare Email Sending notification provider. * @@ -3973,7 +3943,6 @@ export type CreateTeamRequest = { export type CreateUserRequest = { email?: string | null; - must_change_password?: boolean; password?: string | null; roles: Array; username: string; @@ -4784,19 +4753,6 @@ export type DeploymentMetadata = { * ID of the deployment this was rolled back from (if applicable) */ rolledBackFromId?: number | null; - /** - * Uploaded source archive content type. - */ - sourceBundleContentType?: string | null; - /** - * Uploaded source archive ID. Source archives are extracted before the - * regular preset build pipeline and do not require Git metadata. - */ - sourceBundleId?: number | null; - /** - * Uploaded source archive path in the Temps data directory. - */ - sourceBundlePath?: string | null; /** * Static bundle content type (for proper extraction: application/gzip or application/zip) */ @@ -6061,10 +6017,6 @@ export type EnrichVisitorResponse = { visitor_id: string; }; -export type EnrollCloudRequest = { - enrollment_code: string; -}; - export type EnrollmentTokenInfo = { bound_node_name?: string | null; created_at: string; @@ -12443,12 +12395,6 @@ export type PropertyBreakdownQuery = { * Property column to group by */ group_by: PropertyColumn; - /** - * Include crawler/bot traffic (default: false). Off by default so the - * breakdown percentages share a denominator with the headline counts, - * which always exclude crawlers. - */ - include_crawlers?: boolean | null; /** * Maximum number of results to return (default: 20, max: 100) */ @@ -12505,11 +12451,6 @@ export type PropertyTimelineQuery = { * Property column to group by */ group_by: PropertyColumn; - /** - * Include crawler/bot traffic (default: false). See - * [`PropertyBreakdownQuery::include_crawlers`]. - */ - include_crawlers?: boolean | null; /** * Start date for the query range */ @@ -12870,14 +12811,9 @@ export type QueryDataResponse = { */ total_count: number; /** - * Whether rows were dropped from this response to stay inside the byte - * budget. + * Whether rows were dropped from this response to stay inside the byte budget. * - * `returned_count` is always the number of rows actually present, so a - * truncated page is still internally consistent — but a caller comparing - * it against the requested limit would otherwise conclude the table simply - * ended. Reported explicitly so a partial page is never mistaken for a - * complete one, by a human, a script, or a model reading a tool result. + * `returned_count` is always the number of rows actually present, so a truncated page is still internally consistent — but a caller comparing it against the requested limit would otherwise conclude the table simply ended. Reported explicitly so a partial page is never mistaken for a complete one, by a human, a script, or a model reading a tool result. */ truncated: boolean; }; @@ -13394,18 +13330,6 @@ export type RequestRow = { user_agent?: string | null; }; -export type RequiredPasswordChangeRequest = { - new_password: string; -}; - -export type RequiredPasswordChangeResponse = { - message: string; - mfa_enrollment_required: boolean; - mfa_setup?: null | MfaSetupResponse; - success: boolean; - user_id: number; -}; - export type ResetPasswordRequest = { new_password: string; token: string; @@ -13914,7 +13838,6 @@ export type RouteUser = { id: number; image: string; mfa_enabled: boolean; - must_change_password: boolean; name: string; updated_at: number; username: string; @@ -18995,6 +18918,37 @@ export type ZoneListResponse = { zones: Array; }; +export type CloudCapability = { + configured: boolean; + reason?: string | null; + setup_path: string; +}; + +/** + * Non-secret managed control-plane settings stored with application settings. + */ +export type CloudSettings = { + /** + * HTTPS origin used for enrollment and telemetry mirroring. + */ + backend_url?: string; +}; + +export type CloudStatus = { + account_email?: string | null; + backend_url: string; + health: string; + health_message: string; + instance_id?: string | null; + spooled_spans: number; + status: string; + status_message: string; +}; + +export type EnrollCloudRequest = { + enrollment_code: string; +}; + /** * Response type for S3 source */ @@ -22481,37 +22435,6 @@ export type ListPublicProvidersResponses = { export type ListPublicProvidersResponse = ListPublicProvidersResponses[keyof ListPublicProvidersResponses]; -export type ChangeRequiredPasswordData = { - body: RequiredPasswordChangeRequest; - path?: never; - query?: never; - url: '/auth/password-change-required'; -}; - -export type ChangeRequiredPasswordErrors = { - /** - * Password does not meet requirements - */ - 400: unknown; - /** - * Password-change session is missing or expired - */ - 401: unknown; - /** - * Internal server error - */ - 500: unknown; -}; - -export type ChangeRequiredPasswordResponses = { - /** - * Required password change completed - */ - 200: RequiredPasswordChangeResponse; -}; - -export type ChangeRequiredPasswordResponse = ChangeRequiredPasswordResponses[keyof ChangeRequiredPasswordResponses]; - export type RequestPasswordResetData = { body: EmailRequest; path?: never; @@ -24243,58 +24166,6 @@ export type BlobHeadResponses = { 200: unknown; }; -export type DisconnectCloudData = { - body?: never; - path?: never; - query?: never; - url: '/cloud'; -}; - -export type DisconnectCloudResponses = { - 200: CloudStatus; -}; - -export type DisconnectCloudResponse = DisconnectCloudResponses[keyof DisconnectCloudResponses]; - -export type GetCloudCapabilityData = { - body?: never; - path?: never; - query?: never; - url: '/cloud/capability'; -}; - -export type GetCloudCapabilityResponses = { - 200: CloudCapability; -}; - -export type GetCloudCapabilityResponse = GetCloudCapabilityResponses[keyof GetCloudCapabilityResponses]; - -export type EnrollCloudData = { - body: EnrollCloudRequest; - path?: never; - query?: never; - url: '/cloud/enroll'; -}; - -export type EnrollCloudResponses = { - 200: CloudStatus; -}; - -export type EnrollCloudResponse = EnrollCloudResponses[keyof EnrollCloudResponses]; - -export type GetCloudStatusData = { - body?: never; - path?: never; - query?: never; - url: '/cloud/status'; -}; - -export type GetCloudStatusResponses = { - 200: CloudStatus; -}; - -export type GetCloudStatusResponse = GetCloudStatusResponses[keyof GetCloudStatusResponses]; - export type GetDashboardProjectsAnalyticsData = { body?: never; path?: never; @@ -41179,10 +41050,6 @@ export type GetPropertyBreakdownData = { * Maximum number of results (default: 20, max: 100) */ limit?: number; - /** - * Include crawler/bot traffic (default: false) - */ - include_crawlers?: boolean; /** * Filter by country (for region/city drill-downs) */ @@ -41276,10 +41143,6 @@ export type GetPropertyTimelineData = { * Time bucket: hour, day, week, month (default: auto-detect) */ bucket_size?: string; - /** - * Include crawler/bot traffic (default: false) - */ - include_crawlers?: boolean; }; url: '/projects/{project_id}/events/properties/timeline'; }; @@ -44234,7 +44097,7 @@ export type GetUniqueCountsResponses = { export type GetUniqueCountsResponse = GetUniqueCountsResponses[keyof GetUniqueCountsResponses]; export type UploadStaticBundleData = { - body: SourceArchiveUpload; + body?: never; path: { project_id: number; }; @@ -48052,10 +47915,6 @@ export type SetupMfaErrors = { * Unauthorized */ 401: unknown; - /** - * MFA is already enabled; verify and disable it before re-enrollment - */ - 409: unknown; /** * Internal server error */ @@ -49918,3 +49777,55 @@ export type GetAuditLogResponses = { }; export type GetAuditLogResponse = GetAuditLogResponses[keyof GetAuditLogResponses]; + +export type DisconnectCloudData = { + body?: never; + path?: never; + query?: never; + url: '/cloud'; +}; + +export type DisconnectCloudResponses = { + 200: CloudStatus; +}; + +export type DisconnectCloudResponse = DisconnectCloudResponses[keyof DisconnectCloudResponses]; + +export type GetCloudCapabilityData = { + body?: never; + path?: never; + query?: never; + url: '/cloud/capability'; +}; + +export type GetCloudCapabilityResponses = { + 200: CloudCapability; +}; + +export type GetCloudCapabilityResponse = GetCloudCapabilityResponses[keyof GetCloudCapabilityResponses]; + +export type EnrollCloudData = { + body: EnrollCloudRequest; + path?: never; + query?: never; + url: '/cloud/enroll'; +}; + +export type EnrollCloudResponses = { + 200: CloudStatus; +}; + +export type EnrollCloudResponse = EnrollCloudResponses[keyof EnrollCloudResponses]; + +export type GetCloudStatusData = { + body?: never; + path?: never; + query?: never; + url: '/cloud/status'; +}; + +export type GetCloudStatusResponses = { + 200: CloudStatus; +}; + +export type GetCloudStatusResponse = GetCloudStatusResponses[keyof GetCloudStatusResponses]; From d3e8e625b51601d7efe74838b7b0e9a28a5082b7 Mon Sep 17 00:00:00 2001 From: David Viejo Date: Thu, 6 Aug 2026 13:21:39 +0200 Subject: [PATCH 7/9] test(cloud): prove bounded shutdown flush --- crates/temps-cloud-client/src/flusher.rs | 200 ++++++++++++++++++++++- 1 file changed, 199 insertions(+), 1 deletion(-) diff --git a/crates/temps-cloud-client/src/flusher.rs b/crates/temps-cloud-client/src/flusher.rs index a09e7b57d..6391ac9bf 100644 --- a/crates/temps-cloud-client/src/flusher.rs +++ b/crates/temps-cloud-client/src/flusher.rs @@ -17,6 +17,13 @@ pub const BASE_INTERVAL: Duration = Duration::from_secs(15); /// polled, or recovery would need a restart to notice. pub const MAX_INTERVAL: Duration = Duration::from_secs(300); +/// Maximum time a clean shutdown may spend on its final delivery attempt. +/// +/// The pending submission remains owned by [`CloudLink`] if the future is +/// cancelled, so timing out cannot corrupt the in-memory queue while shutdown +/// completes. Source telemetry remains authoritative in local Temps storage. +pub const SHUTDOWN_FLUSH_TIMEOUT: Duration = Duration::from_secs(5); + /// Next interval after an outcome. /// /// Separated from the loop so the policy is testable without waiting on real @@ -43,6 +50,14 @@ pub fn next_interval(current: Duration, outcome: &FlushOutcome) -> Duration { /// Run until cancelled. Spawn this once at instance startup. pub async fn run(link: Arc, mut cancel: tokio::sync::watch::Receiver) { + run_with_shutdown_timeout(link, &mut cancel, SHUTDOWN_FLUSH_TIMEOUT).await; +} + +async fn run_with_shutdown_timeout( + link: Arc, + cancel: &mut tokio::sync::watch::Receiver, + shutdown_flush_timeout: Duration, +) { let mut interval = BASE_INTERVAL; loop { @@ -53,7 +68,27 @@ pub async fn run(link: Arc, mut cancel: tokio::sync::watch::Receiver< // One last attempt on the way out, bounded: a clean // shutdown should not lose a spool we could have delivered, // but it also must not hang the process. - let _ = tokio::time::timeout(Duration::from_secs(5), link.flush()).await; + match tokio::time::timeout(shutdown_flush_timeout, link.flush()).await { + Ok(FlushOutcome::Shipped { spans }) => { + tracing::info!(spans, "mirrored telemetry during shutdown"); + } + Ok(FlushOutcome::Retained { spans, reason }) + | Ok(FlushOutcome::Blocked { spans, reason }) => { + tracing::warn!( + spans, + reason, + "shutdown flush could not mirror telemetry; source remains in local storage" + ); + } + Ok(FlushOutcome::Idle | FlushOutcome::NotLinked) => {} + Err(_) => { + tracing::warn!( + timeout_ms = shutdown_flush_timeout.as_millis(), + spooled_spans = link.spooled(), + "shutdown flush timed out; source telemetry remains in local storage" + ); + } + } tracing::info!("cloud mirror stopped"); return; } @@ -85,8 +120,117 @@ pub async fn run(link: Arc, mut cancel: tokio::sync::watch::Receiver< #[cfg(test)] mod tests { + use std::net::SocketAddr; + use std::sync::atomic::{AtomicU16, AtomicU64, AtomicUsize, Ordering}; + + use axum::{extract::State, routing::post, Json, Router}; + use temps_cloud_protocol::{SpanRecord, TelemetryBatch}; + use uuid::Uuid; + use super::*; + #[derive(Clone, Default)] + struct Stub { + status: Arc, + telemetry_delay_ms: Arc, + received: Arc, + } + + async fn serve(stub: Stub) -> String { + let app = Router::new() + .route( + "/v1/enroll", + post(|| async { + Json(serde_json::json!({ + "tenant_id": Uuid::new_v4(), + "instance_token": "inst_shutdown_test" + })) + }), + ) + .route( + "/v1/telemetry", + post( + |State(stub): State, Json(batch): Json| async move { + let delay = stub.telemetry_delay_ms.load(Ordering::SeqCst); + if delay > 0 { + tokio::time::sleep(Duration::from_millis(delay)).await; + } + let status = stub.status.load(Ordering::SeqCst); + if status != 200 { + return ( + axum::http::StatusCode::from_u16(status) + .unwrap_or(axum::http::StatusCode::INTERNAL_SERVER_ERROR), + Json(serde_json::json!({"detail": "stub failure"})), + ); + } + let spans = batch.spans.len(); + stub.received.fetch_add(spans, Ordering::SeqCst); + ( + axum::http::StatusCode::OK, + Json(serde_json::json!({ + "submission_id": batch.submission_id, + "processed_spans": spans, + "stored_spans": spans, + "metered_bytes": 1 + })), + ) + }, + ), + ) + .with_state(stub); + let listener = tokio::net::TcpListener::bind::( + "127.0.0.1:0".parse().expect("loopback address must parse"), + ) + .await + .expect("test server must bind"); + let address = listener.local_addr().expect("test server has an address"); + tokio::spawn(async move { + let _ = axum::serve(listener, app).await; + }); + format!("http://{address}") + } + + fn span() -> SpanRecord { + SpanRecord { + trace_id: "shutdown-trace".into(), + span_id: "shutdown-span".into(), + name: "shutdown".into(), + ts_millis: 1, + duration_ms: 1.0, + attributes: Default::default(), + } + } + + async fn linked_test_link(stub: Stub) -> (Arc, tempfile::TempDir) { + let directory = tempfile::tempdir().expect("temporary directory must be created"); + let backend = serve(stub).await; + let link = Arc::new(CloudLink::load_for_loopback_development( + directory.path().to_path_buf(), + "shutdown-test", + )); + link.configure( + crate::BackendUrl::loopback_development(&backend) + .expect("stub backend URL must be accepted"), + ) + .expect("test link must be configured"); + link.enroll("shutdown-code") + .await + .expect("test link must enroll"); + (link, directory) + } + + async fn cancel_and_join(link: Arc, timeout: Duration) { + let (cancel, mut receiver) = tokio::sync::watch::channel(false); + let task = tokio::spawn(async move { + run_with_shutdown_timeout(link, &mut receiver, timeout).await; + }); + cancel.send_replace(true); + tokio::time::timeout(Duration::from_secs(1), task) + .await + .expect("shutdown must remain bounded") + .expect("flusher task must exit cleanly"); + } + #[test] fn a_transient_failure_backs_off_and_is_capped() { let mut d = BASE_INTERVAL; @@ -142,4 +286,58 @@ mod tests { assert_eq!(d, MAX_INTERVAL); assert!(d < Duration::from_secs(3600), "must still poll"); } + + #[tokio::test] + async fn shutdown_flushes_queued_spans_before_stopping() { + let stub = Stub { + status: Arc::new(AtomicU16::new(200)), + ..Default::default() + }; + let (link, _directory) = linked_test_link(stub.clone()).await; + link.record(vec![span()]); + + cancel_and_join(link.clone(), Duration::from_secs(1)).await; + + assert_eq!(stub.received.load(Ordering::SeqCst), 1); + assert_eq!(link.spooled(), 0); + } + + #[tokio::test] + async fn shutdown_retains_spans_when_the_backend_rejects_the_attempt() { + let stub = Stub { + status: Arc::new(AtomicU16::new(200)), + ..Default::default() + }; + let (link, _directory) = linked_test_link(stub.clone()).await; + stub.status.store(503, Ordering::SeqCst); + link.record(vec![span()]); + + cancel_and_join(link.clone(), Duration::from_secs(1)).await; + + assert_eq!(stub.received.load(Ordering::SeqCst), 0); + assert_eq!( + link.spooled(), + 1, + "a failed final attempt must remain queued" + ); + } + + #[tokio::test] + async fn shutdown_timeout_is_bounded_without_corrupting_the_pending_submission() { + let stub = Stub { + status: Arc::new(AtomicU16::new(200)), + telemetry_delay_ms: Arc::new(AtomicU64::new(500)), + ..Default::default() + }; + let (link, _directory) = linked_test_link(stub).await; + link.record(vec![span()]); + + cancel_and_join(link.clone(), Duration::from_millis(20)).await; + + assert_eq!( + link.spooled(), + 1, + "timing out must not corrupt the in-memory submission" + ); + } } From 4f3d4bc033eca0878030b1bf7913ec58784737f3 Mon Sep 17 00:00:00 2001 From: David Viejo Date: Thu, 6 Aug 2026 15:59:22 +0200 Subject: [PATCH 8/9] feat(cloud): declare backup restore artifacts --- crates/temps-cloud-protocol/src/lib.rs | 10 ++-- crates/temps-cloud-protocol/src/messages.rs | 66 +++++++++++++++++++++ 2 files changed, 71 insertions(+), 5 deletions(-) diff --git a/crates/temps-cloud-protocol/src/lib.rs b/crates/temps-cloud-protocol/src/lib.rs index b5f5f4fb1..2904e7d5c 100644 --- a/crates/temps-cloud-protocol/src/lib.rs +++ b/crates/temps-cloud-protocol/src/lib.rs @@ -29,11 +29,11 @@ pub mod messages; pub use messages::{ - BackupCompleted, BackupTarget, BackupTargetRequest, EnrollRequest, EnrollResponse, Envelope, - Heartbeat, HeartbeatAck, IngestAck, ManagedAiAnalysisRequest, ManagedAiAnalysisResponse, - ManagedAiCapability, ManagedAiCitation, ManagedAiEvidence, ManagedAiTask, - ManagedNotificationAccepted, ManagedNotificationRequest, ManagedNotificationSeverity, - SpanRecord, TelemetryBatch, + BackupArtifact, BackupCompleted, BackupCompression, BackupEngine, BackupFormat, BackupTarget, + BackupTargetRequest, EnrollRequest, EnrollResponse, Envelope, Heartbeat, HeartbeatAck, + IngestAck, ManagedAiAnalysisRequest, ManagedAiAnalysisResponse, ManagedAiCapability, + ManagedAiCitation, ManagedAiEvidence, ManagedAiTask, ManagedNotificationAccepted, + ManagedNotificationRequest, ManagedNotificationSeverity, SpanRecord, TelemetryBatch, }; use serde::{Deserialize, Serialize}; diff --git a/crates/temps-cloud-protocol/src/messages.rs b/crates/temps-cloud-protocol/src/messages.rs index 57053b87c..728d70ad4 100644 --- a/crates/temps-cloud-protocol/src/messages.rs +++ b/crates/temps-cloud-protocol/src/messages.rs @@ -154,6 +154,37 @@ pub struct IngestAck { // Backups // --------------------------------------------------------------------------- +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum BackupEngine { + Postgres, + TimescaleDb, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum BackupFormat { + /// Plain SQL produced by `pg_dump` or `pg_dumpall` and restored with psql. + PgDumpPlain, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum BackupCompression { + Gzip, +} + +/// Machine-readable restore contract for one backup object. +/// +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct BackupArtifact { + pub engine: BackupEngine, + pub format: BackupFormat, + pub compression: BackupCompression, + /// Major server/tooling version used to create the dump. + pub postgres_major: u16, +} + /// Instance asks where to put a backup. /// /// The cloud replies with a presigned destination; backup bytes then travel @@ -171,6 +202,7 @@ pub struct BackupTargetRequest { /// direct PUT. Optional only for wire compatibility; Cloud may require it. #[serde(default)] pub checksum_sha256: Option, + pub artifact: BackupArtifact, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -436,4 +468,38 @@ mod tests { assert!(response.account_email.is_none()); assert!(response.capabilities.is_empty()); } + + #[test] + fn backup_target_request_requires_a_restore_contract() { + let request = serde_json::from_value::(serde_json::json!({ + "instance_id": Uuid::new_v4(), + "source": "postgres/main", + "estimated_bytes": 42, + "checksum_sha256": "00" + })); + + assert!(request.is_err()); + } + + #[test] + fn backup_restore_contract_uses_stable_wire_names() { + let request = BackupTargetRequest { + instance_id: Uuid::new_v4(), + source: "timescaledb/telemetry".into(), + estimated_bytes: 42, + checksum_sha256: Some("00".into()), + artifact: BackupArtifact { + engine: BackupEngine::TimescaleDb, + format: BackupFormat::PgDumpPlain, + compression: BackupCompression::Gzip, + postgres_major: 18, + }, + }; + + let value = serde_json::to_value(request).unwrap(); + assert_eq!(value["artifact"]["engine"], "timescale_db"); + assert_eq!(value["artifact"]["format"], "pg_dump_plain"); + assert_eq!(value["artifact"]["compression"], "gzip"); + assert_eq!(value["artifact"]["postgres_major"], 18); + } } From 0db07fbcd3ba105a6d7ff7ad1e10528b8faaaf30 Mon Sep 17 00:00:00 2001 From: David Viejo Date: Thu, 6 Aug 2026 16:04:24 +0200 Subject: [PATCH 9/9] refactor(cloud): require backup checksums --- crates/temps-cloud-protocol/src/messages.rs | 26 +++++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/crates/temps-cloud-protocol/src/messages.rs b/crates/temps-cloud-protocol/src/messages.rs index 728d70ad4..ccc0e61f8 100644 --- a/crates/temps-cloud-protocol/src/messages.rs +++ b/crates/temps-cloud-protocol/src/messages.rs @@ -197,11 +197,10 @@ pub struct BackupTargetRequest { /// What is being backed up, e.g. a service or database name. pub source: String, pub estimated_bytes: u64, - /// SHA-256 of the finished artifact. New clients compute the backup before + /// SHA-256 of the finished artifact. Clients compute the backup before /// requesting a target so object storage can validate the bytes during the - /// direct PUT. Optional only for wire compatibility; Cloud may require it. - #[serde(default)] - pub checksum_sha256: Option, + /// direct PUT and the restore worker can verify the recovery read. + pub checksum_sha256: String, pub artifact: BackupArtifact, } @@ -481,13 +480,30 @@ mod tests { assert!(request.is_err()); } + #[test] + fn backup_target_request_requires_a_checksum() { + let request = serde_json::from_value::(serde_json::json!({ + "instance_id": Uuid::new_v4(), + "source": "postgres/main", + "estimated_bytes": 42, + "artifact": { + "engine": "postgres", + "format": "pg_dump_plain", + "compression": "gzip", + "postgres_major": 18 + } + })); + + assert!(request.is_err()); + } + #[test] fn backup_restore_contract_uses_stable_wire_names() { let request = BackupTargetRequest { instance_id: Uuid::new_v4(), source: "timescaledb/telemetry".into(), estimated_bytes: 42, - checksum_sha256: Some("00".into()), + checksum_sha256: "00".into(), artifact: BackupArtifact { engine: BackupEngine::TimescaleDb, format: BackupFormat::PgDumpPlain,